
#include "bmc_type.h"
#include "bmc_main.h"
#include "bmc_conf.h"
#include "hook.h"
#include "App.h"
#include "Chassis.h"
#include "Bridge.h"
#include "SensorEvent.h"
#include "Storage.h"
//#include "Transport.h"
//#include "AMI.h"
#include "Oem.h"
#include "IPMIDefs.h"
#include "DeviceConfig.h"
#include "bmc_main.h"
#include "IPMI_App.h"
#include "IPMI_Chassis.h"
#include "IPMI_Bridge.h"
#include "IPMI_SensorEvent.h"
#include "IPMI_Storage.h"
#include "IPMI_Oem.h"
#include "cmdselect.h"
#include "Support.h"
#include "session.h"

void BMCInfo_InitChConfig()
{
//	int i=0;
//	BMCInfo_t* pBMCInfo = &g_BMCInfo;
//	ChcfgInfo_T gChConfig;
//	UserInfo_T  UserInfo;
//	SessionTblInfo_T SessionTblInfo;
//	char admin[16]={0x61,0x64,0x6d,0x69,0x6e};//data is "admin" 
//	//ChannelInfo_T gChannelInfo;
//	//memset(&gChConfig,0,sizeof(ChcfgInfo_T));
//	pBMCInfo->SDRConfig.ReservationID=0x08;
//	gChConfig.ChannelInfo.ChannelNumber=1;
//	gChConfig.ChannelInfo.SessionLimit=0x04;
//	gChConfig.ChannelInfo.ActiveSession=0x01;
//	gChConfig.ChannelInfo.ChannelUserInfo[0].UserId=0x01;
//	gChConfig.ChannelInfo.ChannelUserInfo[0].AccessLimit=0x04;
//	pBMCInfo->IpmiConfig.MaxUsers=0x7;
//	pBMCInfo->IpmiConfig.MaxChUsers=0x7;
//	pBMCInfo->IpmiConfig.MaxSession=0x7;
//	UserInfo.UserId=0x01;
//	UserInfo.UserStatus=TRUE;
//	SessionTblInfo.SessionTbl[0].Activated=TRUE;
//	SessionTblInfo.SessionTbl[0].SessionID=0x0;
//	memcpy(UserInfo.UserName,admin,16);
//	for(i=0;i<MAX_PRIVILEGE_TYPES;i++)
//		gChConfig.ChannelInfo.AuthType[i]=0x36;
//	memcpy(&(pBMCInfo->UserInfo),&UserInfo,sizeof(UserInfo_T));
////	memcpy(gChConfig.ChannelInfo.ChannelUserInfo[0].)
//	memcpy(&(pBMCInfo->ChConfig),&gChConfig,sizeof(ChcfgInfo_T));


}



MsgHndlrTbl_T m_MsgHndlrTbl [15] =	//notice!
{
	{ NETFN_APP,                    g_App_CmdHndlr                  },
	{ NETFN_CHASSIS,                g_Chassis_CmdHndlr              },
	{ NETFN_BRIDGE,                 g_Bridge_CmdHndlr               },
	{ NETFN_SENSOR,                 g_SensorEvent_CmdHndlr          },
	{ NETFN_STORAGE,                g_Storage_CmdHndlr              },
	{ NETFN_TRANSPORT,              g_Config_CmdHndlr               },
//	{ NETFN_AMI,                    (CmdHndlrMap_T*)g_AMI_CmdHndlr  },
	{ NETFN_OEM,      		g_Oem_CmdHndlr			},
};

void	ProcessIPMIReq (MsgPkt_T* pReq, MsgPkt_T* pRes);
int	GetCmdHndlr(MsgPkt_T* pReq,MsgPkt_T* pRes,CmdHndlrMap_T* pCmdHndlrMap,INT32U HdrOffset,CmdHndlrMap_T** CmdHndrl );
int	CheckPrivilege (INT8U ReqPrivilege, INT8U CmdPrivilege);
int 	GetMsgHndlrMap (INT8U NetFn, CmdHndlrMap_T ** pCmdHndlrMap);




/**
*@fn MsgHndlr
*@brief Message Handler Task
*       Starting Main function of MsgHndlr task
*/
void *MsgHndlr (void *pArg)
{
	MsgPkt_T	Req;
	MsgPkt_T	Res;
	int i=0;
	while (1)
	{
		if (0 != GetMsg (&Req,MSG_HNDLR_Q,WAIT_INFINITE))
		{
			printf ("Error fetching messages from hMsgHndlr_Q\n");
			continue;
		}
		switch (Req.Param)
		{
			case PARAM_IFC  :
				Res.Param = NO_RESPONSE;
				Res.Size  = 0;
				Req.Channel &= 0x0f; /* Only 4 bits are used */
				Res.Param = NORMAL_RESPONSE;
				ProcessIPMIReq (&Req, &Res);
              		 if (0 != PostMsg(&Res,OBSM_TASK_Q))
                	   {
                        	printf ("Error fetching messages from hMsgHndlr_Q\n");
                        	continue;
                	   }



				break;

			default :
				printf("Invalid request\n");
				break;
		}

		
		// /* Check if there is a request from the command handlers */
		// if (0 != pBMCInfo->Msghndlr.WarmReset)
		// {
			// Platform_WarmReset ();
			// pBMCInfo->Msghndlr.WarmReset = 0;
		// }
		// if (0 != pBMCInfo->Msghndlr.ColdReset) { pBMCInfo->Msghndlr.ColdReset = 0; Platform_ColdReset (); }
		// if (0 != pBMCInfo->Msghndlr.BBlk)	  {	pBMCInfo->Msghndlr.BBlk = 0;	Platform_ColdReset (); }

		//printf("==== chassis control ====\n");
		// switch (pBMCInfo->Msghndlr.ChassisControl)
		// {
			// case CHASSIS_POWER_DOWN : Platform_HostPowerOff ();	    break;
			// case CHASSIS_POWER_UP	: Platform_HostPowerOn ();		break;
			// case CHASSIS_POWER_CYCLE: Platform_HostPowerCycle ();	break;
			// case CHASSIS_HARD_RESET : Platform_HostColdReset ();	break;
			// default : break;
		// }
		
		// pBMCInfo->Msghndlr.ChassisControl = 0xFF;

		// if (pBMCInfo->Msghndlr.ChassisIdentify == TRUE)
		// {
			// Platform_Identify (pBMCInfo->Msghndlr.ChassisIdentifyTimeout, pBMCInfo->Msghndlr.ChassisIdentifyForce,BMCInst);
			// pBMCInfo->Msghndlr.ChassisIdentify = FALSE;
		// }
	}
}
	
/**
*@fn ProcessIPMIReq
*@brief Processes the requested IPMI command
*@param pReq Request of the command
*@param pRes Response for the requested command
*@return none
*/
void
ProcessIPMIReq (_NEAR_ MsgPkt_T* pReq, _NEAR_ MsgPkt_T* pRes)
{
	CmdHndlrMap_T *    pCmdHndlrMap;
	INT32U             HdrOffset = 0;
	INT8U	       	   ResLen;
	INT8U              PBTbl = PRIMARY_PB_TBL;
//	INT8U			IfcSupport =0,kcsifcnum;
//	INT8S		 MsgHndlrMapGot=0;
	BMCInfo_t* pBMCInfo = &g_BMCInfo;
//	INT8U    Index;
//	ChannelInfo_T*        pChannelInfo=NULL;
//	ChannelUserInfo_T*    pChUserInfo=NULL;
//	SessionInfo_T*        pSessInfo=NULL;
	int i = 0;
//	int cnt = 0;
//	bool blCmdAllowed = FALSE;
	/* Set the Cmd and Net function in response packet */
	pRes->Cmd		= pReq->Cmd;
	pRes->NetFnLUN	= pReq->NetFnLUN;
	/* Normal IPMI Command response */
	pRes->Param = NORMAL_RESPONSE;

//	printf ("Processing IPMI Packet.\n");
	

	HdrOffset = sizeof (IPMIMsgHdr_T);
	pReq->Size  = pReq->Size - HdrOffset - 1;	//remove header and checksum2

	pRes->Size  = HdrOffset + sizeof (INT8U);	//header and compeletion code
	
//	printf ("Processing PreProcessIPMI Cmd.\n");
	if(IsCommandEnabled(NET_FN(pReq->NetFnLUN), pReq->Cmd) != 0)
	{
		pRes->Data [HdrOffset] = CC_INV_CMD;
		printf ("Invalid Net Function 0x%x or Invalid Command 0x%x\n",NET_FN(pReq->NetFnLUN), pReq->Cmd);
		return;
	}
	
	if(0 != GetMsgHndlrMap (NET_FN (pReq->NetFnLUN), &pCmdHndlrMap))
	{
		pRes->Data [HdrOffset] = CC_INV_CMD;
		printf("MsgHndlr.c : Invalid Net Function 0x%x\n",NET_FN(pReq->NetFnLUN));
		return;
	}
	if(GetCmdHndlr(pReq,pRes,pCmdHndlrMap,HdrOffset,&pCmdHndlrMap) == FALSE)
	{
		pRes->Data [HdrOffset] = CC_INV_CMD;
		printf("MsgHndlr.c : Invalid Command 0x%x\n", pReq->Cmd);
		return;
	}
//	printf("pCmdHndlrMap->ReqLen is %d,pReq->Size is %d\n",pCmdHndlrMap->ReqLen,pReq->Size);
	/* Check for the request size */
	if (0xff != pCmdHndlrMap->ReqLen)
	{
		/* Check for invalid request size */
		if (pCmdHndlrMap->ReqLen != pReq->Size)
		{
			//IPMI_DBG_PRINT_BUF (pReq->Data, pReq->Size);
			pRes->Data [HdrOffset] = CC_REQ_INV_LEN;
			return;
		}
	}


	/* Check for the privilege */
	if (0 != CheckPrivilege (pReq->Privilege, pCmdHndlrMap->Privilege))
	{
		pRes->Data [HdrOffset] 	= CC_INSUFFIENT_PRIVILEGE;
		printf ("MsgHndlr.c : Insufficent privilage\n");
		return;
	}

	/* Invoke the command handler */
//	printf("pReq->Data [HdrOffset] is %d,HdrOffset is %d\n",pReq->Data [HdrOffset],HdrOffset);
	pRes->Size =
	pCmdHndlrMap->CmdHndlr (&pReq->Data [HdrOffset], pReq->Size, &pRes->Data [HdrOffset]) + HdrOffset;
//	printf("ipmi data size is %d data is : \n",pRes->Size);
//	for(i=0;i<pRes->Size;i++)
//		printf("%#x  ",pRes->Data [HdrOffset+i]);
//	printf("\n");
//	printf ("MsgHndlr.c : Processed command\n");
	if( (CMD_SEND_MSG == pReq->Cmd) && (NETFN_APP == pReq->NetFnLUN >> 2))
	{
		int Offset = 0;
		INT8U SeqNum = pBMCInfo->SendMsgSeqNum;
		//printf("---> CMD_SEND_MSG ");
		if ((0 == pRes->Size) &&
			((pBMCInfo->IpmiConfig.PrimaryIPMBSupport == 0x01  && PRIMARY_IPMB_CHANNEL == pRes->Channel) || 
			 (pBMCInfo->IpmiConfig.SecondaryIPMBSupport == 0x01 && pBMCInfo->SecondaryIPMBCh == pRes->Channel)) )
		{
//			printf(" no response\n");
			pRes->Param = NO_RESPONSE;
			Offset = HdrOffset + 2;
		}
		else if (HdrOffset == pRes->Size)
		{
//			printf(" response\n");
			Offset = HdrOffset + 1;
		}
		
		PBTbl = ( ((pReq->Data[sizeof (IPMIMsgHdr_T)] & 0x0F) == pBMCInfo->SecondaryIPMBCh) ? SECONDARY_PB_TBL : PRIMARY_PB_TBL );
		
	   
		while(TRUE)
		{ 
//			if ( (TRUE == m_PendingBridgedResTbl[PBTbl][SeqNum].Used) &&
//				(0 == _fmemcmp (&m_PendingBridgedResTbl[PBTbl][SeqNum].ReqMsgHdr, &pReq->Data[Offset], sizeof (IPMIMsgHdr_T))) )
			{
//				 _fmemcpy (&m_PendingBridgedResTbl[PBTbl][SeqNum].ResMsgHdr, pRes->Data, sizeof (IPMIMsgHdr_T));
				 break;    
			}
//			else
			{
				SeqNum = (SeqNum - 1) & 0x3F;
				if(SeqNum == pBMCInfo->SendMsgSeqNum)
				{
					break; 
				}
			}
		}
	}

	return;
}	

/**
*@fn GetCmdHndlr
*@brief Picks up the exact command to execute by comparing Cmd no.
*@param pReq Request buffer for the command
*@param pRes Response buffer for the command
*@param pCmdHndlrMap
*@param HdrOffset
*@param CmdOverride
*@param CmdHndlr
*@return Returns TRUE on success
*            Returns FALSE on failure
*/
int GetCmdHndlr(MsgPkt_T* pReq,MsgPkt_T* pRes,CmdHndlrMap_T* pCmdHndlrMap,INT32U HdrOffset,CmdHndlrMap_T** CmdHndrl )
{
	while (1)
	{
		/**
		* If we reached the end of the Command Handler map - invalid command
		**/
//		printf("pCmdHndlrMap->Cmd is %d\n",pCmdHndlrMap->Cmd);
		if (0 == pCmdHndlrMap->CmdHndlr)
		{
			pRes->Data [HdrOffset] = CC_INV_CMD;
			printf( "MsgHndlr.c : Invalid Command %d\n", pReq->Cmd );
			return FALSE;
		}

		if (pCmdHndlrMap->Cmd == pReq->Cmd)
		{
			/* Check if command has been implemented */
			if (UNIMPLEMENTED == pCmdHndlrMap->CmdHndlr)
			{
				pRes->Data [HdrOffset] = CC_INV_CMD;
				printf("MsgHndlr.c : Command is not implemented\n");
				return FALSE;
			}
			else
			{
				break;
			}
		}
		pCmdHndlrMap++;
	}
	*CmdHndrl = pCmdHndlrMap;
	return TRUE;
}

/**
*@fn CheckPrivilege
*@brief Checks the privilege of the requested command
*@param ReqPrivilege Privilege of the requested command
*@param CmdPrivilege Privilege of the requested command in CmdHndlr map
*@return Returns 0 on success
*            Returns -1 on success
*/
int
CheckPrivilege (INT8U ReqPrivilege, INT8U CmdPrivilege)
{
	if (ReqPrivilege >= CmdPrivilege) { return 0; }
		return -1;
}

/**
*@fn GetMsgHndlrMap
*@brief Gets the exact command Handler by comparing NetFn
*@param Netfn -NetFunction of the Cmd to execute
*@param pCmdHndlrMap Pointer to the Command Handler
*@return Returns 0 on success
*            Returns -1 on failure
*/
int
GetMsgHndlrMap (INT8U NetFn, CmdHndlrMap_T ** pCmdHndlrMap)
{
	int i;
	BMCInfo_t* pBMCInfo = &g_BMCInfo;
	/* Get the command handler corresponding to the net function */
	for (i = 0; i <  pBMCInfo->MsgHndlrTblSize ; i++)
	{
		if (pBMCInfo->MsgHndlrTbl [i].NetFn == NetFn) { break; }
	}

	/* Check if we have not found our net function */
	if (i ==  pBMCInfo->MsgHndlrTblSize )
	{
		return -1;
	}

	/* Get the handler corresponding to the command */
	*pCmdHndlrMap = (CmdHndlrMap_T*)pBMCInfo->MsgHndlrTbl [i].CmdHndlrMap;
	return 0;
}
