
/******************************************************************
* 
* Filename: libipmi_session.c
*
* Description: Contains implementation of session establishment 
*   functions to BMC
*
* Author: Jimbo
*
******************************************************************/
#include <stdlib.h>
#include <stdint.h>
#include "libipmi_session.h"
//#include "libipmi_rmcp.h"
#include "libipmi_IPM.h"
//#include "libipmi_AMIOEM.h"
#include <string.h>
//#include "dbgout.h"
//#include "libipmi_sal_session.h"
#include <stdio.h>
#include "com_IPMI_App.h"
#include "com_IPMI_AppDevice.h"
#include "com_IPMIDefs.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/file.h>
#include <fcntl.h>
#include <errno.h>
#define MAX_RETRIES	10

uint16_t LIBIPMI_CreateSession(IPMI20_UDS_SESSION_T *pUDSSession, int timeout)
{
    uint16_t wRet = LIBIPMI_E_SUCCESS;
    int client_sock;
    struct sockaddr_un serv_addr;

    printf("---> Create_IPMI20_UDS_Session\n");
    
    /* Open the socket */
    client_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if(client_sock == -1)
    {
        printf("LIBIPMI_UDS_SESSION.C: Unable to create socket \n");
        return LIBIPMI_MEDIUM_E_INVALID_SOCKET;
    }

    /*Connect the client to server*/
    memset ((char *) &serv_addr, 0, sizeof (serv_addr));
    serv_addr.sun_family = AF_UNIX;
    strcpy(serv_addr.sun_path,UDS_SOCKET_PATH);

    printf("---> UDS_Connect, socket: %d, SocketPath: %s\n", client_sock, UDS_SOCKET_PATH);
    if ( connect (client_sock, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
    {
        printf("LIBIPMI_UDS_SESSION.C: Unable to connect to Server:\n");
        return LIBIPMI_MEDIUM_E_CONNECT_FAILURE;
    }

    pUDSSession->hUDSInfo.hSocket = client_sock;
    pUDSSession->hUDSInfo.byIsConnected = 1;
    pUDSSession->byDefTimeout = timeout;
 	pUDSSession->dwSessionID = 0;
    pUDSSession->byChannelNum = UDS_CHANNEL;

    return wRet;
}

/*---------------------------------------------------------------------
LIBIPMI_Send_RAW_IPMI2_0_Command

Sends RAW IPMI Command to BMC
----------------------------------------------------------------------*/
uint16_t LIBIPMI_Send_RAW_IPMI2_0_Command(IPMI20_UDS_SESSION_T *pUDSSession,		//notice!
									uint8_t byNetFnLUN, uint8_t byCommand,
									uint8_t *pszReqData, uint32_t dwReqDataLen,
									uint8_t *pszResData, uint32_t *pdwResDataLen,
									int	timeout)
{

	uint8_t pbyIPMIUDSMsgReq[MAX_REQUEST_SIZE];
   	uint8_t pbyIPMIUDSResData[MAX_RESPONSE_SIZE];
   	uint32_t retlen=0,byretval=0;

   	memset(pbyIPMIUDSMsgReq,0,MAX_REQUEST_SIZE);
   	memset(pbyIPMIUDSResData,0,MAX_RESPONSE_SIZE);

   	retlen = FillUDSMessagePacket(pUDSSession,pbyIPMIUDSMsgReq,byNetFnLUN,byCommand,pszReqData,dwReqDataLen);

    if(retlen <= 0 )
    {
       printf("Data Length Invalid\n");
       return -1;
    }

    byretval = UDS_SendData(&pUDSSession->hUDSInfo,(char *)pbyIPMIUDSMsgReq,retlen,timeout);
    if(byretval != LIBIPMI_STATUS_SUCCESS)
        return byretval;

    byretval = UDS_ReceiveData(&pUDSSession->hUDSInfo, (char *)pbyIPMIUDSResData, pdwResDataLen,timeout);
    if(byretval == LIBIPMI_STATUS_SUCCESS)
    {
        IPMIUDSMsg_T *pIPMIUDSMsg = (IPMIUDSMsg_T *)&pbyIPMIUDSResData[0];
        uint8_t *bycompletioncode = (uint8_t *)&pbyIPMIUDSResData[sizeof(IPMIUDSMsg_T)];
        
        *pdwResDataLen = pIPMIUDSMsg->IPMIMsgLen-sizeof(IPMIUDSMsg_T) - 1;
        memcpy(pszResData,&pbyIPMIUDSResData[sizeof(IPMIUDSMsg_T)],*pdwResDataLen);
        
        if(*bycompletioncode != CC_NORMAL)
            return STATUS_CODE(IPMI_ERROR_FLAG, *bycompletioncode);
        else
        {
            if((0 == pUDSSession->dwSessionID) && (pIPMIUDSMsg->Cmd == CMD_SET_USER_PASSWORD))
            {
                pUDSSession->dwSessionID = pIPMIUDSMsg->SessionID;
                pUDSSession->byRole = pIPMIUDSMsg->Privilege;
                
                if(UDS_CHANNEL == pUDSSession->byChannelNum)
                {
                    pUDSSession->byChannelNum = pIPMIUDSMsg->ChannelNum;
                }
            }
            else if((0 == pUDSSession->dwSessionID) && (pIPMIUDSMsg->Cmd == CMD_GET_DEV_ID) )
            {
                pUDSSession->dwSessionID = pIPMIUDSMsg->SessionID;
                pUDSSession->byRole = pIPMIUDSMsg->Privilege;
                
                if(UDS_CHANNEL == pUDSSession->byChannelNum)
                {
                    pUDSSession->byChannelNum = pIPMIUDSMsg->ChannelNum;
                }
            }
        }
    }
    else
        return STATUS_CODE(IPMI_ERROR_FLAG, byretval);

    return LIBIPMI_STATUS_SUCCESS;
}

/*---------------------------------------------------------------------
LIBIPMI_CloseSession

Closes the connection with BMC
----------------------------------------------------------------------*/
uint16_t LIBIPMI_CloseSession( IPMI20_UDS_SESSION_T *pUDSSession )
{
    printf("LIBIPMI_CloseSession\n");
	close(pUDSSession->hUDSInfo.hSocket);
    /* reset the connected flag */
    pUDSSession->hUDSInfo.byIsConnected = 0;
    return LIBIPMI_STATUS_SUCCESS;
}

// /*---------------------------------------------------------------------
// SetPrivilegeLevel

// Sets the session privilege to specified level
// ----------------------------------------------------------------------*/
// uint16_t SetPrivilegeLevel(IPMI20_SESSION_T *pSession, uint8_t *byPrivLevel, int timeout)
// {
// 	uint8_t			byReq;
// 	uint8_t			pbyRes[2];
// 	uint32_t			dwResLen;
// 	uint16_t			wRet;


// 	printf("---> SetPrivilegeLevel\n");
// 	byReq = *byPrivLevel;
// 	wRet = LIBIPMI_Send_RAW_IPMI2_0_Command (pSession,DEFAULT_NET_FN_LUN,
// 												CMD_SET_SESSION_PRIV_LEVEL,
// 												&byReq, sizeof(uint8_t),
// 												&pbyRes[0], &dwResLen, timeout);


// 	if(wRet != 0)
// 	{
// 		printf("Originally requested priv level failed\n");
// 		//find the current privilege level allowed
// 		byReq = 0;
// 		wRet = LIBIPMI_Send_RAW_IPMI2_0_Command (pSession, DEFAULT_NET_FN_LUN,
// 												CMD_SET_SESSION_PRIV_LEVEL,
// 												&byReq, sizeof(uint8_t),
// 												&pbyRes[0], &dwResLen, timeout);
// 		if(wRet != 0)
// 		{
// 			printf("Amazing..request for current privilege limit returned an error %x2\n",wRet);
// 		}
// 		else
// 		{
// 			printf("New priv level is %x\n",pbyRes[1]);
// 			*byPrivLevel = pbyRes[1];
// 		}
// 	}

// 	return wRet;
// }

