/****************************************************************
 ****************************************************************
 **                                                            **
 **    (C)Copyright 2005-2006, American Megatrends Inc.        **
 **                                                            **
 **            All Rights Reserved.                            **
 **                                                            **
 **        6145-F, Northbelt Parkway, Norcross,                **
 **                                                            **
 **        Georgia - 30071, USA. Phone-(770)-246-8600.         **
 **                                                            **
 ****************************************************************
 ****************************************************************/
/*****************************************************************
 *
 * RMCP.c
 * RMCP Message Handler
 *
 * Author: Govind Kothandapani <govindk@ami.com>
 *       : Bakka Ravinder Reddy <bakkar@ami.com>
 *
 *****************************************************************/
#include <stdio.h>
#include <stdint.h>

#include "com_Message.h"
#include "com_IPMIDefs.h"
#include "RMCP.h"
#include "RMCP+.h"
#include "Session.h"
#include "LANIfc.h"
#include "MD.h"
#include "MD5_128.h"
#include "main.h"

#if IPMI20_SUPPORT == 1

/*** Local definitions ***/
#define AUTH_ALGORITHM                      00
#define INTEGRITY_ALGORITHM                 01
#define CONFIDENTIALITY_ALGORITHM           02

#define MAX_ROLE_SUPPORTED                  0x05
#define MAX_REM_CON_RAND_NO_LEN             0x10
#define MAX_MGD_SYS_RAND_NO_LEN             0x10
#define MAX_MGD_SYS_GUID_LEN                0x10
#define MAX_HMAC_BUF_SIZE                   128
#define RAKP1_HASH_SIZE                     20
#define RAKP1_HASH_HMAC_MD5_SIZE            16
#define RAKP1_HASH_HMAC_SHA256_SIZE  		32

/* RSSP and RAKP Message Status Codes */
#define SC_NO_ERROR                         0
#define SC_INSUFFICIENT_RESOURCE            1
#define SC_INV_SESSION_ID                   2
#define SC_INV_PAYLOAD_TYPE                 3
#define SC_INV_AUTH_ALGORITHM               4
#define SC_INV_INTEGRITY_ALGORITHM          5
#define SC_NO_MATCHED_AUTH_PAYLOAD          6
#define SC_NO_MATCHED_INTEGRITY_PAYLOAD     7
#define SC_INACTIVE_SESSION_ID              8
#define SC_INV_ROLE                         9
#define SC_UNAUTHORISED_ROLE                10
#define SC_INSUFFICIENT_RESOURCE_AT_ROLE    11
#define SC_INV_NAME_LEN                     12
#define SC_UNAUTHORISED_NAME                13
#define SC_UNAUTHORISED_GUID                14
#define SC_INV_INTEGRITY_CHECK              15
#define SC_INV_CONFIDENTIALITY_ALGORTHM     16
#define SC_NO_CIPHER_SUITE_MATCH            17
#define SC_ILLEGAL_OR_UNRECOGNIZED_PARAM    18

/* Authentication Algorithm Numbers */
#define RAKP_NONE                   0
#define RAKP_HMAC_SHA1              1
#define RAKP_HMAC_MD5	            2
#define RAKP_HMAC_SHA256            3

#define HASH_KEY1_CONST_SIZE                20
#define HASH_KEY2_CONST_SIZE                20

/**
 * @var m_SIK
 * @brief Session Key.
**/
static  _FAR_ INT8U m_SIK [SHA2_HASH_KEY_SIZE];


/*----------------------------------------
 * RSSPOpenSessionReq
 *----------------------------------------*/
int
RSSPOpenSessionReq (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes, MiscParams_T *pParams, INT8U Channel, int BMCInst)
{
    _NEAR_  RSSPOpenSessionReq_T    *Req        =
                                      (_NEAR_ RSSPOpenSessionReq_T*)pReq;
    _NEAR_  RSSPOpenSessionRes_T    *Res        =
                                      (_NEAR_ RSSPOpenSessionRes_T*)pRes;
    _NEAR_  RSSPOpenSessionErrRes_T *ErrRes     =
                                      (_NEAR_ RSSPOpenSessionErrRes_T*)pRes;
    _FAR_   BMCInfo_t               *pBMCInfo   = 
                                    &g_BMCInfo[BMCInst];
    _FAR_   ChannelInfo_T           *pChannelInfo;
    INT8U                           Role, i, id;
    BOOL                            IsMatchReq      = FALSE;
    BOOL                            TrackRollOver   = FALSE;
    SessionInfo_T                   SessionInfo;
    INT32U                          TempSessId;
    INT8U                           CipherSuitePrivilage = 0;
    INT8U                           EthIndex;
    INT32U                          TrackRollOverSeq = SEQNUM_ROLLOVER;
    unsigned int                    seed = 1; 


    if(Channel == 0xFF)
    {
        Channel=GetLANChannel(Req->Reserved[0], BMCInst);
    }
    EthIndex= GetEthIndex(Channel, BMCInst);

    if(0xff == EthIndex)
    {
        IPMI_WARNING("\n Invalid Channel number :%x",Channel);
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChUserMutex,WAIT_INFINITE);
    /* Get information abt this channel */
    pChannelInfo = getChannelInfo (Channel, BMCInst);
    if (NULL == pChannelInfo)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        Res->StatusCode = SC_INSUFFICIENT_RESOURCE;
        return sizeof (RSSPOpenSessionErrRes_T);
    }

    if(pChannelInfo->ActiveSession >= pChannelInfo->SessionLimit)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        /* Session limit reached*/
        IPMI_WARNING ("RMCP+.c : OpenSessionReq - Session limit exceeded :%x\t%x BMCInst %x\n ",pChannelInfo->ActiveSession,pChannelInfo->SessionLimit,BMCInst);
        Res->StatusCode = SC_INSUFFICIENT_RESOURCE;
        return sizeof (RSSPOpenSessionErrRes_T);
    }
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);

    /* Get Role */
    Role = Req->Role & 0x0F;

    /* Fill Err Response to return, in case any error occurred */
    ErrRes->Reserved = 0;
    ErrRes->RemConSessionID = Req->RemConSessionID;

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->SessionTblMutex,WAIT_INFINITE);
    if (GetNumOfUsedSessions(BMCInst) >= pBMCInfo->IpmiConfig.MaxSession)
    {
        if(FALSE == CleanSession(BMCInst))
        {
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
            /* Session limit reached*/
            IPMI_WARNING ("RMCP+.c : OpenSessionReq - Session limit exceeded\n");
            Res->StatusCode = SC_INSUFFICIENT_RESOURCE;
            return sizeof (RSSPOpenSessionErrRes_T);
        }
    }

    /* Check Role  */
    if (Role > MAX_ROLE_SUPPORTED)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /* Invalid Payload Type */
        IPMI_WARNING ("RMCP+.c : OpenSessionReq - Invalid role\n");
        Res->StatusCode = SC_INV_ROLE;
        return sizeof (RSSPOpenSessionErrRes_T);
    }

    /*Check Payload Type */
    if ((AUTH_ALGORITHM             != Req->Auth.PayloadType) ||
        (INTEGRITY_ALGORITHM        != Req->Integrity.PayloadType) ||
        (CONFIDENTIALITY_ALGORITHM  != Req->Confidentiality.PayloadType))
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /* Invalid Payload Type */
        IPMI_WARNING ("RMCP+.c : OpenSessionReq - Invalid Payload\n");
        Res->StatusCode = SC_INV_PAYLOAD_TYPE;
        return sizeof (RSSPOpenSessionErrRes_T);
    }

    /* Search for the matching cipher suite id from Cipher suite record. if matching id found
           check for for requested role/privilege is allowed for privilege level for the cipher suite */
    for (i = 0, id = 0; i < MAX_CIPHER_SUITES_BYTES; i++, id++)
    {
        if (i * 5 + 1 > MAX_CIPHER_SUITES_BYTES)
        {
            break;
        }

        if (
            (((Req->Auth.PayloadType 	     << 6) | (Req->Auth.Algorithm & 0x3F))     	 	== g_CipherRec [(i * 5) + 2]) &&
            (((Req->Integrity.PayloadType    << 6) | (Req->Integrity.Algorithm & 0x3F))     == g_CipherRec [(i * 5) + 3]) &&
            (((Req->Confidentiality.PayloadType<< 6) | (Req->Confidentiality.Algorithm & 0x3F))== g_CipherRec [(i * 5) + 4])
           )
        {
            id = g_CipherRec[(i * 5) + 1];
            /* The Cipher Suite ID is matched */
            /* get the privilege level for the given cipher suite id, if id is even its lower nibble else upper nibble */
            CipherSuitePrivilage = pBMCInfo->LANCfs[EthIndex].CipherSuitePrivLevels [(id/2)+1];
            CipherSuitePrivilage = ((id % 2) == 0) ? (CipherSuitePrivilage & 0x0f) : ((CipherSuitePrivilage >> 4) & 0x0f) ;

            if(CipherSuitePrivilage == 0)
            {
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                Res->StatusCode = SC_NO_CIPHER_SUITE_MATCH;
                return sizeof (RSSPOpenSessionErrRes_T);
            }

            /*if requested privilege level is greater than cipher suite id privilege level return errror*/
            if ((CipherSuitePrivilage != 0) && (Role > CipherSuitePrivilage))
            {
                /* Invalid Payload Type */
                //Res->StatusCode = SC_UNAUTHORISED_ROLE;
                //return sizeof (RSSPOpenSessionErrRes_T);
                Role = CipherSuitePrivilage;
            }
            break;
        }
    }
    /* Role 0 indicates to find possible match */
    if (0 == Role)
    {
        IsMatchReq  = TRUE;
        Role        = MAX_ROLE_SUPPORTED;
    }

    /* Find Match */
    do
    {
        Res->StatusCode = SC_NO_ERROR;

        /*Check if requested authentication Algorithm supported **/
        if (0 != Req->Auth.PayloadLen)
        {
            if ((sizeof (RSSPPayloadInfo_T) != Req->Auth.PayloadLen) ||
                (0 == (pBMCInfo->RMCPPlus[EthIndex].Algorithm [Req->Auth.PayloadType] [Role] &
                         (1 << Req->Auth.Algorithm))))
            {
                /* AuthAlgorithm not supported */
                IPMI_DBG_PRINT ("RMCP+.c : OpenSessionReq - Authentication not supported \n");
                Res->StatusCode = SC_NO_CIPHER_SUITE_MATCH;
            }
        }

        /*Check if requested Integrity Algorithm supported  **/
        if (0 != Req->Integrity.PayloadLen)
        {
            if ((sizeof (RSSPPayloadInfo_T) != Req->Integrity.PayloadLen) ||
                (0 == (pBMCInfo->RMCPPlus[EthIndex].Algorithm [Req->Integrity.PayloadType] [Role] &
                         (1 << Req->Integrity.Algorithm))))
            {
                /* Integrity Algorithm not supported */
                IPMI_DBG_PRINT ("RMCP+.c : OpenSessionReq - Integrity not supported\n");
                Res->StatusCode = SC_NO_CIPHER_SUITE_MATCH;
            }
        }

        /*Check if requested Confidentiality Algorithm supported    **/
        if (0 != Req->Confidentiality.PayloadLen)
        {
            if ((sizeof (RSSPPayloadInfo_T) != Req->Confidentiality.PayloadLen) ||
                (0 == (pBMCInfo->RMCPPlus[EthIndex].Algorithm [Req->Confidentiality.PayloadType] [Role] &
                         (1 << Req->Confidentiality.Algorithm))))
            {
                /* Confidentiality Algorithm not supported */
                IPMI_DBG_PRINT ("RMCP+.c : OpenSessionReq - Confidentiality not supported \n");
                Res->StatusCode = SC_NO_CIPHER_SUITE_MATCH;
            }
        }

        if ((SC_NO_ERROR  == Res->StatusCode) &&
            ((CipherSuitePrivilage == 0) || (Role <= CipherSuitePrivilage)))
        {
            /* Found Match */
            break;
        }

    } while (IsMatchReq && Role--);

    /* Return Err response */
    if (Res->StatusCode != SC_NO_ERROR)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        IPMI_WARNING ("RMCP+.c : OpenSessionReq - Error Response\n");
        return sizeof (RSSPOpenSessionErrRes_T);
    }

    if (GetNumOfActiveSessions (BMCInst) >= pBMCInfo->IpmiConfig.MaxSession)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /* No slot available */
        Res->StatusCode = SC_INSUFFICIENT_RESOURCE;
        return sizeof (RSSPOpenSessionErrRes_T);
    }
    /* Add Session Info */
    _fmemset (&SessionInfo, 0, sizeof (SessionInfo_T));
    /* Activated in ActivateSession Command */
    SessionInfo.Activated       = FALSE;
    SessionInfo.RemConSessionID = Req->RemConSessionID;
    SessionInfo.MaxPrivilege = Role;

    do{
        /*generate 32 bit temp session Id*/
        TempSessId = ((INT32U)rand_r(&seed) << 16) | rand_r (&seed); 
    } while ((NULL != getSessionInfo (SESSION_ID_INFO, &TempSessId, BMCInst)) ||
             (0 == TempSessId));

    SessionInfo.SessionID               = TempSessId;
    SessionInfo.Channel                 = Channel;
    SessionInfo.AuthAlgorithm           = Req->Auth.Algorithm;
    SessionInfo.IntegrityAlgorithm      = Req->Integrity.Algorithm;
    SessionInfo.ConfidentialityAlgorithm = Req->Confidentiality.Algorithm;
    if(pParams->IsPktFromLoopBack)
    {
        if(IPMITimeout > 0)
        {
            SessionInfo.TimeOutValue = (IPMITimeout+10);
        }
        else
        {
            /*If it is not defined the timeout values for loop back session should be 
                    SESSION_TIMEOUT defined in config.make.ipmi (60 seconds) */
            SessionInfo.TimeOutValue =  pBMCInfo->IpmiConfig.SessionTimeOut;
        }
        SessionInfo.IsLoopBack              = TRUE;
    }
    else
        SessionInfo.TimeOutValue          = pBMCInfo->IpmiConfig.SessionTimeOut;
    
    if(pBMCInfo->IpmiConfig.SOLIfcSupport == 1)
    {
        if(SessionInfo.SessPyldInfo [PAYLOAD_SOL].Type == PAYLOAD_SOL)
        {
            SessionInfo.TimeOutValue = pBMCInfo->IpmiConfig.SOLSessionTimeOut;
        }
    }
    
    SessionInfo.UserId  = 0xff;
    SessionInfo.SessPyldInfo [0].AuxConfig [0] =
        ((0 != Req->Integrity.Algorithm) ? 0x40: 0x00) |
        ((0 != Req->Confidentiality.Algorithm) ? 0x80: 0x00);
    SessionInfo.InitialInboundSeq   = SEQNUM_ROLLOVER;
    SessionInfo.InboundSeq  = 0x00;

    for(i=0; i < RMCPPLUS_SEQLOWLIMIT; i++)
    {
        if(((SessionInfo.InitialInboundSeq - (i+1)) != 0) &&(TrackRollOver == FALSE))
            SessionInfo.InboundTrac[i] = SessionInfo.InitialInboundSeq - (i+1);
        else if(((SessionInfo.InitialInboundSeq - (i+1)) == 0) &&(TrackRollOver == FALSE))
        {
            SessionInfo.InboundTrac[i] = SessionInfo.InitialInboundSeq - (i+1);
            TrackRollOver = TRUE;
        }
        else if(TrackRollOver == TRUE)
        {
            SessionInfo.InboundTrac[i] = TrackRollOverSeq;
            TrackRollOverSeq--;
        }
    }

    SessionInfo.InboundRecv = 0xFF; 
    AddSession (&SessionInfo, BMCInst);

    /* Load RSSP Open session Response */
    Res->Role = Role;
    Res->Reserved = 0x00;
    Res->RemConSessionID    = Req->RemConSessionID;
    Res->MgdSysSessionID    = SessionInfo.SessionID;

    /* Auth Algorithm Details */
    Res->Auth.PayloadType   = AUTH_ALGORITHM;
    Res->Auth.Reserved1 = 0;
    Res->Auth.PayloadLen    = sizeof (RSSPPayloadInfo_T);
    Res->Auth.Algorithm     = Req->Auth.Algorithm;
    memset(Res->Auth.Reserved2, 0x0, 3);

    /* Integrity Algorithm Details */
    Res->Integrity.PayloadType  = INTEGRITY_ALGORITHM;
    Res->Integrity.Reserved1 = 0;
    Res->Integrity.PayloadLen   = sizeof (RSSPPayloadInfo_T);
    Res->Integrity.Algorithm    = Req->Integrity.Algorithm;
    memset(Res->Integrity.Reserved2, 0x0, 3);

    /* Confidentiality Algorithm Details */
    Res->Confidentiality.PayloadType = CONFIDENTIALITY_ALGORITHM;
    Res->Confidentiality.Reserved1 = 0;
    Res->Confidentiality.PayloadLen  = sizeof (RSSPPayloadInfo_T);
    Res->Confidentiality.Algorithm   = Req->Confidentiality.Algorithm;
    memset(Res->Confidentiality.Reserved2, 0x0, 3);
    
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);

    return sizeof (RSSPOpenSessionRes_T);
}


/*----------------------------------------
 * RAKPMsg1
 *----------------------------------------*/
int
RAKPMsg1 (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes, MiscParams_T *pParams, INT8U Channel, int BMCInst)
{
    _NEAR_  RAKPMsg1Req_T       *Req     = (_NEAR_ RAKPMsg1Req_T*) pReq;
    _NEAR_  RAKPMsg2Res_T       *Res     = (_NEAR_ RAKPMsg2Res_T*) pRes;
    _NEAR_  RAKPMsg2ErrRes_T    *ErrRes  = (_NEAR_ RAKPMsg2ErrRes_T*) pRes;
    _FAR_   SessionInfo_T       *pSessInfo;
    _FAR_   ChannelUserInfo_T   *pChUserInfo;
    _FAR_   ChannelInfo_T       *pChannelInfo;
    _FAR_   UserInfo_T          *pUserInfo;
    _FAR_   RAKPMsg1HMAC_T      *pMsghmac;
    _FAR_   BMCInfo_t           *pBMCInfo = &g_BMCInfo[BMCInst];
    INT8U   Index;
    INT8U   AuthCodeLen = 0;
    INT8U   Role;
    INT32U  ManSysSessionID;
    int     i;
    unsigned int seed = 1;
    INT8U PwdEncKey[MAX_SIZE_KEY + 1] = {0};

    /*Validate Mgd session ID*/
    Role                    = Req->Role & 0x0f;
    ManSysSessionID         = Req->ManSysSessionID;
    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->SessionTblMutex,WAIT_INFINITE);
    pSessInfo               = getSessionInfo (SESSION_ID_INFO, (_FAR_ void*)&ManSysSessionID, BMCInst);
    if (NULL == pSessInfo)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        IPMI_WARNING ("RMCP+.c : RAKPMsg1 - Invalid Session ID\n");
        ErrRes->StatusCode  = SC_INV_SESSION_ID;
        return sizeof (RAKPMsg2ErrRes_T);
    }
    /* In case of error, delete this session info */
    pBMCInfo->LANConfig.DeleteThisLANSessionID = ManSysSessionID;

    if(Channel == 0xFF)
    {
        Channel= pSessInfo->Channel;
    }

    ErrRes->RemConSessionID = pSessInfo->RemConSessionID;

    /* Check Role  */
    if (Role >  MAX_ROLE_SUPPORTED)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /* Invalid Role */
        IPMI_WARNING ("RMCP+.c : RAKPMsg1 - Invalid Role\n");
        Res->StatusCode = SC_INV_ROLE;
        return sizeof (RAKPMsg2ErrRes_T);
    }

    /* Check User Name Length */
    if (Req->UsrNameLen > MAX_USERNAME_LEN)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /* Invalid Name Len */
        IPMI_WARNING ("RMCP+.c : RAKPMsg1 - Username len exceeded\n");
        Res->StatusCode = SC_INV_NAME_LEN;
        return sizeof (RAKPMsg2ErrRes_T);
    }

    /* Privilege for the session has to be assigned in RAKP1 only */
    pSessInfo->Privilege = Role & 0xF;

    /* Pad with NULL characters */
    _fmemset (&Req->UsrName [Req->UsrNameLen], 0, MAX_USERNAME_LEN - Req->UsrNameLen);

    pChannelInfo = getChannelInfo (Channel, BMCInst);
    if (NULL == pChannelInfo)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /* InSufficient resources */
        IPMI_WARNING ("RMCP+.c : RAKPMsg1 - Insufficient resource\n");
        Res->StatusCode = SC_INSUFFICIENT_RESOURCE;
        return sizeof (RAKPMsg2ErrRes_T);
    }


    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChUserMutex,WAIT_INFINITE);
    pSessInfo->Lookup = ((Req->Role & 0x10) >> 0x04);

    if( pParams->IsPktFromLoopBack == TRUE  &&  Req->UsrName[0] == 0 )
    {
        pUserInfo = getUserIdInfo (NULL_USER, BMCInst);
        pSessInfo->UserId = NULL_USER;
        memset (pSessInfo->Password, 0, MAX_PASSWORD_LEN);
    }
    else
    {
        if (USER_ROLE_LOOKUP == pSessInfo->Lookup)
        {
        /* Get userInfo for the given userName and privilege */
        pChUserInfo = getChUserPrivInfo ((_NEAR_ char *)Req->UsrName, Role, &Index,
        pChannelInfo->ChannelUserInfo, BMCInst);

        /* If user not found  */
        if (NULL == pChUserInfo)
        {
            /* Invalid user     */
            IPMI_WARNING ("RMCP+.c : RAKPMsg1 - user_priv - User not found : %s\n", (_NEAR_ char *)Req->UsrName);

            if ( 0 != AddLoginEvent( 0xFF, Req->UsrName, EVENT_LOGIN_FAILURE, BMCInst ) )
            {
                    TCRIT("Problem while adding Log record \n");
            }
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
            Res->StatusCode = SC_UNAUTHORISED_NAME;
            return sizeof (RAKPMsg2ErrRes_T);
        }

        /* Check Role  */
        if (pChUserInfo->AccessLimit == 0xF )
        {
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
            /* Invalid Role */
            IPMI_WARNING ("RMCP+.c : RAKPMsg1 - user_priv - Invalid Role\n");
            Res->StatusCode = SC_INV_ROLE;
            return sizeof (RAKPMsg2ErrRes_T);
        }

        //we cannot assign the pSessInfo->privilege here..this will cause RAKP3 integrity check to fail
        //this is because the client will do integrity with the requested role rather than the max permissible role
        // which we set here. client has no way of knowing at that time
        //pSessInfo->Privilege = Role;
        }
        else /* if (NAME_ONLY_LOOKUP == pSessInfo->Lookup) */
        {
            /* Get userInfo for the given userName*/
            pChUserInfo = getChUserInfo ((_NEAR_ char *)Req->UsrName, &Index,
            pChannelInfo->ChannelUserInfo, BMCInst);
            /* If user not found  */
            if (NULL == pChUserInfo)
            {
                /* Invalid user     */
                IPMI_WARNING ("RMCP+.c : RAKPMsg1 - name_only - User not found\n");

                if ( 0 != AddLoginEvent( 0xFF, Req->UsrName, EVENT_LOGIN_FAILURE, BMCInst ))
                {
                    TCRIT("Problem while adding Log record \n");
                }

                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                Res->StatusCode = SC_UNAUTHORISED_NAME;
                return sizeof (RAKPMsg2ErrRes_T);
            }

            /* Check Role  */
            if (pChUserInfo->AccessLimit == 0xF )
            {
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                /* Invalid Role */
                IPMI_WARNING ("RMCP+.c : RAKPMsg1 - name_only - Invalid Role\n");
                Res->StatusCode = SC_INV_ROLE;
                return sizeof (RAKPMsg2ErrRes_T);
            }
        }

        pUserInfo = getUserIdInfo (pChUserInfo->UserId, BMCInst);
        if (pUserInfo == NULL || FALSE == pUserInfo->UserStatus)
        {
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
            /*user name not enabled*/
            IPMI_WARNING ("RMCP+.c : RAKPMsg1 - User not found in database\n");
            Res->StatusCode = SC_UNAUTHORISED_NAME;
            return sizeof (RAKPMsg2ErrRes_T);
        }

        /* Load UserId Session Info */
        pSessInfo->UserId = (INT8U)pChUserInfo->UserId;
        if (g_corefeatures.userpswd_encryption == ENABLED)
        {
            /* Get Encryption Key from the MBMCInfo_t structure */
            memcpy(PwdEncKey, &(g_MBMCInfo.PwdEncKey), MAX_SIZE_KEY);

            if(DecryptPassword((INT8S *)(pBMCInfo->EncryptedUserInfo[pChUserInfo->UserId - 1].EncryptedPswd), MAX_PASSWORD_LEN, (INT8S*)pSessInfo->Password, MAX_PASSWORD_LEN, PwdEncKey))
            {
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                TCRIT("Error in decrypting the user password for user ID:%d. .\n", pChUserInfo->UserId);
                Res->StatusCode  = SC_INSUFFICIENT_RESOURCE;
                return sizeof(RAKPMsg2ErrRes_T);
            }
        }
        else
        {
        	_fmemcpy (pSessInfo->Password, pUserInfo->UserPassword, MAX_PASSWORD_LEN);
        }
    }

    /* Check for Empty password login */
    if ( ENABLED == g_corefeatures.disable_empty_passwd_login && NULL_USER != pSessInfo->UserId && 0 == pSessInfo->Password[0])
    {
        IPMI_WARNING("RMCP+c : RAKPMsg1 - Empty Password Login is not allowed \n");

        if ( 0 != AddLoginEvent(pSessInfo->UserId, NULL, EVENT_LOGIN_FAILURE, BMCInst))
        {
             TCRIT("Problem while adding Log record \n");
        }

        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        Res->StatusCode = SC_ILLEGAL_OR_UNRECOGNIZED_PARAM;
        return sizeof(RAKPMsg2ErrRes_T);
    }

    /* Check for Default Empty password login */
    if(ENABLED != g_corefeatures.allow_default_empty_passwd_login && NULL_USER != pSessInfo->UserId && 0 == pSessInfo->Password[0] && pUserInfo->UserPasswdConfigured == 0)
    {
        TDBG("RMCP+c : RAKPMsg1 - User Password is not yet configured; Default Empty Password Login is not allowed \n");
        if ( 0 != AddLoginEvent(pSessInfo->UserId, NULL, EVENT_LOGIN_FAILURE, BMCInst))
        {
             TCRIT("Problem while adding Log record \n");
        }
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        Res->StatusCode = SC_ILLEGAL_OR_UNRECOGNIZED_PARAM;
        return sizeof(RAKPMsg2ErrRes_T);
    }

    if(FindUserLockStatus(pSessInfo->UserId, Channel, BMCInst) != 0)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        IPMI_WARNING("RMCP+c : RAKPMsg1 - User is Locked \n");
        /* As of now sending Invalid Role for bad password*/
        Res->StatusCode = SC_INV_ROLE;
        return sizeof(RAKPMsg2ErrRes_T);
    }

    /* Check the number of active sessions */
    if (pUserInfo->CurrentSession >= pUserInfo->MaxSession)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        /*can't accept any more session for this user*/
        Res->StatusCode = SC_INSUFFICIENT_RESOURCE;
        return  sizeof (RAKPMsg2ErrRes_T);
    }
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);

    /* Load Response */
    Res->StatusCode = SC_NO_ERROR;
    /* Store the Remote Console Random number in SessionInfo */
    _fmemcpy (pSessInfo->RemConRandomNo, Req->RemConRandomNo,
              MAX_REM_CON_RAND_NO_LEN);

    for (i = 0 ; i < MAX_MGD_SYS_RAND_NO_LEN; i++)
    {
        Res->ManSysRandomNo [i] = rand_r (&seed);
    }

    /* Store the Managed System Random number in SessionInfo */
    _fmemcpy (pSessInfo->MgdSysRandomNo, Res->ManSysRandomNo,
              MAX_MGD_SYS_RAND_NO_LEN);

    /* Copy the System GUID */
    _fmemcpy (Res->ManSysGUID, BMC_GET_SHARED_MEM (BMCInst)->SystemGUID, 16);

    /* Key Exchange Auth Code  */
    switch (pSessInfo->AuthAlgorithm)
    {
        case RAKP_NONE:
            AuthCodeLen = 0;
            break;

        case RAKP_HMAC_SHA1:
            {
                INT8U PasswdLen = 0;

                pMsghmac                    = (_FAR_ RAKPMsg1HMAC_T*)pBMCInfo->LANConfig.HmacInBuf;
                pMsghmac->RemConSessionID   = pSessInfo->RemConSessionID;
                pMsghmac->MgdSysSessionID   = pSessInfo->SessionID;
                /* Copy Random no.s  and GUID */
                _fmemcpy (pMsghmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
                _fmemcpy (pMsghmac->MgdSysRandNo, pSessInfo->MgdSysRandomNo, 16);
                _fmemcpy (pMsghmac->MgdSysGUID, Res->ManSysGUID, MAX_MGD_SYS_GUID_LEN);

                pMsghmac->Role          = Req->Role;
                pMsghmac->UsrNameLen    = Req->UsrNameLen;
                _fmemcpy (pMsghmac->UsrName, Req->UsrName, Req->UsrNameLen);

                PasswdLen = _fstrlen ((_FAR_ char*)pSessInfo->Password);
                PasswdLen = (PasswdLen > MAX_PASSWORD_LEN) ?
                            MAX_PASSWORD_LEN : PasswdLen;
                hmac_sha1 ((INT8U *)pSessInfo->Password, PasswdLen, (INT8U *)pBMCInfo->LANConfig.HmacInBuf,
                           (sizeof (RAKPMsg1HMAC_T) - MAX_USERNAME_LEN + Req->UsrNameLen),
                           (INT8U *)&pRes [sizeof (RAKPMsg2Res_T)], RAKP1_HASH_SIZE);
                AuthCodeLen = RAKP1_HASH_SIZE;
                break;
            }

        case RAKP_HMAC_MD5:
            {
                INT8U PasswdLen = 0;

                pMsghmac                    = (_FAR_ RAKPMsg1HMAC_T*)pBMCInfo->LANConfig.HmacInBuf;
                pMsghmac->RemConSessionID   = pSessInfo->RemConSessionID;
                pMsghmac->MgdSysSessionID   = pSessInfo->SessionID;
                /* Copy Random no.s  and GUID */
                _fmemcpy (pMsghmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
                _fmemcpy (pMsghmac->MgdSysRandNo, pSessInfo->MgdSysRandomNo, 16);
                _fmemcpy (pMsghmac->MgdSysGUID, Res->ManSysGUID, MAX_MGD_SYS_GUID_LEN);

                pMsghmac->Role          = Req->Role;
                pMsghmac->UsrNameLen    = Req->UsrNameLen;
                _fmemcpy (pMsghmac->UsrName, Req->UsrName, Req->UsrNameLen);

                PasswdLen = _fstrlen ((_FAR_ char*)pSessInfo->Password);
                PasswdLen = (PasswdLen > MAX_PASSWORD_LEN) ?
                            MAX_PASSWORD_LEN : PasswdLen;
                hmac_md5(pSessInfo->Password, PasswdLen, pBMCInfo->LANConfig.HmacInBuf,
                           (sizeof (RAKPMsg1HMAC_T) - MAX_USERNAME_LEN + Req->UsrNameLen),
                           &pRes [sizeof (RAKPMsg2Res_T)], RAKP1_HASH_HMAC_MD5_SIZE);
                AuthCodeLen = RAKP1_HASH_HMAC_MD5_SIZE;
                break;
            }

        case RAKP_HMAC_SHA256:
			{
        		INT8U PasswdLen = 0;

         		pMsghmac                    = (_FAR_ RAKPMsg1HMAC_T*)pBMCInfo->LANConfig.HmacInBuf;
                pMsghmac->RemConSessionID   = pSessInfo->RemConSessionID;
                pMsghmac->MgdSysSessionID   = pSessInfo->SessionID;
                /* Copy Random nos  and GUID */
				_fmemcpy (pMsghmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
				_fmemcpy (pMsghmac->MgdSysRandNo, pSessInfo->MgdSysRandomNo, 16);
				_fmemcpy (pMsghmac->MgdSysGUID, Res->ManSysGUID, MAX_MGD_SYS_GUID_LEN);

				pMsghmac->Role          = Req->Role;
				pMsghmac->UsrNameLen    = Req->UsrNameLen;
				_fmemcpy (pMsghmac->UsrName, Req->UsrName, Req->UsrNameLen);

				PasswdLen = _fstrlen ((_FAR_ char*)pSessInfo->Password);
				PasswdLen = (PasswdLen > MAX_PASSWORD_LEN) ?
								MAX_PASSWORD_LEN : PasswdLen;

        		hmac_sha256(pSessInfo->Password, PasswdLen, pBMCInfo->LANConfig.HmacInBuf,
        			 (sizeof (RAKPMsg1HMAC_T) - MAX_USERNAME_LEN + Req->UsrNameLen),
        	               &pRes [ sizeof (RAKPMsg2Res_T)], RAKP1_HASH_HMAC_SHA256_SIZE);
				AuthCodeLen = RAKP1_HASH_HMAC_SHA256_SIZE;
                break;
           	}        	
			
        default:
            IPMI_WARNING ("RMCP+.c : RAKPMsg1 - Invalid Authentication\n");
            AuthCodeLen = 0;
    }

    pBMCInfo->LANConfig.DeleteThisLANSessionID = 0;
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);

    return sizeof (RAKPMsg2Res_T) + AuthCodeLen;
}


/*----------------------------------------
 * RAKPMsg3
 *----------------------------------------*/
int
RAKPMsg3 (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes, MiscParams_T *pParams,INT8U Channel, int BMCInst)
{
    _NEAR_  RAKPMsg3Req_T       *Req     = (_NEAR_ RAKPMsg3Req_T*)pReq;
    _NEAR_  RAKPMsg4Res_T       *Res     = (_NEAR_ RAKPMsg4Res_T*)pRes;
    _FAR_   SessionInfo_T       *pSessInfo;
    _NEAR_  INT8U               *pKeyXchgCode;
    _NEAR_  SIKhmac_T           *pSIKhmac;
    _FAR_   Msg3hmac_T          *pMsg3hmac;
    _FAR_   UserInfo_T          *pUserInfo;
    _FAR_   RAKPMsg4hmac_T      *pMsg4hmac;
    _FAR_   ChannelInfo_T       *pChannelInfo;
    _FAR_   ChannelUserInfo_T   *pChUserInfo;
    _FAR_   BMCInfo_t           *pBMCInfo = &g_BMCInfo[BMCInst];
            INT8U               TempKey [HASH_KEY1_CONST_SIZE];
            INT8U               TempKey2 [HASH_KEY2_CONST_SIZE];
            INT8U               UserPasswdLen=0;
            int                 i;
            INT8U               ResIntigrityKeyLen=0;
            INT8U               Index;
            INT8U               EthIndex;
            INT8U               UserPswd [MAX_PASSWORD_LEN];
            INT32U              SessionID;
            INT8U PwdEncKey[MAX_SIZE_KEY + 1] = {0};

    SessionID = Req->ManSysSessionID;
    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->SessionTblMutex,WAIT_INFINITE);
    pSessInfo = getSessionInfo (SESSION_ID_INFO, &SessionID, BMCInst);
    /* In case of error, delete this session info */
    pBMCInfo->LANConfig.DeleteThisLANSessionID = Req->ManSysSessionID;

    /* Check if Management System SessionID */
    if (NULL == pSessInfo)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid Session ID\n");
        Res->StatusCode = SC_INV_SESSION_ID;
        return sizeof (RAKPMsg4Res_T);
    }

    /* Check if previous transactions caused an error */
    if (Req->StatusCode !=  SC_NO_ERROR)
    {
        if(Req->StatusCode == SC_INV_INTEGRITY_CHECK)
        {
            OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChUserMutex,WAIT_INFINITE);
            LockUser(pSessInfo->UserId,Channel, BMCInst);
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        }
        IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid Status\n");

        if ( 0 != AddLoginEvent( pSessInfo->UserId, NULL, EVENT_LOGIN_FAILURE, BMCInst ))
        {
            IPMI_WARNING("Problem while adding Log record \n");
        }

        Res->StatusCode = Req->StatusCode;
        DeleteSession(pSessInfo,BMCInst);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        return 0;
    }

    UnlockUser(pSessInfo->UserId,Channel,BMCInst);

    if(Channel == 0xFF)
    {
        Channel= pSessInfo->Channel;
    }

    EthIndex= GetEthIndex(Channel, BMCInst);

    if(0xff == EthIndex)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChUserMutex,WAIT_INFINITE);
    /* Get User Info */
    pUserInfo = getUserIdInfo((INT8U)pSessInfo->UserId, BMCInst);
    if (NULL == pUserInfo)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        IPMI_WARNING ("RMCP+.c : RAKPMsg3 - User not found\n");
        Res->StatusCode = SC_UNAUTHORISED_NAME;
        return sizeof (RAKPMsg4Res_T);
    }

    if (g_corefeatures.userpswd_encryption == ENABLED)
    {
        /* Get Encryption Key from the MBMCInfo_t structure */
            memcpy(PwdEncKey, &(g_MBMCInfo.PwdEncKey), MAX_SIZE_KEY);

        if(DecryptPassword((INT8S *)(pBMCInfo->EncryptedUserInfo[pSessInfo->UserId - 1].EncryptedPswd), MAX_PASSWORD_LEN, (char *)UserPswd, MAX_PASSWORD_LEN, PwdEncKey))
        {
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
            IPMI_ERROR("Error in decrypting the user password for user ID:%d. .\n", pSessInfo->UserId);
            Res->StatusCode = CC_UNSPECIFIED_ERR;
            return sizeof(RAKPMsg4Res_T);
        }
    }
    else
    {
    	_fmemcpy (UserPswd, pUserInfo->UserPassword, MAX_PASSWORD_LEN);
    }

    UserPasswdLen = _fstrlen ((_FAR_ char*)UserPswd);
    UserPasswdLen = (UserPasswdLen > MAX_PASSWORD_LEN) ?
                    MAX_PASSWORD_LEN : UserPasswdLen;

    /* Check for Key Exchange Auth Code */
    pKeyXchgCode = (_FAR_ INT8U*)(pReq + sizeof (RAKPMsg3Req_T));

    /*Construct hmac to check Auth code */
    pMsg3hmac = (_FAR_	Msg3hmac_T*) &pBMCInfo->LANConfig.HmacInBuf;
    _fmemcpy (pMsg3hmac->MgdSysRandNo, pSessInfo->MgdSysRandomNo, 16);
    pMsg3hmac->RemConSessionID  = pSessInfo->RemConSessionID;
    pMsg3hmac->Role             = pSessInfo->Privilege | (pSessInfo->Lookup << 4);
    pMsg3hmac->UsrNameLen       = _fstrlen ((_FAR_ char*)pUserInfo->UserName);
    pMsg3hmac->UsrNameLen        = (pMsg3hmac->UsrNameLen > MAX_USERNAME_LEN) ?
                                        MAX_USERNAME_LEN : pMsg3hmac->UsrNameLen;

    _fmemcpy ((_FAR_ char*)pMsg3hmac->UsrName,
          (_FAR_ char*)pUserInfo->UserName, pMsg3hmac->UsrNameLen);

    /* Key Exchange Auth Code  */
    switch (pSessInfo->AuthAlgorithm)
    {
        case RAKP_NONE:
            break;

        case RAKP_HMAC_SHA1:
            hmac_sha1 ((INT8U *)UserPswd, UserPasswdLen, (INT8U *)pBMCInfo->LANConfig.HmacInBuf,
                       sizeof (Msg3hmac_T) - (16 - pMsg3hmac->UsrNameLen),
                       (INT8U *)&pRes [ sizeof (RAKPMsg4Res_T)], RAKP1_HASH_SIZE);

            if (0 != _fmemcmp (pKeyXchgCode, &pRes [sizeof (RAKPMsg4Res_T)], RAKP1_HASH_SIZE))
            {
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid integrity check\n");
                Res->StatusCode = SC_INV_INTEGRITY_CHECK;
                return sizeof (RAKPMsg4Res_T);
            }
            break;

        case RAKP_HMAC_MD5:
            hmac_md5(UserPswd, UserPasswdLen, pBMCInfo->LANConfig.HmacInBuf,
                       sizeof (Msg3hmac_T) - (MAX_USERNAME_LEN - pMsg3hmac->UsrNameLen),
                       &pRes [ sizeof (RAKPMsg4Res_T)], RAKP1_HASH_HMAC_MD5_SIZE);

            if (0 != _fmemcmp (pKeyXchgCode, &pRes [sizeof (RAKPMsg4Res_T)], RAKP1_HASH_HMAC_MD5_SIZE))
            {
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid integrity check\n");
                Res->StatusCode = SC_INV_INTEGRITY_CHECK;
                return sizeof (RAKPMsg4Res_T);
            }
            break;

        case RAKP_HMAC_SHA256:
        	hmac_sha256(pSessInfo->Password, UserPasswdLen, pBMCInfo->LANConfig.HmacInBuf,
        		 sizeof (Msg3hmac_T) - (MAX_USERNAME_LEN - pMsg3hmac->UsrNameLen),
                       &pRes [ sizeof (RAKPMsg4Res_T)], RAKP1_HASH_HMAC_SHA256_SIZE);
        	 if (0 != _fmemcmp (pKeyXchgCode, &pRes [sizeof (RAKPMsg4Res_T)], RAKP1_HASH_HMAC_SHA256_SIZE))
                {
                    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
                    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
                    IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid integrity check\n");
                    Res->StatusCode = SC_INV_INTEGRITY_CHECK;
                    return sizeof (RAKPMsg4Res_T);
                }
                break;        

        default:
            IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid Authentication\n");
    }

    /*Construct SIK to send the Integrity check */
    memset(pBMCInfo->LANConfig.HmacInBuf,0,sizeof(pBMCInfo->LANConfig.HmacInBuf));
    memset(pBMCInfo->LANConfig.SIK,0,sizeof(pBMCInfo->LANConfig.SIK));

    pSIKhmac = (_FAR_  SIKhmac_T*) &pBMCInfo->LANConfig.HmacInBuf;

    _fmemcpy (pSIKhmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
    _fmemcpy (pSIKhmac->MgdSysRandNo, pSessInfo->MgdSysRandomNo, 16);
    pSIKhmac->Role = pSessInfo->Privilege | (pSessInfo->Lookup << 4) ;
    pSIKhmac->UsrNameLen = _fstrlen ((_FAR_ char*)pUserInfo->UserName);
    pSIKhmac->UsrNameLen = (pSIKhmac->UsrNameLen > MAX_USERNAME_LEN) ?
                           MAX_USERNAME_LEN : pSIKhmac->UsrNameLen;
    _fmemcpy ((_FAR_ char*)pSIKhmac->UsrName,
              (_FAR_ char*)pUserInfo->UserName, pSIKhmac->UsrNameLen);

    for (i = 0; i < HASH_KEY_LEN; i++)
    {
        if (pBMCInfo->RMCPPlus[EthIndex].KGHashKey [i] != 0)
        {
            break;
        }
    }

    switch(pSessInfo->AuthAlgorithm)
    {
        case RAKP_NONE:
             break;

        case RAKP_HMAC_SHA1: 
        {
            // Encryption key must not be used for packets from VLAN or Loopback.
        #ifdef  LAN_RESTRICTIONS_BYPASS_FOR_LOOPBACK_AND_VLAN
            if ((i < HASH_KEY_LEN) && !(pParams->IsPktFromVLAN || pParams->IsPktFromLoopBack) )
        #else
            if ((i < HASH_KEY_LEN))
        #endif
            {
                /* Use the KG (BMC Key set through SetChSecurityKeys command) Key */
                hmac_sha1 ((INT8U *)pBMCInfo->RMCPPlus[EthIndex].KGHashKey, HASH_KEY_LEN, (INT8U *)pBMCInfo->LANConfig.HmacInBuf,
                                    (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen),
                                    (INT8U *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE);
            }
            else
            {
                /* Use the KUID (User Password) Key */
                hmac_sha1 ((INT8U *)UserPswd, UserPasswdLen, (INT8U *)pBMCInfo->LANConfig.HmacInBuf,
                                    (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen),
                                    (INT8U *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE);
            }

            /* Create Key1 & Key2 for Rest of packet Integrity & Encryption */
            _fmemset (TempKey, 1, HASH_KEY1_CONST_SIZE);
            hmac_sha1 ((INT8U *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, (INT8U *)TempKey, HASH_KEY1_CONST_SIZE,
                                    (INT8U *)pSessInfo->Key1, HASH_KEY1_SIZE);
            _fmemset (TempKey2, 2, HASH_KEY2_CONST_SIZE);
            hmac_sha1 ((INT8U *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, (INT8U *)TempKey2, HASH_KEY2_CONST_SIZE,
                                    (INT8U *)pSessInfo->Key2, HASH_KEY2_SIZE);

            /* Construct HMAC to send the Integrity check value using SIK got from prev hmac*/
            pMsg4hmac = (_FAR_ RAKPMsg4hmac_T*) &pBMCInfo->LANConfig.HmacInBuf;
            _fmemcpy (pMsg4hmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
            pMsg4hmac->MgdSysSessionID = pSessInfo->SessionID;
            /*Get System GUID */
            _fmemcpy (pMsg4hmac->MgdSysGUID, BMC_GET_SHARED_MEM (BMCInst)->SystemGUID, 16);
            hmac_sha1 ((INT8U *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, (INT8U *)pBMCInfo->LANConfig.HmacInBuf, sizeof (RAKPMsg4hmac_T),
                                    (INT8U *)&pRes [sizeof (RAKPMsg4Res_T)], HASH_KEY1_CONST_SIZE);
            ResIntigrityKeyLen = HMAC_SHA1_96_LEN;
            break;
        }

        case RAKP_HMAC_MD5:
            {
            #ifdef  LAN_RESTRICTIONS_BYPASS_FOR_LOOPBACK_AND_VLAN
                if ((i < HASH_KEY_LEN) && !(pParams->IsPktFromVLAN || pParams->IsPktFromLoopBack) )
            #else
                if ((i < HASH_KEY_LEN))
            #endif
                {
                    /* Use the KG (BMC Key set through SetChSecurityKeys command) Key */
                    hmac_md5 (pBMCInfo->RMCPPlus[EthIndex].KGHashKey, HASH_KEY_LEN, pBMCInfo->LANConfig.HmacInBuf,
                                            (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen),
                                            pBMCInfo->LANConfig.SIK, SESSION_HMAC_MD5_I_KEY_SIZE);
                }
                else
                {
                    /* Use the KUID (User Password) Key */
                    hmac_md5 (UserPswd, UserPasswdLen, pBMCInfo->LANConfig.HmacInBuf,
                                    (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen),
                                    pBMCInfo->LANConfig.SIK, SESSION_HMAC_MD5_I_KEY_SIZE);
                }
    
                /* Create Key1 & Key2 for Rest of packet Integrity & Encryption */
                _fmemset (TempKey, 1, HASH_KEY1_CONST_SIZE);
                hmac_md5 (pBMCInfo->LANConfig.SIK, SESSION_HMAC_MD5_I_KEY_SIZE, TempKey, HASH_KEY1_CONST_SIZE,
                                pSessInfo->Key1, SESSION_HMAC_MD5_I_KEY_SIZE);
                _fmemset (TempKey2, 2, HASH_KEY2_CONST_SIZE);
                hmac_md5 (pBMCInfo->LANConfig.SIK, SESSION_HMAC_MD5_I_KEY_SIZE, TempKey2, HASH_KEY2_CONST_SIZE,
                                pSessInfo->Key2, SESSION_HMAC_MD5_I_KEY_SIZE);

                /* Construct HMAC to send the Integrity check value using SIK got from prev hmac*/
                pMsg4hmac = (_FAR_ RAKPMsg4hmac_T*) &pBMCInfo->LANConfig.HmacInBuf;
                _fmemcpy (pMsg4hmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
                pMsg4hmac->MgdSysSessionID = pSessInfo->SessionID;
                /*Get System GUID */
                _fmemcpy (pMsg4hmac->MgdSysGUID, BMC_GET_SHARED_MEM (BMCInst)->SystemGUID, 16);
                hmac_md5 (pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, pBMCInfo->LANConfig.HmacInBuf, sizeof (RAKPMsg4hmac_T),
                &pRes [sizeof (RAKPMsg4Res_T)], SESSION_HMAC_MD5_I_KEY_SIZE);
                ResIntigrityKeyLen = HMAC_MD5_LEN;
            }
            break;

        
 
#if 0   //algorithm not specified in IPMI spec, to be removed after review         
        case AUTH_MD5_128:
            {
                // Encryption key must not be used for packets from VLAN or Loopback.
            #ifdef  LAN_RESTRICTIONS_BYPASS_FOR_LOOPBACK_AND_VLAN
                if ((i < HASH_KEY_LEN) && !(pParams->IsPktFromVLAN || pParams->IsPktFromLoopBack) )
            #else
                if ((i < HASH_KEY_LEN))
            #endif
                {
                    /* Use the KG (BMC Key set through SetChSecurityKeys command) Key */
                    MD5_128 ((char *)pBMCInfo->RMCPPlus[EthIndex].KGHashKey, HASH_KEY_LEN, (char *)pBMCInfo->LANConfig.HmacInBuf,
                                (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen),
                                (char *)pBMCInfo->LANConfig.SIK, SESSION_MD5_KEY_SIZE);
                }
                else
                {
                    /* Use the KUID (User Password) Key */
                    MD5_128 ((char *)pUserInfo->UserPassword, UserPasswdLen, (char *)pBMCInfo->LANConfig.HmacInBuf,
                                (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen), (char *)pBMCInfo->LANConfig.SIK, SESSION_MD5_KEY_SIZE);
                }

                /* Create Key1 & Key2 for Rest of packet Integrity & Encryption */
                _fmemset (TempKey, 1, HASH_KEY1_CONST_SIZE);
                MD5_128 ((char *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, (char *)TempKey, HASH_KEY1_CONST_SIZE,
                                (char *)pSessInfo->Key1, SESSION_MD5_KEY_SIZE);
                _fmemset (TempKey2, 2, HASH_KEY2_CONST_SIZE);
                MD5_128 ((char *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, (char *)TempKey2, HASH_KEY2_CONST_SIZE,
                                (char *)pSessInfo->Key2, SESSION_MD5_KEY_SIZE);

                /* Construct HMAC to send the Integrity check value using SIK got from prev hmac*/
                pMsg4hmac = (_FAR_ RAKPMsg4hmac_T*) &pBMCInfo->LANConfig.HmacInBuf;
                _fmemcpy (pMsg4hmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
                pMsg4hmac->MgdSysSessionID = pSessInfo->SessionID;

                /*Get System GUID */
                _fmemcpy (pMsg4hmac->MgdSysGUID, BMC_GET_SHARED_MEM (BMCInst)->SystemGUID, 16);
                MD5_128 ((char *)pBMCInfo->LANConfig.SIK, SESSION_INTEGRITY_KEY_SIZE, (char *)pBMCInfo->LANConfig.HmacInBuf, sizeof (RAKPMsg4hmac_T),
                                (char *)&pRes [sizeof (RAKPMsg4Res_T)], SESSION_MD5_KEY_SIZE);
                ResIntigrityKeyLen = MD5_LEN;
                break;
            }
#endif           
            
	case RAKP_HMAC_SHA256:
	{
		// Encryption key must not be used for packets from VLAN or Loopback.
		#ifdef	LAN_RESTRICTIONS_BYPASS_FOR_LOOPBACK_AND_VLAN
			if ((i < HASH_KEY_LEN) && !(pParams->IsPktFromVLAN || pParams->IsPktFromLoopBack) )
		#else
			if ((i < HASH_KEY_LEN))
		#endif
			{
				/* Use the KG (BMC Key set through SetChSecurityKeys command) Key */
				hmac_sha256((unsigned char *)pBMCInfo->RMCPPlus[EthIndex].KGHashKey, HASH_KEY_LEN, (unsigned char *)pBMCInfo->LANConfig.HmacInBuf,
					   (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen),
				 (unsigned char *)m_SIK, SHA2_HASH_KEY_SIZE);
			}
			else
			{
				/* Use the KUID (User Password) Key */
				hmac_sha256 ((unsigned char *)UserPswd, UserPasswdLen, (unsigned char *)pBMCInfo->LANConfig.HmacInBuf,
			   (sizeof (SIKhmac_T) - 16 + pSIKhmac->UsrNameLen), (unsigned char *)m_SIK, SHA2_HASH_KEY_SIZE);
					
			}

		/* Create Key1 & Key2 for Rest of packet Integrity & Encryption */
				_fmemset (TempKey, 1, HASH_KEY1_CONST_SIZE);
				hmac_sha256 (m_SIK, SHA2_HASH_KEY_SIZE, TempKey, HASH_KEY1_CONST_SIZE,
 			      pSessInfo->Key1, SHA2_HASH_KEY_SIZE);
				_fmemset (TempKey2, 2, HASH_KEY2_CONST_SIZE);
				  hmac_sha256 (m_SIK, SHA2_HASH_KEY_SIZE, TempKey2, HASH_KEY2_CONST_SIZE,
 			     pSessInfo->Key2, SHA2_HASH_KEY_SIZE);
       /* Construct HMAC to send the Integrity check value using SIK got from prev hmac*/
			 pMsg4hmac = (_FAR_ RAKPMsg4hmac_T*) &pBMCInfo->LANConfig.HmacInBuf;
			 _fmemcpy (pMsg4hmac->RemConRandNo, pSessInfo->RemConRandomNo, 16);
			pMsg4hmac->MgdSysSessionID = pSessInfo->SessionID;
			 /*Get System GUID */
			 _fmemcpy (pMsg4hmac->MgdSysGUID, BMC_GET_SHARED_MEM (BMCInst)->SystemGUID, 16);
			 hmac_sha256 (m_SIK, SHA2_HASH_KEY_SIZE, pBMCInfo->LANConfig.HmacInBuf, sizeof (RAKPMsg4hmac_T),
				&pRes [sizeof (RAKPMsg4Res_T)], HASH_KEY1_CONST_SIZE); 
			 ResIntigrityKeyLen = HMAC_SHA256_128_LEN;
	 
			break;
	}
        default:
            IPMI_DBG_PRINT("\nRMCP+.c : Invalid Integrity Algorithm \n");
    }

    /* Get information abt this channel */
    pChannelInfo = getChannelInfo (Channel, BMCInst);
    if (NULL == pChannelInfo)
    {
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
        IPMI_WARNING ("RMCP+.c : RAKPMsg3 - Invalid Integrity check\n");
        Res->StatusCode = SC_INV_INTEGRITY_CHECK;
        return sizeof (RAKPMsg4Res_T);
    }

    pUserInfo = getUserIdInfo((INT8U)pSessInfo->UserId, BMCInst);

	// check the session activated or not, or it will add repeatedly. And finally it will happen "No session slot available."
	if((!pSessInfo->IsLoopBack) && (pSessInfo->Activated!=TRUE))
    {
        /* Update active sessions for current user */
        pUserInfo->CurrentSession++;

        /* Number of active session */
        pChannelInfo->ActiveSession++;
    }

    /* Get userInfo for the given Used Id & Channel */
    pChUserInfo = getChUserIdInfo (pSessInfo->UserId, &Index, pChannelInfo->ChannelUserInfo, BMCInst);

#ifdef  LAN_RESTRICTIONS_BYPASS_FOR_LOOPBACK_AND_VLAN
    if( pParams->IsPktFromVLAN || pParams->IsPktFromLoopBack )
    {
        /* If the packet is from VLAN or LoopBack, then channel privilege should not be
                    considered for session privilege calculation */
        pSessInfo->Privilege = 0x4; //set to admin for loopback and VLAN always
        //UTIL_MIN (pSessInfo->Privilege, pChUserInfo->AccessLimit);
    }
    else
    {
        /* if requested privilege is greater than privilege level for channel or user
                set the minimum of Channel or user privilege*/
        pSessInfo->Privilege =
        UTIL_MIN (pSessInfo->Privilege, UTIL_MIN (pChannelInfo->MaxPrivilege, pChUserInfo->AccessLimit));
    }
#else
    /* if requested privilege is greater than privilege level for channel or user
            set the minimum of Channel or user privilege*/
    pSessInfo->Privilege =
    UTIL_MIN (pSessInfo->Privilege, UTIL_MIN (pChannelInfo->MaxPrivilege, pChUserInfo->AccessLimit));
#endif

    pSessInfo->AuthType     = RMCP_PLUS_FORMAT;
    pSessInfo->Activated    = TRUE;
    /* Set the Max Privilege allowed for the Session*/
    pSessInfo->MaxPrivilege = pSessInfo->Privilege;
    BMC_GET_SHARED_MEM (BMCInst)->SessionHandle += 1;
    pSessInfo->SessionHandle = BMC_GET_SHARED_MEM (BMCInst)->SessionHandle;

    /*Load Response */
    Res->StatusCode      = SC_NO_ERROR;
    Res->RemConSessionID = pSessInfo->RemConSessionID;
    pSessInfo->EventFlag = 1;
    pBMCInfo->LANConfig.DeleteThisLANSessionID = 0;
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChUserMutex);
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SessionTblMutex);
    return (sizeof (RAKPMsg4Res_T) + ResIntigrityKeyLen);
}


#endif /*#if IPMI20_SUPPORT == 1*/
