
/******************************************************************
* 
* 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"
#define MAX_RETRIES	10
#define MAX_USERS 16
//void *dl_salhandler = NULL;  //This handler will be used by SAL layer.
void DeallocateMemory(IPMI20_SESSION_T *pSession);

// extern int GetUserNameForUserID(IPMI20_SESSION_T *pSession,uint8_t UserID,char *UserName,uint8_t AuthEnable,int timeout);
// extern int CheckUserPassword(IPMI20_SESSION_T *pSession, uint8_t UserID, char *Password, uint8_t AuthEnable, int timeout);
// extern void UDS_Close(UDS_CHANNEL_T *UDSInfo );
// extern uint16_t Close_IPMI20_UDS_Session( IPMI20_SESSION_T *pSession );
// extern int16_t Send_RAW_IPMI2_0_UDS_Command(IPMI20_SESSION_T *pSession,
//                                                 uint8_t byNetFnLUN, uint8_t byCommand,
//                                                 uint8_t *pszReqData, uint32_t dwReqDataLen,
//                                                 uint8_t *pszResData, uint32_t *pdwResDataLen,
//                                                 uint8_t AuthEnable,int timeout);
//void DeallocateMemory(IPMI20_SESSION_T *pSession);
//uint16_t SetPrivilegeLevel(IPMI20_SESSION_T *pSession, uint8_t *byPrivilegeLevel, int timeout);

uint16_t LIBIPMI_CreateSession(IPMI20_SESSION_T *pSession, int timeout)
{
    uint16_t wRet;
    wRet = Create_IPMI20_UDS_Session(pSession, UDS_SOCKET_PATH, 
    			NULL, NULL, NULL, NULL, NULL, 
                timeout, UDS_CHANNEL);

    if(wRet != LIBIPMI_E_SUCCESS)
    {
        DeallocateMemory(pSession);
        return wRet;
    }

    return wRet;
}

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

Sends RAW IPMI Command to BMC
----------------------------------------------------------------------*/
uint16_t LIBIPMI_Send_RAW_IPMI2_0_Command(IPMI20_SESSION_T *pSession,		//notice!
									uint8_t byNetFnLUN, uint8_t byCommand,
									uint8_t *pszReqData, uint32_t dwReqDataLen,
									uint8_t *pszResData, uint32_t *pdwResDataLen,
									int	timeout)
{
	uint16_t wRet;
	uint8_t retries = MAX_RETRIES;

	if(pSession)
	{
		if(pSession->bySessionStarted == SESSION_NOT_STARTED)
		{
			printf("Attempt to send command on unstarted session.The socket may have possible timed out on the stack end\n");
			return STATUS_CODE(MEDIUM_ERROR_FLAG, LIBIPMI_SESSION_E_EXPIRED);
		}

		wRet =  Send_RAW_IPMI2_0_UDS_Command(pSession,
										byNetFnLUN, byCommand,
										pszReqData, dwReqDataLen,
										pszResData,pdwResDataLen,
										timeout);
		if( (wRet == LIBIPMI_MEDIUM_E_INVALID_SOCKET) ||
			(wRet == LIBIPMI_MEDIUM_E_TIMED_OUT_ON_SEND) ||
			(wRet == LIBIPMI_MEDIUM_E_SEND_DATA_FAILURE) ||
			(wRet == LIBIPMI_MEDIUM_E_RECV_DATA_FAILURE))
		{
			printf("Encountered what may be socket closure in UDS..will close session here\n");
			LIBIPMI_CloseSession(pSession);
			return wRet;
		}

		return wRet;

	}

	return STATUS_CODE(MEDIUM_ERROR_FLAG, LIBIPMI_SESSION_E_EXPIRED);
}

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

Closes the connection with BMC
----------------------------------------------------------------------*/
uint16_t LIBIPMI_CloseSession( IPMI20_SESSION_T *pSession )
{
	if(pSession)
	{
        uint16_t wRet;

        wRet = Close_IPMI20_UDS_Session(pSession);
        DeallocateMemory(pSession);
        return wRet;
	}

	return STATUS_CODE(MEDIUM_ERROR_FLAG, LIBIPMI_SESSION_E_EXPIRED);
}

/*---------------------------------------------------------------------
DeallocateMemory

Deallocates the memory which was allocated during session establishment
----------------------------------------------------------------------*/
void DeallocateMemory(IPMI20_SESSION_T *pSession)
{
	if(pSession)
	{
	 	pSession->bySessionStarted = SESSION_NOT_STARTED;
		if( pSession->hUDSSession != NULL )
		{
			/* Close UDS Session */
            if(pSession->hUDSSession->hUDSInfo.byIsConnected)
            {
                UDS_Close(&pSession->hUDSSession->hUDSInfo);
            }
            free(pSession->hUDSSession);
		}
		memset(pSession, 0 , sizeof(IPMI20_SESSION_T) );
	}
	return;
}

/*---------------------------------------------------------------------
IsSessionStarted

Returns if the session has started
----------------------------------------------------------------------*/
uint8_t	IsSessionStarted(IPMI20_SESSION_T *pSession)
{
	return pSession->bySessionStarted;
}

/*---------------------------------------------------------------------
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;
}



/**
This function is used to get the UserID for given Username and Password.
It compares all IPMI username with the IN argument Username.
If it matches, then it checks for the password.
If password also matches, it will return SUCCESS and corresponding User ID.
Since duplicate username is supported in IPMI specification,
It will executes unless it gets SUCCESS or reaches MAX_USERS_COUNT.
Username and Password are IN arguments, UserID is OUT argument.
**/
int LIBIPMI_GetUserIDForUserName(IPMI20_SESSION_T *pSession, char *UserName, char *Password, uint8_t *UserID, int timeout)
{
	uint8_t Index = 0;
	char IPMI_Username[MAX_USERNAME_LEN];
	int retval = 0;
	*UserID = 0;

	for(Index = 1; Index <= MAX_USERS; Index++)
	{
		memset(IPMI_Username, 0, MAX_USERNAME_LEN);
		retval = GetUserNameForUserID(pSession, Index, IPMI_Username, timeout);
		if(retval == LIBIPMI_E_SUCCESS)
		{
			if(strncmp(UserName, IPMI_Username, MAX_USERNAME_LEN) == 0)
			{
				*UserID = Index;
				break;
			}
		}
	}
   
	if(*UserID != 0)
	{
		retval = CheckUserPassword(pSession, Index, Password, timeout);
		if(retval == LIBIPMI_E_SUCCESS)
		{
			*UserID = Index;
			return LIBIPMI_E_SUCCESS;
		}
		else
		{
			*UserID = 0;
			return LIBIPMI_E_INVALID_PASSWORD;
		}
	}
  
	return LIBIPMI_E_INVALID_USER_NAME;
}
