/*****************************************************************
 *****************************************************************
 **                                                             **
 **     (C)Copyright 2005-2006, American Megatrends Inc.        **
 **                                                             **
 **             All Rights Reserved.                            **
 **                                                             **
 **         6145-F, Northbelt Parkway, Norcross,                **
 **                                                             **
 **         Georgia - 30071, USA. Phone-(770)-246-8600.         **
 **                                                             **
 *****************************************************************
 *****************************************************************
 ******************************************************************
 ******************************************************************
 *
 * AMIDevice.c
 *
 * Author: Basavaraj Astekar <basavaraja@ami.com>
 *
 ******************************************************************/
#define ENABLE_DEBUG_MACROS     0

#include <stdio.h>
#include <unistd.h>
#include <linux/kernel.h>
#include <sys/sysinfo.h>
#include <dlfcn.h>
#include <openssl/pem.h>

#include "Types.h"
//#include "OSPort.h"
#include "Support.h"
#include "IPMIDefs.h"
#include "IPMI_AppDevice.h"
#include "IPMI_AMIDevice.h"
#include "IPMI_AMI.h"
#include "AMIDevice.h"
#include "SharedMem.h"
#include "dbgout.h"
#include "ipmi_userifc.h"
//#include "sshutil.h"
#include "Platform.h"
#include "Indicators.h"
#include "Debug.h"
#include "flashlib.h"
#include "NVRAccess.h"
#include "MsgHndlr.h"
#include "PMConfig.h"
#include "YafuStatus.h"
#include "Sensor.h"
#include <unistd.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
#include "PDKCmds.h"
//#include "IPMIConf.h"
#include "PDKAccess.h"
#include "Ethaddr.h"
#include "PDKCmdsAccess.h"
#include "flshfiles.h"
#include "PendTask.h"
//#include "IPMI_AMIConf.h"
#include "featuredef.h"
#include<sys/prctl.h>
#include "ubenv.h"
#include "fwinfo.h"
#include "blowfish.h"
#include "ldapconf.h"
#include "activedir_cfg.h"
#include "ubenv.h"
#include "safesystem.h"
#include "usb_ioctl.h"
#include "vmedia_instance.h"
#include "ncml.h"

#include <sys/stat.h>
#include <string.h>
#include "IPMI_AMILicense.h"
#include "WS_base32.h"

#include "bmc_type.h"
//static  _FAR_ SensorSharedMem_T*    pSenSharedMem; 

/* For BIOS flashing
 * see firmware/apps/gpio_utilities
 * included by way of libami/flashlib
 */
extern int assert_host_reset();
extern int write_one_bios_block( int blocknum, unsigned char *data );
extern int read_one_bios_block( int blocknum, unsigned char *data );
extern int deassert_host_reset();
extern unsigned long CalculateChksum (char *data, unsigned long size);
void*  EraseCopyFlash	  (void*);
void*  VerifyFlashStatus	  (void*);
void* YAFUTimerTask(void *pArg);
int YAFUTimerAction();
static int CheckForBootOption(char bootoption);
static bool IsfwuploadSelectorValid(char uploadselector);

/* For Firmware update
 */
#define INVALID_IP_ADDR "0.0.0.0"
#define NO_ADDRESS 0xFFFFFFFF
#define FLASH_TIMEOUT_IN_SECONDS 1200
#define SET_FIRM_REQ_BYTES 200

/* U-Boot Memory Test */
#define UBOOT_MEMTEST_ENABLE_VAR    "do_memtest"
#define UBOOT_MEMTEST_STATUS_VAR    "memtest_pass"
#define MEMTEST_PASS    "yes"
#define MEMTEST_FAIL    "no"
#define MEMTEST_ENABLE  "1"

FlashTimerInfo_T	g_FlashTimerInfo;

#define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
#define MEMERASE                _IOW('M', 2, struct erase_info_user)
#define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)

#define MAX_CMDLINE	50
#define MAX_MODULE			16

/* YafuTimer Related definitions*/
#define UBOOT_MAX_SIZE	65536
/* Timer timeouts for diff interfaces and flasing types(Interactive and ForceFlash)*/
#define YAFU_LAN_IA_TIMER_COUNT	600
#define YAFU_LAN_FF_TIMER_COUNT	600
#define YAFU_USB_IA_TIMER_COUNT	180
#define YAFU_USB_FF_TIMER_COUNT	720
#define YAFU_KCS_IA_TIMER_COUNT	3600
#define YAFU_KCS_FF_TIMER_COUNT	3600

#define YAFU_MSECS_PER_TICK		1000
#define YAFU_FLASH_SUCCEEDED	1
#define YAFU_FLASH_CHUNK	1024

/* Yafu Flashing Types Interactive/Generic*/
#define YAFU_INTERACTIVE_FLASH	1


#ifndef CONFIG_SPX_FEATURE_IPMI_NO_YAFU_SUPPORT

#define DEFAULT_MTD_DEVICE	"/dev/mtd0"
#define SIGNED_HASH_SIZE    128

BOOL  FMHComp;
BOOL ActivateFlashStatus =0x00;
int LastStatCode = 0x00;
int VerifyFlashStatusCode = 0x00;
INT8U *allocmem;
int DualImgPreserveConf=TRUE;
INT8U *WriteMemOff=NULL;
unsigned long Sizetocpy=0;
unsigned long Flashoffset;
unsigned long Fixoffset;
INT8U *VWriteMemOff=NULL;
INT32U ImgSize = 0;
unsigned long Sizetoverify;
unsigned long VFlashoffset;
unsigned long VOffset;
unsigned long VFixoffset;
int gDeviceNode;

/* Yafu Timer relating variables*/
static env_t environment;
unsigned long YafuTimerCnt = 0;
char UBootCfg[UBOOT_MAX_SIZE];
int YafuflashStatus = 0;
int SetBootParam = 0;
extern unsigned long  FlashStart, EnvStart, EnvSize;
int YafuFlashMode=0;

int Vstart=0;
int Vthreadstate=0;

int ECFstart=0;
int ECFthreadstate=0;
pthread_t             threadid, threadid_yafu;
pthread_t             threadidv; /*Verify Flash*/

pthread_mutex_t     YafuThreadMutex;
pthread_cond_t      cond  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t      condv  = PTHREAD_COND_INITIALIZER; /*Verify Flash*/
pthread_mutex_t     mutexv = PTHREAD_MUTEX_INITIALIZER; /*Verify Flash*/


struct erase_info_user {
        uint32_t start;
        uint32_t length;
};


struct mtd_info_user{
    unsigned char type;
    unsigned long flags;
    unsigned long size;
    unsigned long erasesize;
    unsigned long oobblock;
    unsigned long oobsize;
    unsigned long ecctype;
    unsigned long eccsize;
};


/* Initialize the Global structure with default MTD information */
AMIYAFUSwitchFlashDeviceRes_T gAMIYAFUSwitchFlashDevice;

int HookSkips = 0;

#endif

static const INT8U m_DualResBits [] = {2,1,2,1,2,1,1,2};

//extern IfcName_T Ifcnametable[MAX_LAN_CHANNELS];

static const INT8U TriggerEventParamLength[] ={
     1,    /*Length for Critical Flag*/
     1,    /*Length for Non Critical Flag*/
     1,    /*Length for Non Recoverable Flag*/
     1,    /*Length for Fan Troubled Flag*/
     1,    /*Length for WDT Expire Flag*/
     1,    /*Length for System DC On Flag*/
     1,    /*Length for System DC Off Flag*/
     1,    /*Length for System DC Reset Flag*/
     1+4,  /*Length for Specific date time Flag*/
     1,    /*Length for LPC Reset Flag*/
};

/*PAM and NSS defalut order Information*/
PamOrder_T g_DfaultOrder [MODULES_TO_MODIFIED]=
{
    {1, PAM_IPMI},
    {2, PAM_LDAP},
    {3, PAM_AD},
   	{4, PAM_RADIUS}
};

PamOrder_T g_NssOrder [MODULES_TO_MODIFIED] =
{
    {1, "ipmi"},
    {2, "ldap"},
    {3, "ad "},
    {4, "radius"}
};

char  g_FlashingImage;
char  g_RunningImage;
char  g_InactiveImage;
unsigned char g_FWUploadSelector = 0xFF;
static unsigned char g_FWBootSelector = 0xFF;
char g_rebootstatus=TRUE;

#ifndef CONFIG_SPX_FEATURE_IPMI_NO_YAFU_SUPPORT
int InitYafuVar()
{
	gAMIYAFUSwitchFlashDevice.CompletionCode = 0x0;
	strcpy(gAMIYAFUSwitchFlashDevice.MTDName,DEFAULT_MTD_DEVICE);
	gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize = g_coremacros.global_used_flash_size;
	gAMIYAFUSwitchFlashDevice.FlashInfo.FlashAddress = g_coremacros.global_used_flash_start;
	gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize = g_coremacros.global_erase_blk_size;
	gAMIYAFUSwitchFlashDevice.FlashInfo.FlashProductID = 0;
	gAMIYAFUSwitchFlashDevice.FlashInfo.FlashWidth = 8;
	gAMIYAFUSwitchFlashDevice.FlashInfo.FMHCompliance = 1;
	gAMIYAFUSwitchFlashDevice.FlashInfo.Reserved = 0;
	gAMIYAFUSwitchFlashDevice.FlashInfo.NoEraseBlks = 0;

	return 0;
}
#endif

static int Decrypt_LicenseKey(unsigned char *LicenseKey,int size, char *DecrypteLicenseKey);
static int IsDuplicateKey(unsigned char *LicenseKey);

/**
 * FlashTimerTask
 **/
void
FlashTimerTask (int BMCInst)
{
    static int m_InitFlashVars = 0;

    if (0 == m_InitFlashVars)
    {
        m_InitFlashVars 					 = 1;
        g_FlashTimerInfo.TimeOut 			 = 0;
        g_FlashTimerInfo.FlashProcessStarted = 0;
    }

    if (0 == g_FlashTimerInfo.FlashProcessStarted)
    {
        g_FlashTimerInfo.TimeOut 			 = 0;
        return;
    }

    if (0 == g_FlashTimerInfo.TimeOut)
    {
        IPMI_DBG_PRINT ("Flashing Process Timed out \n");
        g_FlashTimerInfo.FlashProcessStarted = 0;
        reboot (LINUX_REBOOT_CMD_RESTART);
    }
    g_FlashTimerInfo.TimeOut--;

}

/**
 ** @fn DefaultSettingsForDualImageSupport
 ** @brief  To set the flashing image as inactive image defaultly.
 ** @param[in] - void.
 ** @retval   Will return 0 on success.
 **
 **/
int DefaultSettingsForDualImageSupport()
{
    DUALIMGINFO_STRUCT info;
    char envval[5] = {0};
    int bootselector;

    if( GetDualImageOptions(&info) == -1)
    {
        TCRIT("Unable to get GetDualImageOptions");
        return -1;
    }

    /* running and inactive images are remain same till next reboot*/
    g_RunningImage  = info.runningImg;
    g_InactiveImage = info.InactiveImg;

    //default upload image is inactive image
    g_FWUploadSelector = AUTO_INACTIVE_IMAGE;
    g_FlashingImage    = info.InactiveImg;

    if( GetUBootParam("bootselector",envval) == 0 )
    {
        sscanf(envval,"%d",&bootselector);
        //Checking for valid Boot selector option
        if( CheckForBootOption(bootselector) == 0)
        {
            g_FWBootSelector = bootselector;
        }
    }
return 0;
}


/**
 * @fn SetMostRecentlyProgFW
 * @brief Sets the most recently programmed firmware image to env variable recentlyprogfw.
 * @param[in]     - Nill
 * @retval      0 - on success.
 *             -1 - on failure case
 */
int SetMostRecentlyProgFW(void)
{
    char envval[5];

    memset(envval,0,sizeof(envval));

    if(( g_FlashingImage == IMAGE_1) || (g_FlashingImage == IMAGE_BOTH)) {

        sprintf(envval,"%d",IMAGE_1);
    }
    else if( g_FlashingImage == IMAGE_2) {

        sprintf(envval,"%d",IMAGE_2);
    }
    else {

        return -1;
    }

    if( SetUBootParam("recentlyprogfw",envval) != 0 )
    {
        TCRIT("Unable to set env variable updation\n");
        return -1;
    }

return 0;
}

#ifndef CONFIG_SPX_FEATURE_IPMI_NO_YAFU_SUPPORT
int Get_Cuurent_Bios_Img_Info(FlashDetails *biosinfo, char *MTD_Device)
{
    struct mtd_info_user user_info;
    int retval = -1;
    int MTDDev = 0;
    MTDDev = open (MTD_Device, O_RDONLY);
    if (MTDDev < 0)
    {
        TCRIT ("Cannot open mtd raw device %s. Exiting...\n", MTD_Device);
        return retval;
    }
    memset(&user_info, 0x00, sizeof(struct mtd_info_user));
    if (ioctl(MTDDev, MEMGETINFO, &user_info) < 0)
    {
        printf("Unable to get MTD info via IOCTL(MEMGETINFO) ... %s\n", strerror(errno));
        return retval;
    }
    biosinfo->FlashSize= user_info.size;
    biosinfo->FlashAddress =  CONFIG_SPX_BIOS_FLASH_START ;
    biosinfo->FlashEraseBlkSize = user_info.erasesize ;
    retval = 0;
    return retval;
}

int
Switch_Device (int SPIDevice, INT8U *pRes)
{
	AMIYAFUSwitchFlashDeviceRes_T *pAMIYAFUSwitchFlashDevice_Res = (AMIYAFUSwitchFlashDeviceRes_T *)pRes;
	int retval = -1;

	memset((char *)pAMIYAFUSwitchFlashDevice_Res, 0, sizeof(AMIYAFUSwitchFlashDeviceRes_T));

    if(access("/var/yafu_bios_update_selection", F_OK) != 0)
    {
	if ((SPIDevice == 0) || (g_PDKHandle[PDK_SWITCH_SPI] == NULL))
	{
		if (SPIDevice)
		{
			TCRIT("Invalid SPI Device Node. Defaulting to 0\n");
		}
	
		strcpy((char *)&pAMIYAFUSwitchFlashDevice_Res->MTDName[0], (char *)DEFAULT_MTD_DEVICE);
		pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FlashSize = g_coremacros.global_used_flash_size;
		pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FlashAddress = g_coremacros.global_used_flash_start;
		pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FlashEraseBlkSize = g_coremacros.global_erase_blk_size;
 		pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FMHCompliance = 0x01;

		retval = 0;
		goto exit_gracefully;
	}
	else
	{
        	retval = ((int(*)(int, INT8U*))g_PDKHandle[PDK_SWITCH_SPI]) (SPIDevice, pRes);
		if (retval != 0) 
		{
			TCRIT("Unable to identify the SPI Partition from the MTD Mapping\n");
			goto exit_gracefully;
		}

		ActivateFlashStatus = 1;	
		HookSkips = 1;	
	}
    }
    else
    {
        char MTD_Device[128];
        FlashDetails biosinfo;
        ActivateFlashStatus = 0x00;
        StartInitFlashSetting();
        /* find the MTD number for HOST SPI */
        if (FindHostBiosDeviceName(MTD_Device) != 0)
            goto exit_gracefully;
        strcpy((char *)&pAMIYAFUSwitchFlashDevice_Res->MTDName[0], MTD_Device);
        if(Get_Cuurent_Bios_Img_Info(&biosinfo, MTD_Device) < 0)
            goto exit_gracefully;
        pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FlashSize = biosinfo.FlashSize;
        pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FlashAddress = biosinfo.FlashAddress;
        pAMIYAFUSwitchFlashDevice_Res->FlashInfo.FlashEraseBlkSize = biosinfo.FlashEraseBlkSize;
        retval = 0;
    }

exit_gracefully:
	return retval;
} 
	
/*---------------------------------------
 * AMIYAFUSwitchFlashDevice
 *---------------------------------------*/
int AMIYAFUSwitchFlashDevice(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
	AMIYAFUSwitchFlashDeviceReq_T *pAMIYAFUSwitchFlashDevice_Req = (AMIYAFUSwitchFlashDeviceReq_T *)pReq;
	AMIYAFUSwitchFlashDeviceRes_T *pAMIYAFUSwitchFlashDevice_Res = (AMIYAFUSwitchFlashDeviceRes_T *)pRes;
	int SPIDevice = (int)(pAMIYAFUSwitchFlashDevice_Req->SPIDevice);
	int ErrCode = 0;
	
	ErrCode = Switch_Device(SPIDevice, (INT8U *)pAMIYAFUSwitchFlashDevice_Res);
	if (ErrCode != 0)
	{
		TCRIT("Unable to Switch to the appropriate SPI Device\n");
		pAMIYAFUSwitchFlashDevice_Res->CompletionCode = YAFU_CC_READ_ERR;
		return sizeof(INT8U);
	}

	pAMIYAFUSwitchFlashDevice_Res->CompletionCode = CC_NORMAL;

	memcpy((char *)&gAMIYAFUSwitchFlashDevice, (char *)pAMIYAFUSwitchFlashDevice_Res, sizeof(AMIYAFUSwitchFlashDeviceRes_T));
	gDeviceNode = SPIDevice;

	return (sizeof(AMIYAFUSwitchFlashDeviceRes_T));
}

/*---------------------------------------
 * AMIYAFURestoreFlashDevice
 *---------------------------------------*/
int AMIYAFURestoreFlashDevice(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
	int retval = 0;
	AMIYAFUSwitchFlashDeviceRes_T *pAMIYAFUSwitchFlashDevice_Res = (AMIYAFUSwitchFlashDeviceRes_T *)pRes;

	if (g_PDKHandle[PDK_REVERT_SPI] != NULL)
	{
        	retval = ((int(*)(void))g_PDKHandle[PDK_REVERT_SPI]) ();
		if (retval != 0) 
		{
			TCRIT("Unable to clear the flash mapping information\n");
			pAMIYAFUSwitchFlashDevice_Res->CompletionCode = YAFU_CC_READ_ERR;
			return sizeof(INT8U);
		}
	}

	pAMIYAFUSwitchFlashDevice_Res->CompletionCode = CC_NORMAL;

	return (sizeof(AMIYAFUSwitchFlashDeviceRes_T));
}

/*---------------------------------------
 * AMIYAFUNotAcks
 *---------------------------------------*/

int AMIYAFUNotAcks(INT8U *pRes,INT16U ErrorCode,INT32U Seqnum)
{
    AMIYAFUNotAck* pAMIYAFUNotAcknowledge =(AMIYAFUNotAck*)pRes;
    pAMIYAFUNotAcknowledge->CompletionCode = YAFU_ERR_STATE;
    pAMIYAFUNotAcknowledge->NotAck.Seqnum = Seqnum;
    pAMIYAFUNotAcknowledge->NotAck.YafuCmd = CMD_AMI_YAFU_COMMON_NAK;
    pAMIYAFUNotAcknowledge->NotAck.Datalen = 0x02;
    pAMIYAFUNotAcknowledge->NotAck.CRC32chksum = 0x00;
    pAMIYAFUNotAcknowledge->ErrorCode = ErrorCode;
    return (sizeof(AMIYAFUNotAck));
}

/*---------------------------------------
 * AMIYAFUGetFlashInfo
 *---------------------------------------*/
int AMIYAFUGetFlashInfo ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
       AMIYAFUGetFlashInfoReq_T *pAMIYAFUFlashInfoReq = (AMIYAFUGetFlashInfoReq_T *)pReq;
       AMIYAFUGetFlashInfoRes_T* pAMIYAFUGetFlashInfo = (AMIYAFUGetFlashInfoRes_T*)pRes;

	pAMIYAFUGetFlashInfo->CompletionCode = YAFU_CC_NORMAL;
       pAMIYAFUGetFlashInfo->FlashInfoRes.Seqnum = pAMIYAFUFlashInfoReq->FlashInfoReq.Seqnum;
	pAMIYAFUGetFlashInfo->FlashInfoRes.YafuCmd= pAMIYAFUFlashInfoReq->FlashInfoReq.YafuCmd;

	pAMIYAFUGetFlashInfo->FlashInfo.FlashSize = gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize;
	pAMIYAFUGetFlashInfo->FlashInfo.FlashAddress = gAMIYAFUSwitchFlashDevice.FlashInfo.FlashAddress;
	pAMIYAFUGetFlashInfo->FlashInfo.FlashEraseBlkSize = gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize;
	pAMIYAFUGetFlashInfo->FlashInfo.FlashProductID = 0;
	pAMIYAFUGetFlashInfo->FlashInfo.FlashWidth = 8;
	pAMIYAFUGetFlashInfo->FlashInfo.FMHCompliance = gAMIYAFUSwitchFlashDevice.FlashInfo.FMHCompliance;

       if(pAMIYAFUGetFlashInfo->FlashInfo.FMHCompliance == 0x01)
	   	FMHComp = 1;

      	pAMIYAFUGetFlashInfo->FlashInfo.Reserved = 0;
	pAMIYAFUGetFlashInfo->FlashInfo.NoEraseBlks = ((gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize)/(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));

       if((pAMIYAFUGetFlashInfo->FlashInfo.NoEraseBlks * pAMIYAFUGetFlashInfo->FlashInfo.FlashEraseBlkSize) == pAMIYAFUGetFlashInfo->FlashInfo.FlashSize)
             pAMIYAFUGetFlashInfo->FlashInfoRes.Datalen= 0x20;
       else
             pAMIYAFUGetFlashInfo->FlashInfoRes.Datalen = 0x20 + pAMIYAFUGetFlashInfo->FlashInfo.NoEraseBlks;

      pAMIYAFUGetFlashInfo->FlashInfoRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUGetFlashInfo->FlashInfo,sizeof(pAMIYAFUGetFlashInfo->FlashInfo));

       return( sizeof( AMIYAFUGetFlashInfoRes_T ) );

}

/*---------------------------------------
 * AMIYAFUGetFirmwareInfo
 *---------------------------------------*/
#define FW_INFO_FILE "/proc/ractrends/Helper/FwInfo"
static void GetFirmwareVersion(unsigned int* Major,unsigned int* Minor,unsigned int* Rev,unsigned int* ProductID)
{
    char aline[100];
    int AuxVer = 0;  
    int i = 0, count = 0, ret = 0;

    FILE* fp = fopen(FW_INFO_FILE,"rb");
	if(fp == NULL)
	{
		TCRIT("Unable to find firmware version info!!!\n");
		*Major = 0;
		*Minor = 0;
		*Rev = 0;
		return ;
	}


	fgets(aline,93,fp);

    for(i = 0; i < 93; i++) 
    {
        if (aline[i] == '\0')
            break;
        if (aline[i] == '.')
            ++count;
    }

    if(count == 3)
        sscanf(aline,"FW_VERSION=%d.%d.%d.%d",Major,Minor,&AuxVer,Rev);
    else
        sscanf(aline,"FW_VERSION=%d.%d.%d",Major,Minor,Rev);   

    while(fgets(aline,93,fp) != NULL)
    {
        ret = sscanf(aline,"FW_PRODUCTID=%d",ProductID);
        if (ret == 1)
            break;
    } 

	fclose(fp);

return;
}


int AMIYAFUGetFirmwareInfo ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )  //Added by winston for YAFU */
{
       static unsigned int Major,Minor,Rev,ProductID;
//	static unsigned char MinorBCD;

       AMIYAFUGetFirmwareInfoReq_T *pAMIYAFUGetFirmwareInfoReq = (AMIYAFUGetFirmwareInfoReq_T *)pReq;
       AMIYAFUGetFirmwareInfoRes_T* pAMIYAFUGetFirmwareInfo = (AMIYAFUGetFirmwareInfoRes_T*)pRes;
       static int firsttime = 1;

	if(firsttime == 1)
	{
		GetFirmwareVersion(&Major,&Minor,&Rev,&ProductID);
        //	MinorBCD = ((Minor/10)<<4)+(Minor%10);
		firsttime = 0;
	}

      
       pAMIYAFUGetFirmwareInfo->CompletionCode = CC_NORMAL;
	pAMIYAFUGetFirmwareInfo->FirmwareinfoRes.Seqnum = pAMIYAFUGetFirmwareInfoReq->FirmwareinfoReq.Seqnum;
	pAMIYAFUGetFirmwareInfo->FirmwareinfoRes.YafuCmd= pAMIYAFUGetFirmwareInfoReq->FirmwareinfoReq.YafuCmd;
	pAMIYAFUGetFirmwareInfo->FirmwareinfoRes.Datalen= 0x26;
	pAMIYAFUGetFirmwareInfo->FirmwareinfoRes.CRC32chksum = 0x00;
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.FirmMajVersion =  (INT8U)Major;
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.FirmMinVersion = (INT8U)Minor;
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.FirmAuxVersion = Rev;
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.FirmBuildNum = 0;
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.Reserved = 0x00;
	strcpy((char *)pAMIYAFUGetFirmwareInfo->FirmwareInfo.FirmwareName,"Rom.ima");
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.FirmwareSize = gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize;
	pAMIYAFUGetFirmwareInfo->FirmwareInfo.ProductID = (INT32U)ProductID;
       pAMIYAFUGetFirmwareInfo->FirmwareinfoRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUGetFirmwareInfo->FirmwareInfo,sizeof(pAMIYAFUGetFirmwareInfo->FirmwareInfo));

       return( sizeof( AMIYAFUGetFirmwareInfoRes_T ) );
}


/*---------------------------------------
 * AMIYAFUGetFMHInfo
 *---------------------------------------*/
int AMIYAFUGetFMHInfo ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
      int fd = -1;
      DWORD i=0,Offset =0,m=0;
      INT8U *Buf=NULL;
      FlashMH      FlashModHeader;
      ALT_FMHead    AltFmh;
      char *FMHDetails = NULL;
      AMIYAFUGetFMHInfoReq_T *pAMIYAFUGetFMHInfoReq = (AMIYAFUGetFMHInfoReq_T *)pReq;
      AMIYAFUGetFMHInfoRes_T* pAMIYAFUGetFMHInfo = (AMIYAFUGetFMHInfoRes_T*)pRes;
      INT8U TotalFMH = 0,ImgCount = 0,NoOfImg = IMAGE_1;
      INT16U  NoOfFMH = 0;
      int ErrCode = 0, retval = 0;

      pAMIYAFUGetFMHInfo->NumFMH = 0x00;

      FMHDetails = malloc(MAX_FMHLENGTH);
      if(FMHDetails == NULL)
      {
             printf("Error in malloc of FMHDetails");
	      return -1;
      }


    if(g_corefeatures.dual_image_support == ENABLED)
    {
        NoOfImg = IMAGE_2;
    }

	// This hook can be used to perform any OEM routines such as fetching FMH from different location instead of mtd
	// Returning 0 from this hook will revert back to performing default probe and find FMH sequence
	// Returning <non-zero> from this hook will validate the ErrCode from the hook, and return appropriately. Default action will be skipped
	if (g_PDKHandle[PDK_OEMRESTOREFMH] != NULL)
   	{
        	retval = ((int(*)(int, char*, INT8U*, int*, int))g_PDKHandle[PDK_OEMRESTOREFMH]) 
								(gDeviceNode, FMHDetails, &TotalFMH, &ErrCode, BMCInst);

		if (retval != 0)
		{
			if (ErrCode != 0)
			{
				return (AMIYAFUNotAcks(pRes,YAFU_CC_READ_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
			}
			                        		
			goto skip_probe;
		}
   	}

         fd=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDONLY);
	 if(fd == -1)
	 {
	     if (FMHDetails != NULL)
	     {
	         free(FMHDetails);
	     }	 
	     return (AMIYAFUNotAcks(pRes,YAFU_CC_DEV_OPEN_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
	 }

        for(ImgCount = IMAGE_1;ImgCount<=NoOfImg;ImgCount++)
       {
           NoOfFMH = 0;
           if(ImgCount ==IMAGE_2)
           {
                 Offset = GetMacrodefine_getint("CONFIG_SPX_FEATURE_GLOBAL_USED_FLASH_SIZE", 0);
           }

	  if ( lseek (fd, Offset, SEEK_SET) == -1)
	  {
	     fprintf (stderr,
	      "seek error on %s: %s\n",
	       gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
	     if (fd != -1)
	     {
	         close(fd);
	         fd=-1;
	     }
	     if (FMHDetails != NULL)
	     {
	         free(FMHDetails);
	     }
	     
             return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
	   }

   for(i=0;i<((gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize)/(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));i++)
   {
	Buf= (INT8U *)malloc(64);

	if(Buf == NULL)
	      return (AMIYAFUNotAcks(pRes,YAFU_CC_ALLOC_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
       
	if ( lseek (fd, ( Offset + ( i*(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)) ), SEEK_SET) == -1)
	{
		   fprintf (stderr,
			"seek error on %s: %s\n",
			 gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
		   if (fd != -1)
		   {
		       close(fd);
		       fd=-1;
		   }
		   if (Buf != NULL)
		   {
		       free(Buf);
		   }
		   if (FMHDetails != NULL)
		   {
		       free(FMHDetails);
		   }

                  return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
	 }



       if( (read(fd,Buf,64)) != 64 )
       {
          if (fd != -1)
          {
              close(fd);
              fd=-1;
          }
          if (Buf != NULL)
          {
              free(Buf);
          }
          if (FMHDetails != NULL)
          {
              free(FMHDetails);
          }
      	      return (AMIYAFUNotAcks(pRes,YAFU_CC_READ_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
       }


      memcpy((char*)&FlashModHeader,Buf,64);

      if(strncmp((char *)FlashModHeader.FmhSignature,"$MODULE$",(sizeof(FlashModHeader.FmhSignature) -1)) == 0 )	//Check FMH Signature
      {

            if(FlashModHeader.EndSignature != 21930)
	      	  	continue;

	     memcpy((FMHDetails + m),(char *)&FlashModHeader,64);


              printf("Module Name = %s\n",FlashModHeader.ModuleName);

	     m +=64;
	     NoOfFMH += 0x1;

	     free(Buf);

	}
      else
      {

          if ( lseek (fd, ( Offset + (  i*(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)) ) +((gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize) -sizeof(AltFmh)), SEEK_SET) == -1)
	   {
		   fprintf (stderr,
			"seek error on %s: %s\n",
			 gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
                    if (fd != -1)
                    {
                        close(fd);
                        fd=-1;
                    }
                    if (Buf != NULL)
                    {
                        free(Buf);
                    }
                    if (FMHDetails != NULL)
                    {
                        free(FMHDetails);
                    }

                 return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
	    }



         if( (read(fd,Buf,sizeof(AltFmh))) != sizeof(AltFmh) )
	  {
		fprintf (stderr,
			 "Bytes read error %s: %s\n",
			 gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
	          if (fd != -1)
	          {
	              close(fd);
	              fd=-1;
	          }
	          if (Buf != NULL)
	          {
	              free(Buf);
	          }
	          if (FMHDetails != NULL)
	          {
	              free(FMHDetails);
	          }
              return (AMIYAFUNotAcks(pRes,YAFU_CC_READ_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
          }


	      memcpy((char *)&AltFmh,Buf,sizeof(AltFmh));
             if(strncmp((char *)AltFmh.Signature,"$MODULE$",(sizeof(AltFmh.Signature) -1)) == 0 )	//Check FMH Signature
             	{


           		if ( lseek (fd, ( Offset + ( i*(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)) ) +AltFmh.LinkAddress, SEEK_SET) == -1)
	   		{
		   		fprintf (stderr,
					"seek error on %s: %s\n",
			 		gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
		   	          if (fd != -1)
		   	          {
		   	              close(fd);
		   	              fd=-1;
		   	          }
		   	          if (Buf != NULL)
		   	          {
		   	              free(Buf);
		   	          }
		   	          if (FMHDetails != NULL)
		   	          {
		   	              free(FMHDetails);
		   	          }
                           return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
	  		 }



         		if( (read(fd,Buf,64)) != 64 )
	  		{
				fprintf (stderr,
					 "Bytes read error %s: %s\n",
					 gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
			          if (fd != -1)
			          {
			              close(fd);
			              fd=-1;
			          }
			          if (Buf != NULL)
			          {
			              free(Buf);
			          }
			          if (FMHDetails != NULL)
			          {
			              free(FMHDetails);
			          }
                            return (AMIYAFUNotAcks(pRes,YAFU_CC_READ_ERR,pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum));
         		 }


	      		memcpy((char*)&FlashModHeader,Buf,64);

	      		if(strncmp((char *)FlashModHeader.FmhSignature,"$MODULE$",(sizeof(FlashModHeader.FmhSignature) -1)) == 0 )	//Check FMH Signature
            		{

            			if(FlashModHeader.EndSignature != 21930)
	      	  			continue;


                            memcpy((FMHDetails +m),(char *)&FlashModHeader,64);

              		printf("Module Name = %s\n",FlashModHeader.ModuleName);

	     			m +=64;
	     			NoOfFMH += 0x1;


	   		}

             	}
	  free(Buf);
	  Buf=NULL;
      	}
    }

       if(ImgCount == IMAGE_1)
       {
            pAMIYAFUGetFMHInfo->NumFMH = NoOfFMH;
       }
       else if(ImgCount == IMAGE_2)
       {
            pAMIYAFUGetFMHInfo->NumFMH |=  NoOfFMH<<8;
       }
       TotalFMH+= NoOfFMH;
    }

skip_probe:
      if(pAMIYAFUGetFMHInfoReq->FMHReq.Datalen == 0x00)
      {
            pAMIYAFUGetFMHInfo->FMHRes.Datalen= 0x04 + (TotalFMH* 64);
      }
	else
	{
		pAMIYAFUGetFMHInfo->CompletionCode = CC_INV_DATA_FIELD;
		if (fd != -1)
                {
                    close(fd);
                    fd=-1;
                }
                if (Buf != NULL)
                {
                    free(Buf);
                }
                if (FMHDetails != NULL)
                {
                    free(FMHDetails);
                }
		return sizeof (*pRes);
	}

      memcpy (( INT8U*) (pAMIYAFUGetFMHInfo + 1),( INT8U*)FMHDetails,(TotalFMH * 64) );

      pAMIYAFUGetFMHInfo->CompletionCode = YAFU_CC_NORMAL;
      pAMIYAFUGetFMHInfo->FMHRes.Seqnum = pAMIYAFUGetFMHInfoReq->FMHReq.Seqnum;
      pAMIYAFUGetFMHInfo->FMHRes.YafuCmd= pAMIYAFUGetFMHInfoReq->FMHReq.YafuCmd;
      pAMIYAFUGetFMHInfo->Reserved = 0x00;
      pAMIYAFUGetFMHInfo->FMHRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUGetFMHInfo->Reserved,pAMIYAFUGetFMHInfo->FMHRes.Datalen);

      if (FMHDetails != NULL)
      	free (FMHDetails);
      return( sizeof( AMIYAFUGetFMHInfoRes_T ) + (TotalFMH * 64));
}


/*---------------------------------------
 * AMIYAFUGetStatus
 *---------------------------------------*/
int AMIYAFUGetStatus  ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
    AMIYAFUGetStatusReq_T *pAMIYAFUGetStatusReq =(AMIYAFUGetStatusReq_T *)pReq;
    AMIYAFUGetStatusRes_T* pAMIYAFUGetStatus = (AMIYAFUGetStatusRes_T*)pRes;


    pAMIYAFUGetStatus->GetStatusRes.Seqnum = pAMIYAFUGetStatusReq->GetStatusReq.Seqnum;
    pAMIYAFUGetStatus->GetStatusRes.YafuCmd= pAMIYAFUGetStatusReq->GetStatusReq.YafuCmd;
    pAMIYAFUGetStatus->LastStatusCode =(INT16U) LastStatCode;
    pAMIYAFUGetStatus->YAFUState = 0x00;


    pAMIYAFUGetStatus->Mode = 0x00;
    pAMIYAFUGetStatus->Reserved = 0x00;
    pAMIYAFUGetStatus->GetStatusRes.Datalen=8;
    pAMIYAFUGetStatus->Message[0] = 0;
    pAMIYAFUGetStatus->CompletionCode = YAFU_CC_NORMAL;
    pAMIYAFUGetStatus->GetStatusRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUGetStatus->LastStatusCode,(INT32U)pAMIYAFUGetStatus->GetStatusRes.Datalen);


     return ( sizeof( AMIYAFUGetStatusRes_T ) );
}


/*---------------------------------------
 * YAFUTimerAction
 *---------------------------------------*/
int YAFUTimerAction()
{

    /* Preserving the UBoot configurations*/
    char *mtdDevice = MTDDEVICE;
    int mtd;

    mtd = open (mtdDevice, O_RDWR);
    if (mtd < 0)    
    {
        TCRIT ("Cannot open mtd raw device %s. Exiting...\n", mtdDevice);
        return errno;
    }
	
    /*  Write back environment into flash   */
    if(WriteEnv (&environment,mtd, (EnvStart - FlashStart), EnvSize, GetMacrodefine_getint("CONFIG_SPX_FEATURE_GLOBAL_ERASE_BLOCK_SIZE", 0)) != 0)
    {
        TCRIT ("Cannot write back u-boot environment preserved into flash\n");
		CloseEnv(&environment,mtd);
        return -1;
    }
    CloseEnv(&environment,mtd);

    // Deactivate Flash Mode
    ActivateFlashStatus = 0x00;
    LastStatCode = 0x00;

    if(g_corefeatures.dual_image_support == ENABLED)
    {
        SetMostRecentlyProgFW();
    }

// Resetting the BMC
    /*  Reboot system here  */
    sleep(1);
    reboot (LINUX_REBOOT_CMD_RESTART);
    return 0;
}

/*---------------------------------------
 * YAFUTimerTask
 *---------------------------------------*/
void* YAFUTimerTask(void *pArg)
{
    INT8U YafuInterfaceType=0;
    INT8U *cursessiontype = (INT8U*)pArg;
    prctl(PR_SET_NAME,__FUNCTION__,0,0,0);

    if(cursessiontype != NULL)
        YafuInterfaceType = *cursessiontype;

    if( YafuInterfaceType == LAN_SESSION_TYPE)
    {
	if( YafuFlashMode == YAFU_INTERACTIVE_FLASH)
		YafuTimerCnt = YAFU_LAN_IA_TIMER_COUNT;
        else
		YafuTimerCnt = YAFU_LAN_FF_TIMER_COUNT ;
    }
    else if( YafuInterfaceType == KCS_SESSION_TYPE)
    {
	if( YafuFlashMode == YAFU_INTERACTIVE_FLASH)
		YafuTimerCnt = YAFU_KCS_IA_TIMER_COUNT;
	else
		YafuTimerCnt = YAFU_KCS_FF_TIMER_COUNT ;
    }		
    else if(YafuInterfaceType == USB_SESSION_TYPE)
    {
	if( YafuFlashMode == YAFU_INTERACTIVE_FLASH)
		YafuTimerCnt = YAFU_USB_IA_TIMER_COUNT;
	else
		YafuTimerCnt = YAFU_USB_FF_TIMER_COUNT;
    }
    else
    {
	TDBG(" Flash request received from unknown Interface, so terminating!! \n");
	return NULL;
    }
	
    TINFO("YafuTimer has started with Timeout = %ld\n",YafuTimerCnt);
    while (1)
    {
    	if(YafuflashStatus == YAFU_FLASH_SUCCEEDED)
		break;
        YafuTimerCnt--;
        usleep (1000 * YAFU_MSECS_PER_TICK);
	if( !YafuTimerCnt)
 	{
 		TDBG("Flashing process has Timed OUT, so preserving the UBoot and resetting the BMC\n");
		YAFUTimerAction();
		break;
 	}
    }
    return NULL;

}


/*---------------------------------------
 * AMIYAFUActivateFlashMode
 *---------------------------------------*/
int AMIYAFUActivateFlashMode ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
    int RetVal = 0, mtdDev=0; 
    _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];
    AMIYAFUActivateFlashModeReq_T *pAMIYAFUActivateFlashReq = (AMIYAFUActivateFlashModeReq_T *)pReq;
    AMIYAFUActivateFlashModeRes_T* pAMIYAFUActivateFlash = (AMIYAFUActivateFlashModeRes_T*)pRes;
    _FAR_ SensorSharedMem_T*	pSenSharedMem; 
    INT8U* sessiontype = NULL;
    int ErrVal = 0;
    
    if(CalculateChksum((char *)&pAMIYAFUActivateFlashReq->Mode,sizeof(INT16U)) != pAMIYAFUActivateFlashReq->ActivateflashReq.CRC32chksum)
    {
          LastStatCode=YAFU_INVALID_CHKSUM;
          return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUActivateFlashReq->ActivateflashReq.Seqnum));
    }
   

   if (g_PDKHandle[PDK_ACTIVATEFLASHMODE] != NULL)
   {
        ErrVal = ((int(*)(INT16U, int *, int))g_PDKHandle[PDK_ACTIVATEFLASHMODE]) (pAMIYAFUActivateFlashReq->Mode, &RetVal, BMCInst);
   }

   if ((g_PDKHandle[PDK_ACTIVATEFLASHMODE] == NULL) || (ErrVal == 0))
    RetVal = PrepareFlashArea (FLSH_CMD_PREP_YAFU_FLASH_AREA, g_corefeatures.dual_image_support);

    if ((RetVal == 0) || (RetVal == 4))
    {
         ActivateFlashStatus = 0x01;
         if(access("/var/yafu_bios_update_selection", F_OK) != 0)
        {
            YafuFlashMode = pAMIYAFUActivateFlashReq->Mode;
            if(threadid_yafu == 0)
            {
                OS_THREAD_TLS_GET(g_tls.CurSessionType,sessiontype);
                TINFO("Creating Thread for YafuTimerTask\n");
                pthread_create(&threadid_yafu, NULL, YAFUTimerTask,(void *)sessiontype);
            }

            SetBootParam = 1;
            if((RetVal = InitEnv(&environment,&mtdDev,&SetBootParam)) != 0)
            {
                printf("Cannot init U-Boot Env in YAFUActivateFlashMode for YafuTimerThread\n");
                return RetVal;
            }
            close(mtdDev);

            RetVal =0;
        }
    }
    else
    {
         ActivateFlashStatus = 0x00;
    }

   if( g_corefeatures.online_flashing_support != ENABLED)
   {
       pSenSharedMem = (_FAR_ SensorSharedMem_T*)&pBMCInfo->SensorSharedMem; //m_hSensorSharedMem;   /* Create mutex for Sensor shared memory */
       OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->SensorSharedMemMutex,WAIT_INFINITE);
       pSenSharedMem->GlobalSensorScanningEnable = FALSE;
       /* Release mutex for Sensor shared memory */
       OS_THREAD_MUTEX_RELEASE(&pBMCInfo->SensorSharedMemMutex);
   }

	if(pAMIYAFUActivateFlashReq->ActivateflashReq.Datalen == 0x02)
		pAMIYAFUActivateFlash->ActivateflashRes.Datalen= 0x02;
	else
	{
	    LastStatCode=YAFU_CC_INVALID_DATLEN;
           return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUActivateFlashReq->ActivateflashReq.Seqnum));
    }
    LOCK_BMC_SHARED_MEM(BMCInst);
    g_MBMCInfo.FlashType= YAFU_FLASH;
    UNLOCK_BMC_SHARED_MEM(BMCInst);
    pAMIYAFUActivateFlash->CompletionCode = YAFU_CC_NORMAL;
    pAMIYAFUActivateFlash->ActivateflashRes.Seqnum = pAMIYAFUActivateFlashReq->ActivateflashReq.Seqnum;
    pAMIYAFUActivateFlash->ActivateflashRes.YafuCmd= pAMIYAFUActivateFlashReq->ActivateflashReq.YafuCmd;
    pAMIYAFUActivateFlash->ActivateflashRes.CRC32chksum = 0x00;
    pAMIYAFUActivateFlash->Delay = 0x00;

    return ( sizeof( AMIYAFUActivateFlashModeRes_T ) );
}

/*-------------------------------------------
 * AMIYAFUDualImgSup
 *------------------------------------------*/
int AMIYAFUDualImgSup(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
    AMIYAFUDualImgSupReq_T *pAMIYAFUDualImgSupReq = (AMIYAFUDualImgSupReq_T *)pReq;
    AMIYAFUDualImgSupRes_T *pAMIYAFUDualImgSupRes = (AMIYAFUDualImgSupRes_T *)pRes;

    if(g_corefeatures.dual_image_support == ENABLED)
    {
        if(CalculateChksum((char *)&pAMIYAFUDualImgSupReq->PreserveConf,pAMIYAFUDualImgSupReq->DualImgSupReq.Datalen) != pAMIYAFUDualImgSupReq->DualImgSupReq.CRC32chksum)
        {
             LastStatCode=YAFU_INVALID_CHKSUM;
             return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUDualImgSupReq->DualImgSupReq.Seqnum));
        }

        pAMIYAFUDualImgSupRes->CompletionCode = YAFU_CC_NORMAL;
        if((pAMIYAFUDualImgSupReq->PreserveConf == TRUE) || (pAMIYAFUDualImgSupReq->PreserveConf == FALSE))
        {
            DualImgPreserveConf = pAMIYAFUDualImgSupReq->PreserveConf;
        }
        else
        {
            LastStatCode = YAFU_CC_INVALID_DATA;
            return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATA,pAMIYAFUDualImgSupReq->DualImgSupReq.CRC32chksum));
        }
    }
    else
    {
        *pRes = CC_INV_CMD;
        return sizeof(INT8U);
    }

    return sizeof(AMIYAFUDualImgSupRes_T);
}

/*---------------------------------------
 * AMIYAFUAllocateMemory
 *---------------------------------------*/
int AMIYAFUAllocateMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
	//char command[64];
	//FILE *fp = NULL;
	struct sysinfo s_info;
	int error;
	INT32U  free_mem=0;


    AMIYAFUAllocateMemoryReq_T  *pAMIYAFUAllocateMemoryReq = (AMIYAFUAllocateMemoryReq_T *)pReq;

if (ActivateFlashStatus == 0x01)
{
   AMIYAFUAllocateMemoryRes_T* pAMIYAFUAllocateMemory = (AMIYAFUAllocateMemoryRes_T*)pRes;

   if(CalculateChksum((char *)&pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc,sizeof(INT32U)) != pAMIYAFUAllocateMemoryReq->AllocmemReq.CRC32chksum)
  {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUAllocateMemoryReq->AllocmemReq.Seqnum));
  }

    if(pAMIYAFUAllocateMemoryReq->AllocmemReq.Datalen== 0x04)
		pAMIYAFUAllocateMemory->AllocmemRes.Datalen = 0x04;
    else
    {
              LastStatCode=YAFU_CC_INVALID_DATLEN;
              return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUAllocateMemoryReq->AllocmemReq.Seqnum));
    
    }

    if(pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc > (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize) )
    {
        /*strcpy( command, "free | grep Mem | awk '{print $4}'" );
        fp = popen( command, "r" );
        if( fp == NULL )
        	return -1;
        fscanf(fp, "%ld", &free_mem );
        pclose(fp);*/
	error=sysinfo(&s_info);
	if(error !=0)
	{
	   fprintf(stderr,"\nError in getting free RAM Memory using Sysinfo system call\n Error Code:%d\n",error);
	   LastStatCode=YAFU_CC_GET_MEM_ERR;
	   return(AMIYAFUNotAcks(pRes,YAFU_CC_GET_MEM_ERR,pAMIYAFUAllocateMemoryReq->AllocmemReq.Seqnum));
	}
	free_mem=s_info.freeram;

        /*Reserve the one block of memory for future allocation to fix the page fault in EraseCopyFlash function*/
        free_mem = free_mem - gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize;

        if(pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc > free_mem)
        {
            fprintf(stderr,"\nFlash Image Size(%d)  is greater than Free Memory(%d) in RAM \n\n",(INT32U)pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc,free_mem);
            pAMIYAFUAllocateMemory->Addofallocmem = (INT32U)0xfffffffe;
        }
        else
        {
    allocmem =(INT8U *) malloc ( pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc);

    if(allocmem == NULL)
		pAMIYAFUAllocateMemory->Addofallocmem = (INT32U)0xffffffff;
            else
	        	pAMIYAFUAllocateMemory->Addofallocmem = (INT32U)allocmem ;
        }
        ImgSize = pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc;
    }
    else
    {

        allocmem =(INT8U *) malloc ( pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc);

        if(allocmem == NULL)
	    	pAMIYAFUAllocateMemory->Addofallocmem = (INT32U)0xffffffff;
        else
		pAMIYAFUAllocateMemory->Addofallocmem = (INT32U)allocmem ;

        ImgSize = pAMIYAFUAllocateMemoryReq->Sizeofmemtoalloc;
    }

    pAMIYAFUAllocateMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode= (int)pAMIYAFUAllocateMemory->CompletionCode;
    pAMIYAFUAllocateMemory->AllocmemRes.Seqnum = pAMIYAFUAllocateMemoryReq->AllocmemReq.Seqnum;
    pAMIYAFUAllocateMemory->AllocmemRes.YafuCmd= pAMIYAFUAllocateMemoryReq->AllocmemReq.YafuCmd;
    pAMIYAFUAllocateMemory->AllocmemRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUAllocateMemory->Addofallocmem,sizeof(INT32U));

    return ( sizeof(AMIYAFUAllocateMemoryRes_T));
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUAllocateMemoryReq->AllocmemReq.Seqnum));
    
}

}

/*---------------------------------------
 * AMIYAFUFreeMemory
 *---------------------------------------*/
int AMIYAFUFreeMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{
   AMIYAFUFreeMemoryReq_T *pAMIYAFUFreeMemoryReq = (AMIYAFUFreeMemoryReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    INT32U *memtofree;

    AMIYAFUFreeMemoryRes_T* pAMIYAFUFreeMemory	=(AMIYAFUFreeMemoryRes_T*)pRes;

   if(CalculateChksum((char *)&pAMIYAFUFreeMemoryReq->AddrtobeFreed,sizeof(INT32U)) != pAMIYAFUFreeMemoryReq->FreememReq.CRC32chksum)
  {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUFreeMemoryReq->FreememReq.Seqnum));

  }

    if(pAMIYAFUFreeMemoryReq->FreememReq.Datalen== 0x04)
          pAMIYAFUFreeMemory->FreememRes.Datalen= 0x01;
    else
    {
            LastStatCode = YAFU_CC_INVALID_DATLEN;
            return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUFreeMemoryReq->FreememReq.Seqnum));
    }

   memtofree = (INT32U *)pAMIYAFUFreeMemoryReq->AddrtobeFreed;

   free(memtofree);

    pAMIYAFUFreeMemory->Status =0x00;
    pAMIYAFUFreeMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = pAMIYAFUFreeMemory->CompletionCode;
    pAMIYAFUFreeMemory->FreememRes.Seqnum = pAMIYAFUFreeMemoryReq->FreememReq.Seqnum;
    pAMIYAFUFreeMemory->FreememRes.YafuCmd= pAMIYAFUFreeMemoryReq->FreememReq.YafuCmd;
    pAMIYAFUFreeMemory->FreememRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUFreeMemory->Status,sizeof(INT8U));

    return (sizeof(AMIYAFUFreeMemoryRes_T));
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUFreeMemoryReq->FreememReq.Seqnum));   
    
}


}

/*---------------------------------------
 * AMIYAFUReadFlash
 *---------------------------------------*/

int AMIYAFUReadFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUReadFlashReq_T *pAMIYAFUReadFlashReq = (AMIYAFUReadFlashReq_T *)pReq;


if(ActivateFlashStatus == 0x01)
{
     int fd =0;
     //INT8U *offset;
     INT8U *Buf = 0;
     DWORD StartOffset = 0;
     Buf = NULL;
    AMIYAFUReadFlashRes_T* pAMIYAFUReadFlash =(AMIYAFUReadFlashRes_T*)pRes;

   if(CalculateChksum((char *)&pAMIYAFUReadFlashReq->offsettoread,pAMIYAFUReadFlashReq->ReadFlashReq.Datalen) != pAMIYAFUReadFlashReq->ReadFlashReq.CRC32chksum)
  {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));   
  }

    if(pAMIYAFUReadFlashReq->ReadFlashReq.Datalen!= 0x07)
   {
        LastStatCode =  YAFU_CC_INVALID_DATLEN ;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));   
   }

   // offset = (INT8U *) pAMIYAFUReadFlashReq->offsettoread;
    
    Buf = malloc(pAMIYAFUReadFlashReq->Sizetoread);

    if(Buf == NULL)
    {
      	LastStatCode = YAFU_CC_ALLOC_ERR;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_ALLOC_ERR,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));               
    }

    if(g_corefeatures.dual_image_support == ENABLED)
    {
        if( g_FlashingImage == IMAGE_2 )
            StartOffset = g_coremacros.global_used_flash_size;
    }

      fd=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDONLY);
      if(fd == -1)
      {
                LastStatCode = YAFU_CC_DEV_OPEN_ERR;
              IPMI_ERROR ("Amiyafuupdate:Unable to open %s device/n", gAMIYAFUSwitchFlashDevice.MTDName);
		printf("Unable to open %s device\n", gAMIYAFUSwitchFlashDevice.MTDName);
		if(Buf != NULL)
		{
		    free(Buf);
		}
              return (AMIYAFUNotAcks(pRes,YAFU_CC_DEV_OPEN_ERR,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));                 
      	}

    if ( lseek (fd,StartOffset + pAMIYAFUReadFlashReq->offsettoread, SEEK_SET) == -1)
    {
	    LastStatCode = YAFU_CC_SEEK_ERR;
           fprintf (stderr,
            "seek error on %s: %s\n",
            gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
           if(Buf != NULL)
           {
               free(Buf);
           }
           if(fd != -1)
           {
               close(fd);
           }
            return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));                 

    }

     if( (read(fd,Buf,pAMIYAFUReadFlashReq->Sizetoread)) != pAMIYAFUReadFlashReq->Sizetoread)
     {

        LastStatCode = YAFU_CC_READ_ERR;
         fprintf (stderr,
            "Bytes read error %s: %s\n",
            gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
         if(Buf != NULL)
          {
              free(Buf);
          }
          if(fd != -1)
          {
              close(fd);
          }
         return (AMIYAFUNotAcks(pRes,YAFU_CC_READ_ERR,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));                 
	
     	}


     pAMIYAFUReadFlash->ReadFlashRes.Datalen= pAMIYAFUReadFlashReq->Sizetoread;

     pAMIYAFUReadFlash->CompletionCode = YAFU_CC_NORMAL;
     LastStatCode = pAMIYAFUReadFlash->CompletionCode;
     pAMIYAFUReadFlash->ReadFlashRes.Seqnum = pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum;
     pAMIYAFUReadFlash->ReadFlashRes.YafuCmd= pAMIYAFUReadFlashReq->ReadFlashReq.YafuCmd;
     pAMIYAFUReadFlash->ReadFlashRes.CRC32chksum = CalculateChksum((char *)&Buf,sizeof(pAMIYAFUReadFlashReq->Sizetoread));

    memcpy (( INT8U*) (pAMIYAFUReadFlash + 1),
              ( INT8U*)Buf,
              pAMIYAFUReadFlashReq->Sizetoread );

    free(Buf);
    if(fd != -1)
    {
        close(fd);
    }
    return (sizeof(AMIYAFUReadFlashRes_T) + pAMIYAFUReadFlashReq->Sizetoread);
}
else
{
     LastStatCode = YAFU_CC_IN_DEACTIVATE;
     return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUReadFlashReq->ReadFlashReq.Seqnum));                 
}

}


/*---------------------------------------
 * AMIYAFUWriteFlash
 *---------------------------------------*/
int AMIYAFUWriteFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst)
{

    AMIYAFUWriteFlashReq_T *pAMIYAFUWriteFlashReq = (AMIYAFUWriteFlashReq_T *)pReq;

 if(ActivateFlashStatus == 0x01)
{
    //INT8U *OffsetToWrite;
    int fd;
    DWORD StartOffset = 0;

    AMIYAFUWriteFlashRes_T* pAMIYAFUWriteFlash = (AMIYAFUWriteFlashRes_T*)pRes;

   if(CalculateChksum((char *)&pAMIYAFUWriteFlashReq->offsettowrite,pAMIYAFUWriteFlashReq->WriteFlashReq.Datalen) != pAMIYAFUWriteFlashReq->WriteFlashReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUWriteFlashReq->WriteFlashReq.Seqnum));                 
   }

    //OffsetToWrite = (INT8U *)pAMIYAFUWriteFlashReq->offsettowrite;

    if(g_corefeatures.dual_image_support == ENABLED)
    {
        if( g_FlashingImage == IMAGE_2 )
            StartOffset = g_coremacros.global_used_flash_size;
    }

     fd=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDWR);
     if (fd == -1)
     {
          LastStatCode = YAFU_CC_DEV_OPEN_ERR;
	   printf("ERROR: open failed (%s)\n", strerror(errno));
          return (AMIYAFUNotAcks(pRes,YAFU_CC_DEV_OPEN_ERR,pAMIYAFUWriteFlashReq->WriteFlashReq.Seqnum));                 
     }

        if ( lseek (fd, StartOffset +  pAMIYAFUWriteFlashReq->offsettowrite, SEEK_SET) == -1)
	{
	     LastStatCode = YAFU_CC_SEEK_ERR;
		   fprintf (stderr,
            "seek error on %s: %s\n",
            gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
            return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUWriteFlashReq->WriteFlashReq.Seqnum));                 
      }

        if(write(fd,(pReq + sizeof(AMIYAFUWriteFlashReq_T)),(pAMIYAFUWriteFlashReq->WriteFlashReq.Datalen - 5)) != (pAMIYAFUWriteFlashReq->WriteFlashReq.Datalen - 5))
      {
	  LastStatCode = YAFU_CC_WRITE_ERR;
         return (AMIYAFUNotAcks(pRes,YAFU_CC_SEEK_ERR,pAMIYAFUWriteFlashReq->WriteFlashReq.Seqnum));                 

      }

    pAMIYAFUWriteFlash->SizeWritten = (pAMIYAFUWriteFlashReq->WriteFlashReq.Datalen - 5);
    pAMIYAFUWriteFlash->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = pAMIYAFUWriteFlash->CompletionCode;
    pAMIYAFUWriteFlash->WriteFlashRes.Seqnum = pAMIYAFUWriteFlashReq->WriteFlashReq.Seqnum;
    pAMIYAFUWriteFlash->WriteFlashRes.YafuCmd= pAMIYAFUWriteFlashReq->WriteFlashReq.YafuCmd;
    pAMIYAFUWriteFlash->WriteFlashRes.Datalen= 0x02;
    pAMIYAFUWriteFlash->WriteFlashRes.CRC32chksum = CalculateChksum((char *)&(pAMIYAFUWriteFlash->SizeWritten),sizeof(INT16U));

    close(fd);
    return (sizeof(AMIYAFUWriteFlashRes_T));
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUWriteFlashReq->WriteFlashReq.Seqnum));                 
}

}

/*---------------------------------------
 * AMIYAFUEraseFlash
 *---------------------------------------*/
int AMIYAFUEraseFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUErashFlashReq_T *pAMIYAFUEraseFlashReq = (AMIYAFUErashFlashReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    INT32U offset;
    int fd;
    DWORD StartOffset = 0;
    struct erase_info_user		erase_info;

    AMIYAFUErashFlashRes_T* pAMIYAFUEraseFlash =(AMIYAFUErashFlashRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUEraseFlashReq->Blknumtoerase,sizeof(INT32U)) != pAMIYAFUEraseFlashReq->EraseFlashReq.CRC32chksum)
   {
        LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUEraseFlashReq->EraseFlashReq.Seqnum));
   }

    if(pAMIYAFUEraseFlashReq->EraseFlashReq.Datalen== 0x04)
          pAMIYAFUEraseFlash->EraseFlashRes.Datalen= 0x01;
    else
    {
	   LastStatCode= YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUEraseFlashReq->EraseFlashReq.Seqnum));
    }

    offset = ((pAMIYAFUEraseFlashReq->Blknumtoerase) -1) * (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);

    if(g_corefeatures.dual_image_support == ENABLED)
    {
        if( g_FlashingImage == IMAGE_2 )
            StartOffset = g_coremacros.global_used_flash_size;
    }

    fd=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDWR);
    if (fd == -1)
    {
          LastStatCode = YAFU_CC_DEV_OPEN_ERR;
          printf("ERROR: open failed (%s)\n", strerror(errno));
          return (AMIYAFUNotAcks(pRes,YAFU_CC_DEV_OPEN_ERR,pAMIYAFUEraseFlashReq->EraseFlashReq.Seqnum));
    }

    erase_info.start = StartOffset +  offset;
    erase_info.length = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);

     if((ioctl (fd, MEMERASE, &erase_info)) != -1)
     {
        pAMIYAFUEraseFlash->Status = 0x00;
     }
     else
     {
        pAMIYAFUEraseFlash->Status = 0x01;
     }


    pAMIYAFUEraseFlash->CompletionCode =YAFU_CC_NORMAL;
    LastStatCode = (INT16U) pAMIYAFUEraseFlash->CompletionCode;
    pAMIYAFUEraseFlash->EraseFlashRes.Seqnum = pAMIYAFUEraseFlashReq->EraseFlashReq.Seqnum;
    pAMIYAFUEraseFlash->EraseFlashRes.YafuCmd= pAMIYAFUEraseFlashReq->EraseFlashReq.YafuCmd;
    pAMIYAFUEraseFlash->EraseFlashRes.CRC32chksum = CalculateChksum((char *)&(pAMIYAFUEraseFlash->Status),sizeof(INT8U));

    return (sizeof(AMIYAFUErashFlashRes_T));
}
else
{
    LastStatCode =  YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUEraseFlashReq->EraseFlashReq.Seqnum));
}

}

/*---------------------------------------
 * AMIYAFUProtectFlash
 *---------------------------------------*/
int AMIYAFUProtectFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUProtectFlashReq_T *pAMIYAFUProtectFlashReq = (AMIYAFUProtectFlashReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
   INT32U offset;
   int fd;
   DWORD StartOffset = 0;
   struct erase_info_user		 erase_info;

   AMIYAFUProtectFlashRes_T* pAMIYAFUProtectFlash = (AMIYAFUProtectFlashRes_T*)pRes;


   if(CalculateChksum((char *)&pAMIYAFUProtectFlashReq->Blknum,pAMIYAFUProtectFlashReq->ProtectFlashReq.Datalen) != pAMIYAFUProtectFlashReq->ProtectFlashReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUProtectFlashReq->ProtectFlashReq.Seqnum));                     
   }

    if(pAMIYAFUProtectFlashReq->ProtectFlashReq.Datalen== 0x05)
          pAMIYAFUProtectFlash->ProtectFlashRes.Datalen= 0x01;
    else
    {
        LastStatCode = YAFU_CC_INVALID_DATLEN;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUProtectFlashReq->ProtectFlashReq.Seqnum));                     
    }

    if(access("/var/yafu_bios_update_selection", F_OK) != 0)
    {
        if(g_corefeatures.dual_image_support == ENABLED)
        {
            if( g_FlashingImage == IMAGE_2 )
                StartOffset = g_coremacros.global_used_flash_size;
        }
    }
     fd=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDWR);
     if (fd == -1) {
	  LastStatCode =  YAFU_CC_DEV_OPEN_ERR;
         printf("ERROR: open failed (%s)\n", strerror(errno));
         return (AMIYAFUNotAcks(pRes,YAFU_CC_DEV_OPEN_ERR,pAMIYAFUProtectFlashReq->ProtectFlashReq.Seqnum));                     

    }

     if(pAMIYAFUProtectFlashReq->Blknum == 0xffffffff)
     {
         erase_info.start = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashAddress);
         erase_info.length = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize);
     }
     else
     {
          offset = StartOffset + ( ((pAMIYAFUProtectFlashReq->Blknum)-1) * (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize) );

          erase_info.start = offset;
          erase_info.length = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashSize);
     }

     if(pAMIYAFUProtectFlashReq->Protect ==  0x01)
     {
     	 if((ioctl (fd, MEMLOCK, &erase_info)) != -1)
	 	 pAMIYAFUProtectFlash->Status = 0x00;
    	 else
	 	 pAMIYAFUProtectFlash->Status = 0x01;
     }
     else if(pAMIYAFUProtectFlashReq->Protect == 0x00)
     {
             if((ioctl (fd, MEMUNLOCK, &erase_info)) != -1)
	 	 pAMIYAFUProtectFlash->Status = 0x00;
    	     else
	 	 pAMIYAFUProtectFlash->Status = 0x01;
     }


    pAMIYAFUProtectFlash->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = pAMIYAFUProtectFlash->CompletionCode;
    pAMIYAFUProtectFlash->ProtectFlashRes.Seqnum = pAMIYAFUProtectFlashReq->ProtectFlashReq.Seqnum;
    pAMIYAFUProtectFlash->ProtectFlashRes.YafuCmd= pAMIYAFUProtectFlashReq->ProtectFlashReq.YafuCmd;
    pAMIYAFUProtectFlash->ProtectFlashRes.CRC32chksum =  CalculateChksum((char *)&(pAMIYAFUProtectFlash->Status),sizeof(INT8U));
    close(fd);

    return (sizeof(AMIYAFUProtectFlashRes_T));
}
else
{
     LastStatCode = YAFU_CC_IN_DEACTIVATE;
     return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUProtectFlashReq->ProtectFlashReq.Seqnum));
}

}
void*  EraseCopyFlash	(void *pArg)
{

	int fd;
	INT32U i=0,j;
	INT8U *Buf = NULL;
	INT8U *TmpBuf = NULL;
	struct erase_info_user erase_info;
    DWORD StartOffset = 0;
	void *dl_handle = NULL;
        int (*dl_func)(int, unsigned long, INT8U*, unsigned long, INT32U);
	int retval = 0;
	int ErrCode = 0;
        INT8U FlashError=0;

	prctl(PR_SET_NAME,__FUNCTION__,0,0,0);
	while(1)
	{
		ECFthreadstate=1;
		if(ECFstart==1)
		{
            if(access("/var/yafu_bios_update_selection", F_OK) != 0)
            {
                if(g_corefeatures.dual_image_support == ENABLED)
                {
                    if( g_FlashingImage == IMAGE_2 )
                    StartOffset = g_coremacros.global_used_flash_size;
                }
            }

			// This hook can be used to perform any OEM flashing routines
			// Returning 0 from this hook will revert back to performing default flashing sequence
			// Returning <non-zero> from this hook will validate the ErrCode from the hook, and return appropriately. Default action will be skipped
			// BMCInst is not required for this hook, because flashing can be done by only 1 instance at a time.
			if (g_PDKHandle[PDK_OEMFLASH] != NULL)
   			{
        			retval = ((int(*)(int, INT8U*, unsigned long, int*))g_PDKHandle[PDK_OEMFLASH]) 
									(gDeviceNode, WriteMemOff, Sizetocpy, &ErrCode);
	
				if (retval != 0)
				{
					if (ErrCode != 0)
					{
						LastStatCode = YAFU_FLASH_ERASE_FAILURE;
					}
					else
					{
						LastStatCode = YAFU_ECF_SUCCESS;
					}
			                        		
					ECFstart=0;
					continue;
				}
   			}

            		fd=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDWR);
			if (fd == -1)
			{
				LastStatCode = YAFU_CC_DEV_OPEN_ERR;
				printf("ERROR: open failed (%s)\n", strerror(errno));
				return (void*)0;
			}

			if(access("/var/bios_update_selection", F_OK) != 0)
			{
				FlashError = 0;
				// Loop through the entire file size. Each iteration will handle a block of data
				// The block is set to Erase Block Size configured in the PRJ
			for(j=0;j < (Sizetocpy/(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));j++)
			{
				// Allocate a buffer equivalent to the Erase Block Size configured in the PRJ
				Buf = malloc((gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));
				if(Buf == NULL)
				{
                                   OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
					LastStatCode = YAFU_CC_ALLOC_ERR;
                                   OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
					ECFstart=0;
					FlashError = 1;
					break;
				}
				// Assign the allocated buffer to a temporary pointer
				TmpBuf = Buf;

				// Seek to the required offset in the MTD Device
				if ( lseek (fd,StartOffset + Flashoffset, SEEK_SET) == -1)
				{
                                   OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
					LastStatCode = YAFU_CC_SEEK_ERR;
                                   OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
					fprintf (stderr,
					"seek error on %s: %s\n",
					gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
					ECFstart=0;
					FlashError = 1;
					free(Buf);
					break;
				}

				// Read a block of data from the MTD Device.
				if( (read(fd,Buf,(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize))) != (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize))
				{
                                   OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
					LastStatCode= YAFU_CC_READ_ERR;
                                   OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
					fprintf (stderr,
					"Bytes read error %s: %s\n",
					gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
					ECFstart=0;
					FlashError = 1;
					free(Buf);
					break;
				}

				// Compares the read buffer block with a block of data read from the memory.
				// Previously it would compare the entire block in a byte-by-byte manner
				// Now, we have modified it to use memcmp() on a smaller chunk in the block.
				// The chunk size has been defined as 1024 Bytes.
				// Smaller chunks is to allow smaller processing time for each iteration
				for(i=0;i<(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK);i++) 
				{
	                                if (memcmp(Buf, WriteMemOff, YAFU_FLASH_CHUNK) != 0)
       	                                {
               	                                WriteMemOff = WriteMemOff - (i * YAFU_FLASH_CHUNK);
               	                                break;
                       	                }

                                       	Buf += YAFU_FLASH_CHUNK;
                                       	WriteMemOff += YAFU_FLASH_CHUNK;
                               	}

				// Comparing the buffer has been completed. Now, free the allocated buffer
                               	Buf = TmpBuf;
                               	free (Buf);

				// If the buffers were same for the entire block, then we would skip that block.  Continue with the next block again
				// If the buffers were found different in the memcmp(), then we would proceed to flash that buffer into the flash device
                      		if (i == (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK))
                               	{
                                       	printf("Skipping the erase block %ld\n",(Flashoffset / (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)));
                                       	Flashoffset += (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
                                       	continue;
				}

				// This stage starts the erase/write cycle on the flash device for each block
				// Fill the erase structure with the flash device offset and the erase block size
				erase_info.start = StartOffset + Flashoffset;
				printf("Upgrading the block =  %ld\n",(Flashoffset / (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)));
				erase_info.length = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);

				// Erase the offset using the file descriptor ioctl.
				if((ioctl (fd, MEMERASE, &erase_info)) == -1)
				{
                                   OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
					LastStatCode = YAFU_FLASH_ERASE_FAILURE;
                                   OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
					ECFstart=0;
					FlashError = 1;
					break;
				}

				// Seek to the appropriate offset
				if ( lseek (fd, StartOffset + Flashoffset, SEEK_SET) == -1)
				{
                                   OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
					LastStatCode = YAFU_CC_SEEK_ERR;
                                   OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
					fprintf (stderr,
					"seek error on %s: %s\n",
					gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
					ECFstart=0;
					FlashError = 1;
					break;
				}

				// This code set loops through the block of data, and writes the block of data into the flash deviec
				// The write into the flash device is done in smaller chunks instead of performing for the whole block in a single shot
				// Previously, we would perform write() call on the whole block of data.
				// On platforms with low SPI clock frequency, writing that big block of data was taking more time in the driver layer
				// This was devoiding other interfaces from handling the commands quickly.
				// Some OEMs required IPMB reponse within 110ms which was timing out during flashing.
				// Writing in smaller chunks would bring back control to user space again, thereby giving some cpu time to otehr interface threads also
				// With this change, the IPMB response was being procesed and sent within 110ms in 99% of the cases.
				for (i = 0; i < (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK); i++)
        	                {
    	                        	if (write (fd, WriteMemOff, YAFU_FLASH_CHUNK) != YAFU_FLASH_CHUNK)
                        	        {
                                 		OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                                        	LastStatCode = YAFU_CC_WRITE_ERR;
                                   		OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                                               	ECFstart=0;
                                               	FlashError = 1;
                                               	break;
                                       	}
                                       	WriteMemOff += YAFU_FLASH_CHUNK;
                               	}

                               	Flashoffset += (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
			}
			}
			else
			{
				dl_handle = NULL;

                dl_handle = dlopen((char *)PDKAPP_LIB, RTLD_LAZY);

                if (dl_handle)
                {
                    dl_func = dlsym(dl_handle,"PDK_YafuDoFullBiosFlash");

                if(NULL != dl_func)
                {
                    retval = dl_func(fd,Flashoffset,WriteMemOff,Sizetocpy, gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
                    if(retval != 0)
                    {
                        OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                        LastStatCode = YAFU_FLASH_ERASE_FAILURE;
                        OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                        ECFstart=0;
                    }
                }
                else
                {
			FlashError = 0;
                    for(j=0;j < (Sizetocpy/(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));j++)
                    {
                        Buf = malloc((gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));
                        if(Buf == NULL)
                        {
                            OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                            LastStatCode = YAFU_CC_ALLOC_ERR;
                            OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                            ECFstart=0;
			    	FlashError = 1;
                            break;
                        }
			TmpBuf = Buf;

                        if ( lseek (fd, Flashoffset, SEEK_SET) == -1)
                        {
                            OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                            LastStatCode = YAFU_CC_SEEK_ERR;
                            OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                            fprintf (stderr,
                                "seek error on %s: %s\n",
                                gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
                            ECFstart=0;
				FlashError = 1;
                            break;
                        }

                        if( (read(fd,Buf,(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize))) != (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize))
                        {
                            OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                            LastStatCode= YAFU_CC_READ_ERR;
                            OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                                fprintf (stderr,
                                "Bytes read error %s: %s\n",
                                gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
                            ECFstart=0;
			    	FlashError = 1;
                            break;
                        }

			for (i = 0; i < (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK); i++)
			{
	                	if (memcmp(Buf, WriteMemOff, YAFU_FLASH_CHUNK) != 0)
        	                {
                	        	WriteMemOff = WriteMemOff - (i * YAFU_FLASH_CHUNK);
                	                break;
                        	}

                                Buf += YAFU_FLASH_CHUNK;
                                WriteMemOff += YAFU_FLASH_CHUNK;
                        }

                        Buf = TmpBuf;
                        free (Buf);

                        if (i == (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK))
                        {
                        	printf("Skipping the erase block %ld\n",
						(Flashoffset / (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)));
                                Flashoffset += (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
                                continue;
                        }

                        erase_info.start =Flashoffset;
                        printf("Upgrading the block =  %ld\n",(Flashoffset / (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)));
                        erase_info.length = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);

                        if((ioctl (fd, MEMERASE, &erase_info)) == -1)
                        {
                            OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                            LastStatCode = YAFU_FLASH_ERASE_FAILURE;
                            OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                            ECFstart=0;
				FlashError = 1;
                            break;
                        }

                        if ( lseek (fd,Flashoffset, SEEK_SET) == -1)
                        {
                            OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                            LastStatCode = YAFU_CC_SEEK_ERR;
                            OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                            fprintf (stderr,
                            "seek error on %s: %s\n",
                            gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
                            ECFstart=0;
				FlashError = 1;
                            break;
                        }

                        for (i = 0; i < (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK); i++)
                        {
                        	if (write (fd, WriteMemOff, YAFU_FLASH_CHUNK) != YAFU_FLASH_CHUNK)
                                {
                            		OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex,WAIT_INFINITE);
                                        LastStatCode = YAFU_CC_WRITE_ERR;
                            		OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
                                        ECFstart=0;
                                        FlashError = 1;
                                        break;
                                }
                                WriteMemOff += YAFU_FLASH_CHUNK;
                         }

                         Flashoffset += (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
                    }
                }
                dlclose(dl_handle);
            }
        }
        close(fd);
        ECFstart=0;
			if (FlashError == 0)
			{
        OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex, WAIT_INFINITE);
        LastStatCode = YAFU_ECF_SUCCESS;
        OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
			}
            }
		else
		{
			pthread_mutex_lock(&mutex);
			pthread_cond_wait(&cond, &mutex);
			pthread_mutex_unlock(&mutex);
		}
	}

}

int CheckImageSign()
{
    INT8U *HashString = NULL,*pHash = NULL,*AllocatedMem = NULL;
    static RSA *RSAPubKey=NULL;
    INT32U RemBytes = 0;
    FILE *pubfp  = NULL;
    int  nRet = 0;
    unsigned char strHashOfImg[SHA_DIGEST_LENGTH]={0};
    unsigned char strBuf[BUFSIZE]={0};
    SHA_CTX c;
    int Count = 0;
    char str[SHA_DIGEST_LENGTH*2] = {0};

      RemBytes = ImgSize % gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize;
      if(RemBytes == SIGNED_HASH_SIZE) // Consider that the image is signed image
      {
          if (ENABLED == g_corefeatures.signed_hashed_image_support)
          {
             HashString = malloc(RemBytes);

             /* Copy the Hash String from Image */
             memcpy(HashString,allocmem+(ImgSize-RemBytes),RemBytes);

             /* Open the Public Key File and get the Key first */
            pubfp = fopen(TEMP_PUB_KEY,"rb");
            if(pubfp==NULL)
            {
                IPMI_ERROR("Cannot open file public.pem\n");
                free(HashString);
                return -1;
            }
            if (!PEM_read_RSA_PUBKEY(pubfp, &RSAPubKey, NULL, NULL))
            {
                    IPMI_ERROR("Error loading RSA Public Key File.\n");
                    free(HashString);
                    fclose(pubfp);
                    return -1;
            }

            fclose(pubfp);

            pHash = malloc(RSA_size(RSAPubKey));
            if(!(pHash))
            {
                IPMI_ERROR("Memory allocation failed!!\n");
                free(HashString);
                return -1;
            }
            memset(pHash,0,RemBytes);

            nRet = RSA_public_decrypt(RemBytes, HashString, pHash,RSAPubKey,RSA_PKCS1_PADDING);
            if(nRet==-1)
            {
                IPMI_ERROR("Decrypting the enc-hash failed with return code %d..\n",nRet);
                free(pHash);
                free(HashString);
                return -1;
            }

            if(allocmem == NULL)
            {
                IPMI_ERROR("Decrypting the enc-hash failed with return code %d..\n",nRet);
                free(pHash);
                free(HashString);
                return -1;
            }

            AllocatedMem = allocmem;

            //returns 1 on success and 0 otherwise
            if(SHA1_Init(&c)!=1)
            {
                free(pHash);
                free(HashString);
                return -1;
            }

            for(Count=0;Count<((ImgSize)/(BUFSIZE));Count++)
            {
                nRet = BUFSIZE;
                memcpy(strBuf,AllocatedMem,nRet);
                if(SHA1_Update(&c,strBuf,(unsigned long)nRet)!=1)
                {
                    IPMI_ERROR("Decrypting the enc-hash failed with return code %d..\n",nRet);
                    free(pHash);
                    free(HashString);
                    return -1;
                }
                AllocatedMem += BUFSIZE;
            }

            memset(strHashOfImg,0,SHA_DIGEST_LENGTH);

            if(SHA1_Final(strHashOfImg,&c)!=1)
            {
               IPMI_ERROR("Error in SHA1 Final\n");
                free(pHash);
                free(HashString);
                return -1;
            }

            for(Count=0;Count<SHA_DIGEST_LENGTH;Count++)
            {
                if ( Count == 0)
                {
                    sprintf(str,"%02x",strHashOfImg[Count]);
                }
                else
                {
                    sprintf(str,"%s%02x",str,strHashOfImg[Count]);
                }
                TDBG("%x",strHashOfImg[Count]);
            }
            if(memcmp(str,(char *)pHash,(SHA_DIGEST_LENGTH*2))==0)
            {
                 IPMI_ERROR("IMAGE IS VALID\n");
                 free(pHash);
                 free(HashString);
            }
            else
            {
                IPMI_ERROR("INVALID IMAGE\n");
                free(pHash);
                free(HashString);
                return -1;
            }
        }
        else
        {
            return -2;
        }
      }
    return 0;
}

/*---------------------------------------
 * AMIYAFUEraseCopyFlash
 *---------------------------------------*/
int AMIYAFUEraseCopyFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUEraseCopyFlashReq_T *pAMIYAFUEraseCopyFlashReq = (AMIYAFUEraseCopyFlashReq_T *)pReq;
    int Ret = 0;

if(ActivateFlashStatus == 0x01)
{
    INT8U *MemOffset = NULL;

    AMIYAFUEraseCopyFlashRes_T* pAMIYAFUEraseCopyFlash = (AMIYAFUEraseCopyFlashRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUEraseCopyFlashReq->Memoffset,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Datalen) != pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.CRC32chksum)
    {
        LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
    }

    if(pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Datalen == 0x0c)
    {
          pAMIYAFUEraseCopyFlash->EraseCpyFlashRes.Datalen = 0x04;
    }
    else
    {
          LastStatCode = YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
    }

     MemOffset = (INT8U *) pAMIYAFUEraseCopyFlashReq->Memoffset;

        if(ECFstart==0)
        {
              if(threadid == 0) // Thread is not Created Initialize the Mutex
              {
                    OS_THREAD_MUTEX_INIT(YafuThreadMutex, PTHREAD_MUTEX_RECURSIVE);
                    Ret = CheckImageSign();
                    if(Ret == -1)
                    {
                      LastStatCode = YAFU_CC_INVALID_SIGN_IMAGE;
                      return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_SIGN_IMAGE,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
                    }
                    else if(Ret == -2)
                    {
                       LastStatCode = YAFU_CC_SIGNED_SUPP_NOT_ENABLED;
                      return (AMIYAFUNotAcks(pRes,YAFU_CC_SIGNED_SUPP_NOT_ENABLED,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
                    }
              }

              WriteMemOff=MemOffset;
              Sizetocpy=pAMIYAFUEraseCopyFlashReq->Sizetocopy;
              Flashoffset=pAMIYAFUEraseCopyFlashReq->Flashoffset;
              Fixoffset=pAMIYAFUEraseCopyFlashReq->Flashoffset;
                if(access("/var/bios_update_selection", F_OK) == 0)
                {
                    int MTDDev;
                    MTDDev=open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDWR);

                    if (MTDDev == -1)
                    {
                        LastStatCode = YAFU_CC_DEV_OPEN_ERR;
                        printf("ERROR: open failed (%s)\n", strerror(errno));
                        return (AMIYAFUNotAcks(pRes,YAFU_CC_DEV_OPEN_ERR,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
                    }

                    if(YafuVerifyBiosImage(MTDDev, Flashoffset, WriteMemOff, Sizetocpy, gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize) != 0 )
                    {
                        LastStatCode = YAFU_CC_WRITE_ERR;
                        close(MTDDev);
                        return (AMIYAFUNotAcks(pRes,YAFU_CC_WRITE_ERR,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
                    }
                        close(MTDDev);
                }

                ECFstart=1;
                OS_THREAD_MUTEX_ACQUIRE(&YafuThreadMutex, WAIT_INFINITE);
                if(ECFthreadstate==0)
                {
                    //OS_CREATE_THREAD (EraseCopyFlash, NULL, NULL);
                    pthread_create(&threadid, NULL, EraseCopyFlash, NULL);
                }
                else
                {
                    pthread_mutex_lock(&mutex);
                    pthread_cond_broadcast(&cond);
                    pthread_mutex_unlock(&mutex);
                }
                pAMIYAFUEraseCopyFlash->CompletionCode = YAFU_CC_NORMAL;
            }
            else
            {
                pAMIYAFUEraseCopyFlash->CompletionCode = YAFU_ECF_PROGRESS;
            }
    LastStatCode = (INT16U)pAMIYAFUEraseCopyFlash->CompletionCode;
    OS_THREAD_MUTEX_RELEASE(&YafuThreadMutex);
    pAMIYAFUEraseCopyFlash->Sizecopied =  pAMIYAFUEraseCopyFlashReq->Sizetocopy;
    pAMIYAFUEraseCopyFlash->EraseCpyFlashRes.Seqnum = pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum;
    pAMIYAFUEraseCopyFlash->EraseCpyFlashRes.YafuCmd= pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.YafuCmd;
    pAMIYAFUEraseCopyFlash->EraseCpyFlashRes.CRC32chksum = CalculateChksum((char *)&(pAMIYAFUEraseCopyFlash->Sizecopied),sizeof(INT32U));

    return (sizeof(AMIYAFUEraseCopyFlashRes_T));
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUEraseCopyFlashReq->EraseCpyFlashReq.Seqnum));
}


}
int AMIYAFUGetECFStatus( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
	AMIYAFUGetECFStatusReq_T *pAMIYAFUGetECFStatusReq = (AMIYAFUGetECFStatusReq_T *)pReq;
    AMIYAFUGetECFStatusRes_T* pAMIYAFUGetECFStatus = (AMIYAFUGetECFStatusRes_T*)pRes;

    if ((LastStatCode != YAFU_CC_NORMAL) && (LastStatCode != YAFU_ECF_SUCCESS))
	{
		return (AMIYAFUNotAcks(pRes,LastStatCode,pAMIYAFUGetECFStatusReq->GetECFStatusReq.Seqnum));
	}
	
	pAMIYAFUGetECFStatus->CompletionCode=YAFU_CC_NORMAL;
	pAMIYAFUGetECFStatus->Status =(INT16U) LastStatCode;
    pAMIYAFUGetECFStatus->Progress= ((Flashoffset-Fixoffset)*100)/(Sizetocpy);
    pAMIYAFUGetECFStatus->GetECFStatusRes.Datalen=0x00;
	pAMIYAFUGetECFStatus->GetECFStatusRes.Seqnum = pAMIYAFUGetECFStatusReq->GetECFStatusReq.Seqnum;
    pAMIYAFUGetECFStatus->GetECFStatusRes.YafuCmd= pAMIYAFUGetECFStatusReq->GetECFStatusReq.YafuCmd;
	pAMIYAFUGetECFStatus->GetECFStatusRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUGetECFStatus->Status,(INT32U)pAMIYAFUGetECFStatus->GetECFStatusRes.Datalen);
    return ( sizeof( AMIYAFUGetECFStatusRes_T ) );

}

void*  VerifyFlashStatus	(void *pArg)
{
	
    int fd;
    INT32U i,j;
    INT8U *FlashBuf = NULL;
    INT8U *TmpFlashBuf = NULL;
    DWORD StartOffset = 0;
    int retval = 0;
    int ErrCode = 0;
    INT8U VerifyError=0;
    prctl(PR_SET_NAME,__FUNCTION__,0,0,0);

	while(1)
	{
		Vthreadstate=1;
		if(Vstart==1)
		{
			if(access("/var/yafu_bios_update_selection", F_OK) != 0)
			{
				if(g_corefeatures.dual_image_support == ENABLED)
				{
					if( g_FlashingImage == IMAGE_2 )
						StartOffset = g_coremacros.global_used_flash_size;
				}
			}

			// This hook can be used to perform any OEM verification routines
			// Returning 0 from this hook will revert back to performing default verification sequence
			// Returning <non-zero> from this hook will validate the ErrCode from the hook, and return appropriately. Default action will be skipped
			// BMCInst is not required for this hook, because flashing can be done by only 1 instance at a time.
			if (g_PDKHandle[PDK_OEMVERIFY] != NULL)
   			{
        			retval = ((int(*)(int, INT8U*, unsigned long, int*))g_PDKHandle[PDK_OEMVERIFY])
								(gDeviceNode, VWriteMemOff, Sizetoverify, &ErrCode);

				if (retval != 0)
				{
					if (ErrCode != 0)
					{
						LastStatCode = YAFU_VERIFY_FAILURE;
					}
					else
					{
						LastStatCode = YAFU_VERIFY_SUCCESS;
					}
			                        		
					Vstart=0;
					continue;
				}
   			}

			fd = open(gAMIYAFUSwitchFlashDevice.MTDName, O_RDONLY);
			if (fd == -1) {
				VerifyFlashStatusCode = YAFU_CC_DEV_OPEN_ERR;
				printf("ERROR: open failed (%s)\n", strerror(errno));
				return (void*)0; 		  
			}
			VerifyError=0;

			// Loop through the entire image size in memory.  The verify would be handled in blocks of data, each erase block in size
			for(j=0;j<(Sizetoverify/(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));j++)
			{
				// Allocate a buffer for storing the block of data to be read from flash.  It will be erase block size
				FlashBuf = malloc ((gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize));
				if(FlashBuf == NULL)
				{
					VerifyFlashStatusCode = YAFU_CC_ALLOC_ERR;
					Vstart=0;
					VerifyError=1;
					break;						

				}
				// Assign it to a tempory pointer for future use
				TmpFlashBuf = FlashBuf;

				// Seek the MTD Device to the appropriate offset
				if ( lseek (fd, StartOffset + VFlashoffset, SEEK_SET) == -1)
				{
					VerifyFlashStatusCode = YAFU_CC_SEEK_ERR;

					fprintf (stderr,
					"seek error on %s: %s\n",
					gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
					Vstart=0;
					free(FlashBuf);
					VerifyError=1;
					break;
				}

				// Read a full erase block of data from the flash device. 
				// Since read is faster than write, we can read a whole block of data in a single shot
				if( (read(fd,FlashBuf,(gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize)))!= (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize))
				{
					VerifyFlashStatusCode = YAFU_CC_READ_ERR;
					fprintf (stderr,
					"Bytes read error %s: %s\n",
					gAMIYAFUSwitchFlashDevice.MTDName, strerror (errno));
					Vstart=0;
					free(FlashBuf);
                    			VerifyError=1;
					break;

				}

				// Compares the read buffer block with a block of data read from the memory.
				// Previously it would compare the entire block in a byte-by-byte manner
				// Now, we have modified it to use memcmp() on a smaller chunk in the block.
				// The chunk size has been defined as 1024 Bytes.
				// Smaller chunks is to allow smaller processing time for each iteration
                                for (i = 0; i < (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK); i++)
                                {
                                        if (memcmp(FlashBuf, VWriteMemOff, YAFU_FLASH_CHUNK) != 0)
                                        {
                                                VWriteMemOff = VWriteMemOff - (i * YAFU_FLASH_CHUNK);
                                                break;
                                        }

                                        FlashBuf += YAFU_FLASH_CHUNK;
                                        VWriteMemOff += YAFU_FLASH_CHUNK;
                                }

				// If the data was found to be same between the data read from flash and the data in memory,
				// then, it means the block is successfully written. So proceed with then block
				// If the block was found different, then stop this process with an error, since verify failed
                                if (i == (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize / YAFU_FLASH_CHUNK))
                                {
                                        VOffset = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
                                }
                                else
                                {
                                        TDBG("FlashBuf after verify: Flash = 0x%08lX Mem = 0x%08lX\n",(INT32U)FlashBuf, (INT32U)VWriteMemOff);
                                        TDBG("Verify Failure \n");
                                        VOffset = (INT32U )VWriteMemOff;
                                        VerifyError = 1;
                                        VerifyFlashStatusCode = YAFU_INVALID_CHKSUM;
                                        break;
                                }

                                FlashBuf = TmpFlashBuf;
                                free (FlashBuf);
                                VFlashoffset += (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
			}

			close(fd);
			Vstart=0;
			if (VerifyError==0)
			{
			    VerifyFlashStatusCode = YAFU_VERIFY_SUCCESS;
			}

			// This hook can be used to perform an OEM actions if required upon completion of verification phase
			// This will be the last access point before the flashing sequence exits
			// PDK_OEMSaveFMH has not been added separately.  Instead the FMH can be saved from within this POST_VERIFY hook itself	
			// BMCInst is not required for this hook, because flashing can be done by only 1 instance at a time.
			retval = 0;	
			if (g_PDKHandle[PDK_POST_VERIFY] != NULL)
			{
                        	retval = ((int(*)(int, INT8U, int))g_PDKHandle[PDK_POST_VERIFY]) (gDeviceNode, VerifyError, VerifyFlashStatusCode);
                        	if (retval != 0)
                        	{
                                	TCRIT("Error in handling the Post Verify OEM Sequence\n");
                        	}
			}
		}
		else
		{
			pthread_mutex_lock(&mutexv);
			pthread_cond_wait(&condv, &mutexv);
			pthread_mutex_unlock(&mutexv);
		}
	}

}


/*---------------------------------------
 * AMIYAFUVerifyFlash
 *---------------------------------------*/
int AMIYAFUVerifyFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUVerifyFlashReq_T *pAMIYAFUVerifyFlashReq = (AMIYAFUVerifyFlashReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    INT8U  *MemOffset;

    AMIYAFUVerifyFlashRes_T* pAMIYAFUVerfyFlash = (AMIYAFUVerifyFlashRes_T*)pRes;


   if(CalculateChksum((char *)&pAMIYAFUVerifyFlashReq->Memoffset,(3 * sizeof(INT32U))) != pAMIYAFUVerifyFlashReq->VerifyFlashReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
	  printf("Error in verify flash \n");
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUVerifyFlashReq->VerifyFlashReq.Seqnum));
   }


    if(pAMIYAFUVerifyFlashReq->VerifyFlashReq.Datalen== 0x0c)
          pAMIYAFUVerfyFlash->VerifyFlashRes.Datalen= 0x04;
    else
    {
          LastStatCode = YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUVerifyFlashReq->VerifyFlashReq.Seqnum));
    }


/* wait until Erase Copy Flash to finish */
	while(ECFstart!=0)
	{
//		fprintf(stderr,"\nErase Copy Flash in Progress %d ",ECFstart);
	}
    MemOffset = (INT8U *)pAMIYAFUVerifyFlashReq->Memoffset;
	
	if(Vstart==0)
	{
		VWriteMemOff=MemOffset;
		Sizetoverify=pAMIYAFUVerifyFlashReq->Sizetoverify;
		VFlashoffset=pAMIYAFUVerifyFlashReq->Flashoffset;
		VFixoffset=pAMIYAFUVerifyFlashReq->Flashoffset;
		Vstart=1;
		VerifyFlashStatusCode = 0x00;
		if(Vthreadstate==0)
			{
	  			//OS_CREATE_THREAD (EraseCopyFlash, NULL, NULL);
	  			 pthread_create(&threadidv, NULL, VerifyFlashStatus, NULL);
			}
		else
			{
			pthread_mutex_lock(&mutexv);
			pthread_cond_broadcast(&condv);
			pthread_mutex_unlock(&mutexv);
			
			}
		pAMIYAFUVerfyFlash->CompletionCode = YAFU_CC_NORMAL;
	}
	else
	{
	pAMIYAFUVerfyFlash->CompletionCode = YAFU_VERIFY_PROGRESS;
    
	}
  	pAMIYAFUVerfyFlash->Offset = (gAMIYAFUSwitchFlashDevice.FlashInfo.FlashEraseBlkSize);
    LastStatCode = (INT16U)pAMIYAFUVerfyFlash->CompletionCode;
    pAMIYAFUVerfyFlash->VerifyFlashRes.Seqnum = pAMIYAFUVerifyFlashReq->VerifyFlashReq.Seqnum;
    pAMIYAFUVerfyFlash->VerifyFlashRes.YafuCmd= pAMIYAFUVerifyFlashReq->VerifyFlashReq.YafuCmd;
    pAMIYAFUVerfyFlash->VerifyFlashRes.CRC32chksum = CalculateChksum((char *)&(pAMIYAFUVerfyFlash->Offset),sizeof(INT32U));

    return (sizeof(AMIYAFUVerifyFlashRes_T));
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUVerifyFlashReq->VerifyFlashReq.Seqnum));                       
}

}
int AMIYAFUGetVerifyStatus  ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
		AMIYAFUGetVerifyStatusReq_T *pAMIYAFUGetVerifyStatusReq = (AMIYAFUGetVerifyStatusReq_T *)pReq;
		AMIYAFUGetVerifyStatusRes_T* pAMIYAFUGetVerifyStatus = (AMIYAFUGetVerifyStatusRes_T*)pRes;

		if(LastStatCode!=YAFU_CC_NORMAL&&LastStatCode!=YAFU_VERIFY_SUCCESS)
			{
				return (AMIYAFUNotAcks(pRes,LastStatCode,pAMIYAFUGetVerifyStatusReq->GetVerifyStatusReq.Seqnum));    
			}
	
		pAMIYAFUGetVerifyStatus->CompletionCode=YAFU_CC_NORMAL;
		pAMIYAFUGetVerifyStatus->Status =(INT16U) VerifyFlashStatusCode;
		pAMIYAFUGetVerifyStatus->Offset=VOffset;
		pAMIYAFUGetVerifyStatus->Progress= ((VFlashoffset-VFixoffset)*100)/(Sizetoverify);
		pAMIYAFUGetVerifyStatus->GetVerifyStatusRes.Datalen=0x00;
		pAMIYAFUGetVerifyStatus->GetVerifyStatusRes.Seqnum = pAMIYAFUGetVerifyStatusReq->GetVerifyStatusReq.Seqnum;
		pAMIYAFUGetVerifyStatus->GetVerifyStatusRes.YafuCmd= pAMIYAFUGetVerifyStatusReq->GetVerifyStatusReq.YafuCmd;
		pAMIYAFUGetVerifyStatus->GetVerifyStatusRes.CRC32chksum = CalculateChksum((char *)&(pAMIYAFUGetVerifyStatus->Offset),sizeof(INT32U));
		return ( sizeof( AMIYAFUGetVerifyStatusRes_T ) );

}

/*---------------------------------------
 * AMIYAFUReadMemory
 *---------------------------------------*/
int AMIYAFUReadMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
     AMIYAFUReadMemoryReq_T *pAMIYAFUReadMemoryReq =(AMIYAFUReadMemoryReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
     INT32U *offsetoread;
     INT8U	*Buf = 0;

    AMIYAFUReadMemoryRes_T* pAMIYAFUReadMemory = (AMIYAFUReadMemoryRes_T*)pRes;

   if(CalculateChksum((char *)&pAMIYAFUReadMemoryReq->Memoffset,pAMIYAFUReadMemoryReq->ReadMemReq.Datalen) != pAMIYAFUReadMemoryReq->ReadMemReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUReadMemoryReq->ReadMemReq.Seqnum));                       
   }

    if(pAMIYAFUReadMemoryReq->ReadMemReq.Datalen != 0x07)
    {
	  LastStatCode = YAFU_CC_INVALID_DATLEN;
         return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUReadMemoryReq->ReadMemReq.Seqnum));                       

    }

    offsetoread = (INT32U *)pAMIYAFUReadMemoryReq->Memoffset;

    Buf = malloc(pAMIYAFUReadMemoryReq->Sizetoread);

      if(Buf == NULL)
      {
	     LastStatCode = YAFU_CC_ALLOC_ERR;
           printf("Unable to allocate memory/n");
           return (AMIYAFUNotAcks(pRes,YAFU_CC_ALLOC_ERR,pAMIYAFUReadMemoryReq->ReadMemReq.Seqnum));                       
      }

    memcpy (( INT8U*) Buf,
              ( INT8U*)offsetoread,
              pAMIYAFUReadMemoryReq->Sizetoread );


    memcpy (( INT8U*) (pAMIYAFUReadMemory + 1),
              ( INT8U*)Buf,
              pAMIYAFUReadMemoryReq->Sizetoread );

    pAMIYAFUReadMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U)pAMIYAFUReadMemory->CompletionCode;
    pAMIYAFUReadMemory->ReadMemRes.Seqnum = pAMIYAFUReadMemoryReq->ReadMemReq.Seqnum;
    pAMIYAFUReadMemory->ReadMemRes.Datalen= pAMIYAFUReadMemoryReq->Sizetoread;
    pAMIYAFUReadMemory->ReadMemRes.CRC32chksum = CalculateChksum((char *)Buf,pAMIYAFUReadMemoryReq->Sizetoread);

    free(Buf);
    return (sizeof(AMIYAFUReadMemoryRes_T) + pAMIYAFUReadMemoryReq->Sizetoread );
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUReadMemoryReq->ReadMemReq.Seqnum));
}

}


/*---------------------------------------
 * AMIYAFUWriteMemory
 *---------------------------------------*/
int AMIYAFUWriteMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUWriteMemoryReq_T *pAMIYAFUWriteMemoryReq = (AMIYAFUWriteMemoryReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    INT8U *OffsetToWrite;


    AMIYAFUWriteMemoryRes_T* pAMIYAFUWriteMemory = (AMIYAFUWriteMemoryRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUWriteMemoryReq->Memoffset,pAMIYAFUWriteMemoryReq->WriteMemReq.Datalen) != pAMIYAFUWriteMemoryReq->WriteMemReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         printf("Error in checksum of write memory \n");
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUWriteMemoryReq->WriteMemReq.Seqnum));
  
   }

    OffsetToWrite = (INT8U *)pAMIYAFUWriteMemoryReq->Memoffset;

    memcpy (( INT8U*) OffsetToWrite,
	 	 (pReq + sizeof(AMIYAFUWriteMemoryReq_T)),
		 (pAMIYAFUWriteMemoryReq->WriteMemReq.Datalen - 5));


    pAMIYAFUWriteMemory->SizeWritten = (pAMIYAFUWriteMemoryReq->WriteMemReq.Datalen - 5);

    pAMIYAFUWriteMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U) pAMIYAFUWriteMemory->CompletionCode;
    pAMIYAFUWriteMemory->WriteMemRes.Seqnum= pAMIYAFUWriteMemoryReq->WriteMemReq.Seqnum;
    pAMIYAFUWriteMemory->WriteMemRes.YafuCmd= pAMIYAFUWriteMemoryReq->WriteMemReq.YafuCmd;
    pAMIYAFUWriteMemory->WriteMemRes.Datalen=0x02;
    pAMIYAFUWriteMemory->WriteMemRes.CRC32chksum =  CalculateChksum((char *)&pAMIYAFUWriteMemory->SizeWritten,sizeof(INT16U));

    return (sizeof(AMIYAFUWriteMemoryRes_T));
}
else
{
   LastStatCode = YAFU_CC_IN_DEACTIVATE;
   return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUWriteMemoryReq->WriteMemReq.Seqnum));
}


}

/*---------------------------------------
 * AMIYAFUCopyMemory
 *---------------------------------------*/
int AMIYAFUCopyMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUCopyMemoryReq_T *pAMIYAFUCopyMemoryReq = (AMIYAFUCopyMemoryReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
     INT8U *SrcOffset;
     INT8U *DestOffset;

     AMIYAFUCopyMemoryRes_T* pAMIYAFUCopyMemory = (AMIYAFUCopyMemoryRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUCopyMemoryReq->MemoffsetSrc,pAMIYAFUCopyMemoryReq->CopyMemReq.Datalen) != pAMIYAFUCopyMemoryReq->CopyMemReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUCopyMemoryReq->CopyMemReq.Seqnum));                        

   }

   if(pAMIYAFUCopyMemoryReq->CopyMemReq.Datalen== 0x0c)
          pAMIYAFUCopyMemory->CopyMemRes.Datalen= 0x04;
    else
    {
	   LastStatCode = YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUCopyMemoryReq->CopyMemReq.Seqnum));                        

    }

    SrcOffset = (INT8U *)pAMIYAFUCopyMemoryReq->MemoffsetSrc;

    DestOffset = (INT8U *)pAMIYAFUCopyMemoryReq->MemoffsetDest;

     memcpy(DestOffset,SrcOffset,pAMIYAFUCopyMemoryReq->Sizetocopy);

    pAMIYAFUCopyMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U)pAMIYAFUCopyMemory->CompletionCode;
    pAMIYAFUCopyMemory->CopyMemRes.Seqnum = pAMIYAFUCopyMemoryReq->CopyMemReq.Seqnum;
    pAMIYAFUCopyMemory->CopyMemRes.YafuCmd= pAMIYAFUCopyMemoryReq->CopyMemReq.YafuCmd;
    pAMIYAFUCopyMemory->Sizecopied = pAMIYAFUCopyMemoryReq->Sizetocopy;
    pAMIYAFUCopyMemory->CopyMemRes.CRC32chksum= CalculateChksum((char *)&pAMIYAFUCopyMemory->Sizecopied,sizeof(INT32U));

    return (sizeof(AMIYAFUCopyMemoryRes_T));
}
else
{
    LastStatCode =  YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUCopyMemoryReq->CopyMemReq.Seqnum));                        
}

}

/*---------------------------------------
 * AMIYAFUCompareMemory
 *---------------------------------------*/
int AMIYAFUCompareMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst)
{

    AMIYAFUCompareMemoryReq_T *pAMIYAFUCompareMemoryReq = (AMIYAFUCompareMemoryReq_T *)pReq;

if( ActivateFlashStatus == 0x01)
{
   INT8U *FirstOffset;
   INT8U *SecondOffset;
   INT32U i=0;

    AMIYAFUCompareMemoryRes_T* pAMIYAFUCompareMemory = (	AMIYAFUCompareMemoryRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUCompareMemoryReq->Memoffset1,pAMIYAFUCompareMemoryReq->CmpMemReq.Datalen) != pAMIYAFUCompareMemoryReq->CmpMemReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM,pAMIYAFUCompareMemoryReq->CmpMemReq.Seqnum));                           

   }

    if(pAMIYAFUCompareMemoryReq->CmpMemReq.Datalen== 0x0c)
          pAMIYAFUCompareMemory->CmpMemRes.Datalen= 0x04;
    else
    {
	   LastStatCode = YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN,pAMIYAFUCompareMemoryReq->CmpMemReq.Seqnum));                              

    }

    FirstOffset = (INT8U *) pAMIYAFUCompareMemoryReq->Memoffset1;

    SecondOffset = (INT8U *) pAMIYAFUCompareMemoryReq->Memoffset2;

    for(i=0;i<pAMIYAFUCompareMemoryReq->SizetoCmp;i++)
    	{
    	   if(*FirstOffset == *SecondOffset)
    	   	{
    	   	   FirstOffset++;
                 SecondOffset++;
    	   	}
	    else
	    	{
	    	printf("The value of i = 0x%08X\n", i);
	    	printf("Inside else\n");
	    	break;
	    	}
    	}

    if( i == pAMIYAFUCompareMemoryReq->SizetoCmp)
		pAMIYAFUCompareMemory->Offset = 0x00;
    else
		pAMIYAFUCompareMemory->Offset = (INT32U )FirstOffset;

    pAMIYAFUCompareMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U)pAMIYAFUCompareMemory->CompletionCode;
    pAMIYAFUCompareMemory->CmpMemRes.Seqnum = pAMIYAFUCompareMemoryReq->CmpMemReq.Seqnum;
    pAMIYAFUCompareMemory->CmpMemRes.YafuCmd= pAMIYAFUCompareMemoryReq->CmpMemReq.YafuCmd;
    pAMIYAFUCompareMemory->CmpMemRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUCompareMemory->Offset,sizeof(INT32U));

    return (sizeof(AMIYAFUCompareMemoryRes_T));
}
else
{
    LastStatCode =  YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE,pAMIYAFUCompareMemoryReq->CmpMemReq.Seqnum));                              
}

}

/*---------------------------------------
 * AMIYAFUClearMemory
 *---------------------------------------*/
int AMIYAFUClearMemory ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
     AMIYAFUClearMemoryReq_T *pAMIYAFUClearMemoryReq = (AMIYAFUClearMemoryReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    INT8U *Offset;
    AMIYAFUClearMemoryRes_T* pAMIYAFUClearMemory = (AMIYAFUClearMemoryRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUClearMemoryReq->MemofftoClear,pAMIYAFUClearMemoryReq->ClearMemReq.Datalen) != pAMIYAFUClearMemoryReq->ClearMemReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM, pAMIYAFUClearMemoryReq->ClearMemReq.Seqnum));                                 
   }

    if(pAMIYAFUClearMemoryReq->ClearMemReq.Datalen== 0x08)
          pAMIYAFUClearMemory->ClearMemRes.Datalen= 0x04;
    else
    {
	   LastStatCode = YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN, pAMIYAFUClearMemoryReq->ClearMemReq.Seqnum));                                 
    }

    Offset = (INT8U *)pAMIYAFUClearMemoryReq->MemofftoClear;

    memset(Offset,0,pAMIYAFUClearMemoryReq->SizetoClear);

    pAMIYAFUClearMemory->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = pAMIYAFUClearMemory->CompletionCode;
    pAMIYAFUClearMemory->ClearMemRes.Seqnum = pAMIYAFUClearMemoryReq->ClearMemReq.Seqnum;
    pAMIYAFUClearMemory->ClearMemRes.YafuCmd=pAMIYAFUClearMemoryReq->ClearMemReq.YafuCmd;
    pAMIYAFUClearMemory->SizeCleared=pAMIYAFUClearMemoryReq->SizetoClear;
    pAMIYAFUClearMemory->ClearMemRes.CRC32chksum = CalculateChksum((char *)&pAMIYAFUClearMemory->SizeCleared,sizeof(INT32U));

    return (sizeof(AMIYAFUClearMemoryRes_T));
}
else
{
    LastStatCode =  YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE, pAMIYAFUClearMemoryReq->ClearMemReq.Seqnum));                                 
}

}

/*---------------------------------------
 * AMIYAFUGetBootConfig
 *---------------------------------------*/
int AMIYAFUGetBootConfig ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{

    AMIYAFUGetBootConfigReq_T *pAMIYAFUGetBootConfigReq = (AMIYAFUGetBootConfigReq_T *)pReq;
    char *Buffer = NULL;
    int len = 0;

if( ActivateFlashStatus == 0x01)
{
     int Retval;

    AMIYAFUGetBootConfigRes_T* pAMIYAFUGetBootConfig = (AMIYAFUGetBootConfigRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUGetBootConfigReq->VarName[0],pAMIYAFUGetBootConfigReq->GetBootReq.Datalen) != pAMIYAFUGetBootConfigReq->GetBootReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM, pAMIYAFUGetBootConfigReq->GetBootReq.Seqnum));
   }

    if(pAMIYAFUGetBootConfigReq->GetBootReq.Datalen == 0x41)
          pAMIYAFUGetBootConfig->GetBootRes.Datalen= 0x42;
    else
    {
	   LastStatCode =  YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN, pAMIYAFUGetBootConfigReq->GetBootReq.Seqnum));
    }
    Buffer = malloc (MAX_BOOTVAL_LENGTH);
    if(Buffer == NULL)
    {
        LastStatCode=YAFU_CC_ALLOC_ERR;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_ALLOC_ERR,pAMIYAFUGetBootConfigReq->GetBootReq.Seqnum));

    }
    memset(Buffer,0,MAX_BOOTVAL_LENGTH);
    Retval= GetUBootParam((char *)&pAMIYAFUGetBootConfigReq->VarName,Buffer);

    len = strlen(Buffer);
    len++;

    if(Retval != 0)
         pAMIYAFUGetBootConfig->Status = 0x00;
   else
   	  pAMIYAFUGetBootConfig->Status = 0x01;

    pAMIYAFUGetBootConfig->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U)pAMIYAFUGetBootConfig->CompletionCode;
    pAMIYAFUGetBootConfig->GetBootRes.Seqnum = pAMIYAFUGetBootConfigReq->GetBootReq.Seqnum;
    pAMIYAFUGetBootConfig->GetBootRes.YafuCmd=pAMIYAFUGetBootConfigReq->GetBootReq.YafuCmd;

    memcpy (( INT8U*) (pAMIYAFUGetBootConfig + 1),
                   ( INT8U*)Buffer,len );
    pAMIYAFUGetBootConfig->GetBootRes.Datalen = len + 1;  //one for status
    pAMIYAFUGetBootConfig->GetBootRes.CRC32chksum= CalculateChksum((char *)&pAMIYAFUGetBootConfig->Status,pAMIYAFUGetBootConfig->GetBootRes.Datalen);

    free(Buffer);
    return (sizeof(AMIYAFUGetBootConfigRes_T) + len);
}
else
{
    LastStatCode =   YAFU_CC_IN_DEACTIVATE;
    return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE, pAMIYAFUGetBootConfigReq->GetBootReq.Seqnum));
}

}

/*---------------------------------------
 * AMIYAFUSetBootConfig
 *---------------------------------------*/
int AMIYAFUSetBootConfig ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIYAFUSetBootConfigReq_T *pAMIYAFUSetBootConfigReq = (AMIYAFUSetBootConfigReq_T *)pReq;

if( ActivateFlashStatus == 0x01)
{

    int RetVal=0;
    char *BootVal = NULL;

    AMIYAFUSetBootConfigRes_T* pAMIYAFUSetBootConfig = (AMIYAFUSetBootConfigRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUSetBootConfigReq->VarName[0],pAMIYAFUSetBootConfigReq->SetBootReq.Datalen) != pAMIYAFUSetBootConfigReq->SetBootReq.CRC32chksum)
    {
	  LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM, pAMIYAFUSetBootConfigReq->SetBootReq.Seqnum));
    }


    BootVal = malloc (pAMIYAFUSetBootConfigReq->SetBootReq.Datalen - 65);
    if(BootVal  == NULL)
    {
        LastStatCode=YAFU_CC_ALLOC_ERR;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_ALLOC_ERR,pAMIYAFUSetBootConfigReq->SetBootReq.Seqnum));

    }
    pReq += sizeof(AMIYAFUSetBootConfigReq_T);
    memcpy(BootVal,pReq,(pAMIYAFUSetBootConfigReq->SetBootReq.Datalen - 65));
    memset(pReq,0,(pAMIYAFUSetBootConfigReq->SetBootReq.Datalen - 65));
    pReq -= sizeof(AMIYAFUSetBootConfigReq_T);

    if(strcmp((char *)pAMIYAFUSetBootConfigReq->VarName,"baudrate") != 0)
    {
        RetVal = SetUBootParam((char *)pAMIYAFUSetBootConfigReq->VarName,BootVal);
        if(RetVal != 0)
        {
            pAMIYAFUSetBootConfig->Status = 0x00;
        }
        else
        {
            pAMIYAFUSetBootConfig->Status = 0x01;
        }
    }
    else
              pAMIYAFUSetBootConfig->Status = 0x01;

    pAMIYAFUSetBootConfig->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U)pAMIYAFUSetBootConfig->CompletionCode;
    pAMIYAFUSetBootConfig->SetBootRes.Seqnum = pAMIYAFUSetBootConfigReq->SetBootReq.Seqnum;
    pAMIYAFUSetBootConfig->SetBootRes.YafuCmd = pAMIYAFUSetBootConfigReq->SetBootReq.YafuCmd;
    pAMIYAFUSetBootConfig->SetBootRes.Datalen = 0x01;
    pAMIYAFUSetBootConfig->SetBootRes.CRC32chksum= CalculateChksum((char *)&pAMIYAFUSetBootConfig->Status,pAMIYAFUSetBootConfig->SetBootRes.Datalen );

    free(BootVal);
    return (sizeof(AMIYAFUSetBootConfigRes_T));
}
else
{
   LastStatCode =  YAFU_CC_IN_DEACTIVATE;
   return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE, pAMIYAFUSetBootConfigReq->SetBootReq.Seqnum));
}

}

/*---------------------------------------
 * AMIYAFUGetBootVars
 *---------------------------------------*/
int AMIYAFUGetBootVars ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIYAFUGetBootVarsReq_T *pAMIYAFUGetBootVarsReq = (AMIYAFUGetBootVarsReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    //int RetVal;
    char *Buffer;
    int BootVarlen =0;


    AMIYAFUGetBootVarsRes_T* pAMIYAFUGetBootVars = (AMIYAFUGetBootVarsRes_T*)pRes;
    pAMIYAFUGetBootVars->VarCount = 0X00;


    Buffer = malloc (MAX_BOOTVAR_LENGTH);
    if(Buffer == NULL)
    {
        LastStatCode=YAFU_CC_ALLOC_ERR;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_ALLOC_ERR,pAMIYAFUGetBootVarsReq->GetBootReq.Seqnum));
    }

    GetAllUBootParam ((char *)&pAMIYAFUGetBootVars->VarCount,Buffer,&BootVarlen);

    memcpy (( INT8U*) (pAMIYAFUGetBootVars + 1),
                   ( INT8U*)Buffer,BootVarlen );

    pAMIYAFUGetBootVars->GetBootRes.Datalen = BootVarlen + 1; //One added for Variable count

    pAMIYAFUGetBootVars->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U)pAMIYAFUGetBootVars->CompletionCode;
    pAMIYAFUGetBootVars->GetBootRes.Seqnum = pAMIYAFUGetBootVarsReq->GetBootReq.Seqnum;
    pAMIYAFUGetBootVars->GetBootRes.YafuCmd = pAMIYAFUGetBootVarsReq->GetBootReq.YafuCmd;
    pAMIYAFUGetBootVars->GetBootRes.CRC32chksum= CalculateChksum((char *)&pAMIYAFUGetBootVars->VarCount,pAMIYAFUGetBootVars->GetBootRes.Datalen);

    free(Buffer);
    return (sizeof(AMIYAFUGetBootVarsRes_T)+ BootVarlen);
}
else
{
   LastStatCode = YAFU_CC_IN_DEACTIVATE;
   return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE, pAMIYAFUGetBootVarsReq->GetBootReq.Seqnum));
}

}



/*---------------------------------------
 * AMIYAFUDeactivateFlash
 *---------------------------------------*/
int AMIYAFUDeactivateFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    char Cmd[128];
    AMIYAFUDeactivateFlashReq_T *pAMIYAFUDeactivateFlashReq = (AMIYAFUDeactivateFlashReq_T *)pReq;

if(ActivateFlashStatus == 0x01)
{
    AMIYAFUDeactivateFlashRes_T* pAMIYAFUDeactivateFlash = (AMIYAFUDeactivateFlashRes_T*)pRes;

    if(pAMIYAFUDeactivateFlashReq->DeactivateFlashReq.Datalen== 0x00)
          pAMIYAFUDeactivateFlash->DeactivateFlashRes.Datalen= 0x01;
    else
    {
          LastStatCode = YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN, pAMIYAFUDeactivateFlashReq->DeactivateFlashReq.Seqnum));
    }

    ActivateFlashStatus = 0x00;

    if(access("/var/yafu_bios_update_selection", F_OK) == 0)
    {
        StartInitFlashSetting();
        sprintf(Cmd, "rm %s", FLASHER_COMPLETION_FILE_INIT7);
        safe_system(Cmd);
        sprintf(Cmd, "/sbin/rmmod host_spi_flash_hw");
        safe_system(Cmd);
        sprintf(Cmd, "/sbin/rmmod host_spi_flash");
        safe_system(Cmd);
        sprintf(Cmd, "rm /var/yafu_bios_update_selection");
        safe_system(Cmd);
    }

    if(g_corefeatures.online_flashing_support == ENABLED)
    {
        unlink(FLASHER_INIT_START);
        unlink(FLASHER_COMPLETION_FILE_INIT7);
    }
    pAMIYAFUDeactivateFlash->Status = 0x00;
    pAMIYAFUDeactivateFlash->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U) pAMIYAFUDeactivateFlash->CompletionCode;
    pAMIYAFUDeactivateFlash->DeactivateFlashRes.Seqnum = pAMIYAFUDeactivateFlashReq->DeactivateFlashReq.Seqnum;
    pAMIYAFUDeactivateFlash->DeactivateFlashRes.YafuCmd = pAMIYAFUDeactivateFlashReq->DeactivateFlashReq.YafuCmd;
    pAMIYAFUDeactivateFlash->DeactivateFlashRes.CRC32chksum= CalculateChksum((char *)&pAMIYAFUDeactivateFlash->Status,sizeof(INT8U));

    if(g_corefeatures.dual_image_support == ENABLED && access("/var/bios_update_selection", F_OK) != 0)
    {
        SetMostRecentlyProgFW();
    }

    return (sizeof(AMIYAFUDeactivateFlashRes_T));
}
else
{
    LastStatCode = YAFU_CC_IN_DEACTIVATE;
   return (AMIYAFUNotAcks(pRes,YAFU_CC_IN_DEACTIVATE, pAMIYAFUDeactivateFlashReq->DeactivateFlashReq.Seqnum));                                    
}

}

/*---------------------------------------
 * AMIYAFUResetDevice
 *---------------------------------------*/
int AMIYAFUResetDevice ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    int Restart_Flag = 0;

    AMIYAFUResetDeviceReq_T *pAMIYAFUResetDeviceReq = (AMIYAFUResetDeviceReq_T *)pReq;
    AMIYAFUResetDeviceRes_T* pAMIYAFUResetDevice = (AMIYAFUResetDeviceRes_T*)pRes;
    // YafuflashStatus is updated to terminate the YafuTimerThread
    YafuflashStatus = YAFU_FLASH_SUCCEEDED;

     if(CalculateChksum((char *)&pAMIYAFUResetDeviceReq->WaitSec,sizeof(INT16U)) != pAMIYAFUResetDeviceReq->ResetReq.CRC32chksum)
   {
         LastStatCode=YAFU_INVALID_CHKSUM;
         return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM, pAMIYAFUResetDeviceReq->ResetReq.Seqnum));                                    

   }

    if(pAMIYAFUResetDeviceReq->ResetReq.Datalen== 0x02)
          pAMIYAFUResetDevice->ResetRes.Datalen= 0x01;
    else
    {
	   LastStatCode =   YAFU_CC_INVALID_DATLEN;
          return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN, pAMIYAFUResetDeviceReq->ResetReq.Seqnum));                                      

    }

	if(access("/var/yafu_bios_update_selection", F_OK) != 0)
	{
    if(g_corefeatures.preserve_config == ENABLED)
    {
        if(pAMIYAFUResetDeviceReq->WaitSec == 0x02)
        {
            Restart_Flag = 1;
            TINFO("Trying to preserve config on full flash using preservecfg application");
            safe_system("/usr/local/bin/preservecfg 2");
        }
    }

    if(g_corefeatures.dual_image_support == ENABLED)
    {
        if(DualImgPreserveConf == FALSE)
        {
            safe_system("rm -rf /conf/*");
        }
    }
	}

    /* Considering rebootstatus flag*/
    RestartDeviceWithNewFirmware();
	
    pAMIYAFUResetDevice->Status = 0x01;
    pAMIYAFUResetDevice->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U) pAMIYAFUResetDevice->CompletionCode;
    pAMIYAFUResetDevice->ResetRes.Seqnum = pAMIYAFUResetDeviceReq->ResetReq.Seqnum;
    pAMIYAFUResetDevice->ResetRes.YafuCmd = pAMIYAFUResetDeviceReq->ResetReq.YafuCmd;
    pAMIYAFUResetDevice->ResetRes.CRC32chksum=CalculateChksum((char *)&pAMIYAFUResetDevice->Status,sizeof(INT8U));

    return (sizeof(AMIYAFUResetDeviceRes_T));
}

int AMIYAFUFWSelectFlash ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIYAFUFWSelectFlashModeReq_T *pAMIYAFUFWSelectFlashModeReq = (AMIYAFUFWSelectFlashModeReq_T *)pReq;
    AMIYAFUFWSelectFlashModeRes_T* pAMIYAFUFWSElectFlashMode = (AMIYAFUFWSelectFlashModeRes_T*)pRes;

    if(CalculateChksum((char *)&pAMIYAFUFWSelectFlashModeReq->fwselect,sizeof(INT8U)) != pAMIYAFUFWSelectFlashModeReq->fwselectflashReq.CRC32chksum)
    {
        LastStatCode=YAFU_INVALID_CHKSUM;
        return (AMIYAFUNotAcks(pRes,YAFU_INVALID_CHKSUM, pAMIYAFUFWSelectFlashModeReq->fwselectflashReq.Seqnum));
    }

    if(pAMIYAFUFWSelectFlashModeReq->fwselectflashReq.Datalen == 0x01)
        pAMIYAFUFWSElectFlashMode->fwselectflashRes.Datalen = 0x01;
    else
    {
        LastStatCode =   YAFU_CC_INVALID_DATLEN;
        return (AMIYAFUNotAcks(pRes,YAFU_CC_INVALID_DATLEN, pAMIYAFUFWSelectFlashModeReq->fwselectflashReq.Seqnum));
    }

    if (pAMIYAFUFWSelectFlashModeReq->fwselect == FW_BMC )
    {
        safe_system("rm -f /var/yafu_bios_update_selection");
    }
    else if (pAMIYAFUFWSelectFlashModeReq->fwselect == FW_BIOS)
    {
        safe_system("touch /var/yafu_bios_update_selection");
    }

    pAMIYAFUFWSElectFlashMode->CompletionCode = YAFU_CC_NORMAL;
    LastStatCode = (INT16U) pAMIYAFUFWSElectFlashMode->CompletionCode;
    pAMIYAFUFWSElectFlashMode->fwselectflashRes.Seqnum = pAMIYAFUFWSelectFlashModeReq->fwselectflashReq.Seqnum;
    pAMIYAFUFWSElectFlashMode->fwselectflashRes.YafuCmd = pAMIYAFUFWSelectFlashModeReq->fwselectflashReq.YafuCmd;

    return (sizeof(AMIYAFUResetDeviceRes_T));
}
#endif

/**
 * @fn CheckForBootOption
 * @brief Check for valid boot selector option.
 * @param[in] bootoption - boot selector option.
 * @retval      0 - for valid boot selector option.
 *              1 - invalid boot option.
 */
static int CheckForBootOption(char bootoption)
{
    //Checking for valid Boot selector option
    if(  (bootoption != AUTO_HIGH_VER_FW) && 
         (bootoption != LOWER_IMAGE_FW ) && 
         (bootoption != HIGHER_IMAGE_FW ) && 
         (bootoption != AUTO_LOW_VER_FW) &&
         (bootoption != MOST_RECENTLY_PROG_FW) && 
         (bootoption != LEAST_RECENTLY_PROG_FW) )
    {
        return -1;
    }

return 0;
}

/**
 * @fn IsfwuploadSelectorValid
 * @brief Check for valid firmware upload selector.
 * @param[in] uploadselector - Firmwareupload selector option.
 * @retval  TRUE  - for valid firmware upload selector.
 *          FALSE - invalid firmware upload selector option.
 */
static bool IsfwuploadSelectorValid(char uploadselector)
{
   return( (uploadselector == AUTO_INACTIVE_IMAGE)
           || (uploadselector == IMAGE_1 )
           || (uploadselector == IMAGE_2 ) 
           || (uploadselector == IMAGE_BOTH )
         );
}

int AMIDualImageSupport( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIDualImageSupReq_T *pAMIDualImageSupReq = (AMIDualImageSupReq_T *)pReq;
    AMIDualImageSupRes_T *pAMIDualImageSupRes = (AMIDualImageSupRes_T *)pRes;
    char envval[5]    = {0};
    int  bootselector = 0;
    unsigned char   fwuploadselector = 0;
    FWINFO_STRUCT   FwInfo;
    char tempstr[30];
    char * pTemp;


    if(g_corefeatures.dual_image_support == ENABLED)
    {
        if(ReqLen != m_DualResBits[pAMIDualImageSupReq->Parameter - 1])
        {
            *pRes = CC_REQ_INV_LEN;
            return sizeof(INT8U); 
        }

        switch (pAMIDualImageSupReq->Parameter) //validating for command sub specifier
        {
            case SETFWBOOTSELECTOR:

                if (IsCardInFlashMode() != 0)
                {
                   *pRes = CC_DEV_IN_FIRMWARE_UPDATE_MODE;
                    return sizeof(INT8U);
                }

                //Checking for valid Boot selector option
                if( CheckForBootOption(pAMIDualImageSupReq->BootSelector) != 0 )
                {
                    IPMI_ERROR("Invalid Bootoption");
                    *pRes = CC_INV_DATA_FIELD;
                    return sizeof(INT8U);
                }
				
                /*caching bootselector value to avoid unnecessary writes to same values in next set */
                if( g_FWBootSelector != pAMIDualImageSupReq->BootSelector )
                {
                    /* sets env if bootselector differs with previous one */
                    memset(envval,0,sizeof(envval));
                    sprintf(envval,"%d",pAMIDualImageSupReq->BootSelector);
                    if( SetUBootParam("bootselector",envval) != 0 )
                    {
                        IPMI_ERROR("Setting env variable bootselector failed");
                        *pRes = CC_UNSPECIFIED_ERR;
                        return sizeof(INT8U);
                    }
                    g_FWBootSelector = pAMIDualImageSupReq->BootSelector;
                }
                pAMIDualImageSupRes->BootSelOpt.SetBootSelector = pAMIDualImageSupReq->BootSelector;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.SetBootSelector);
                break;

            case GETFWBOOTSELECTOR:

                if(g_FWBootSelector == 0xFF) /* reads from env at very first time */
                {
                    if( GetUBootParam("bootselector",envval) != 0 )
                    {
                        IPMI_ERROR("Reading env variable bootselector failed");
                        *pRes = CC_UNSPECIFIED_ERR;
                        return sizeof(INT8U);
                    }
                    sscanf(envval,"%d",&bootselector);
                    //Checking for valid Boot selector option
                    if( CheckForBootOption(bootselector) !=0 )
                    {
                       IPMI_ERROR("Invalid Bootoption");
                       *pRes = CC_UNSPECIFIED_ERR;
                       return sizeof(INT8U);
                    }
                    g_FWBootSelector = bootselector;
                }
                pAMIDualImageSupRes->BootSelOpt.GetBootSelector = g_FWBootSelector;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.GetBootSelector);
                break;

            case SETFWUPLOADSELECTOR:
                if( IsCardInFlashMode() != 0)
                {
                   *pRes = CC_DEV_IN_FIRMWARE_UPDATE_MODE;
                   return sizeof(INT8U);
                } 

                fwuploadselector =  pAMIDualImageSupReq->BootSelector;
                if( IsfwuploadSelectorValid(fwuploadselector) == FALSE)
                {
                    *pRes = CC_INV_DATA_FIELD;
                    return sizeof(INT8U);
                }
				
                if( fwuploadselector != g_FWUploadSelector )
                {
                    if(fwuploadselector == AUTO_INACTIVE_IMAGE)
                    {
                        fwuploadselector = g_InactiveImage;
                    }

                    if ( InformFlasher(fwuploadselector,FLSH_DUAL_IMAGE_OPTIONS) != 0 )
                    {
                        IPMI_ERROR(" SETFWUPLOADSELECTOR unable to communicate flasher process \n");
                        *pRes = CC_UNSPECIFIED_ERR;
                        return sizeof(INT8U);
                    }
                    g_FWUploadSelector = pAMIDualImageSupReq->BootSelector;
                    g_FlashingImage = fwuploadselector;
                }
                pAMIDualImageSupRes->BootSelOpt.SetUploadSelector = pAMIDualImageSupReq->BootSelector;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.SetUploadSelector);
                break;

            case GETFWUPLOADSELECTOR:

                if( IsfwuploadSelectorValid(g_FWUploadSelector) == FALSE )
                {
                    *pRes = CC_UNSPECIFIED_ERR;
                    return sizeof(INT8U);
                }

                pAMIDualImageSupRes->BootSelOpt.GetUploadSelector = (g_FWUploadSelector == AUTO_INACTIVE_IMAGE) ? g_InactiveImage:g_FWUploadSelector;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.GetUploadSelector);
                break;

            case SETREBOOTSTATUS:
                if ((pAMIDualImageSupReq->BootSelector != REBOOT_DEVICE) && (pAMIDualImageSupReq->BootSelector != NO_REBOOT_DEVICE))
                {
                    *pRes = CC_INV_DATA_FIELD;
                    return sizeof(INT8U); 
                }
                
                if ( InformFlasher(pAMIDualImageSupReq->BootSelector,FLSH_REBOOT_DEVICE_OPTIONS) != 0 )
                {
                    IPMI_ERROR(" SetRebootStatus unable to communicate flasher process \n");
                    *pRes = CC_UNSPECIFIED_ERR;
                    return sizeof(INT8U); 
                }

                 g_rebootstatus = pAMIDualImageSupRes->BootSelOpt.SetRebootStatus = pAMIDualImageSupReq->BootSelector;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.SetRebootStatus);
                break;

            case GETREBOOTSTATUS:
                pAMIDualImageSupRes->BootSelOpt.GetRebootStatus = g_rebootstatus;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.GetRebootStatus);
                break;

            case GETCURACTIVEIMG:
                pAMIDualImageSupRes->BootSelOpt.GetCurActiveImg = g_RunningImage;
                pAMIDualImageSupRes->CompletionCode = CC_NORMAL;
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.GetCurActiveImg);
                break;

            case GETDUALIMGFWINFO:
                if((pAMIDualImageSupReq->BootSelector != IMAGE_1) && (pAMIDualImageSupReq->BootSelector != IMAGE_2))
                {
                    IPMI_ERROR("Invalid Image Selector %x\n",pAMIDualImageSupReq->BootSelector);
                    *pRes = CC_INV_DATA_FIELD;
                    return sizeof(INT8U);
                }

                if(pAMIDualImageSupReq->BootSelector == IMAGE_1)
                {
                    if (0 != GetIMG1FWInfo(&FwInfo))
                    {
                        IPMI_ERROR("Error while getting the FWInfo for IMAGE1\n");
                        *pRes = CC_UNSPECIFIED_ERR;
                        return sizeof(INT8U);
                    }
                }

                if(pAMIDualImageSupReq->BootSelector == IMAGE_2)
                {
                    if (0 != GetIMG2FWInfo(&FwInfo))
                    {
                        IPMI_ERROR("Error while getting the FWInfo for IMAGE2\n");
                        *pRes = CC_UNSPECIFIED_ERR;
                        return sizeof(INT8U);
                    }
                }

                /*Parse the Major and Minor Version*/
                memset(tempstr,'\0', sizeof(tempstr));
                pTemp = (char *)FwInfo.FWVersion;
                sscanf(pTemp," %[^.] ",tempstr);
                pAMIDualImageSupRes->BootSelOpt.GetFwVersion.MajVer = atoi(tempstr);
                pTemp = strchr(pTemp,'.');
                pTemp = pTemp + 1;
                memset(tempstr,'\0', sizeof(tempstr));
                sscanf(pTemp," %[^.] ",tempstr);
                pAMIDualImageSupRes->BootSelOpt.GetFwVersion.MinVer = atoi(tempstr);
                return sizeof(INT8U) + sizeof(pAMIDualImageSupRes->BootSelOpt.GetFwVersion);
                break;

            default:
                *pRes = CC_INV_DATA_FIELD;
                return sizeof(INT8U);
        }

    }
    else
    {
        *pRes = CC_INV_CMD;
        return sizeof(INT8U);
    }
}

/*
*@fn AMIGetNMChNum
*@brief This command helps in framing send message command if the Sensor Owner ID is
             other than BMC like Node Manager.This retrives the correct IPMB channel associated 
             with the device.
*@param pReq - Request for the command   
*@param ReqLen - Request length for the command
*@param pRes - Respose for the command
*@return Returns size of AMIGetChNumRes_T
*/
int AMIGetNMChNum ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst ) 
{
    AMIGetChNumRes_T* pAMIGetChNumRes = (AMIGetChNumRes_T*) pRes;
    _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];

    if(g_corefeatures.node_manager != ENABLED)
    {
        *pRes = CC_DEVICE_NOT_SUPPORTED;
        return sizeof(*pRes);
    }
    
    pAMIGetChNumRes->ChannelNum = (pBMCInfo->NMConfig.NM_IPMBBus ? pBMCInfo->SecondaryIPMBCh : pBMCInfo->PrimaryIPMBCh);
    pAMIGetChNumRes->CompletionCode = CC_NORMAL;

    return sizeof(AMIGetChNumRes_T);
}

/**
*@fn AMIGetEthIndex
*@brief This command helps in getting the Corresponding EthIndex Value
           for the requested Channel Number
*@param pReq - Request for the command   
*@param ReqLen - Request length for the command
*@param pRes - Respose for the command
*@return Returns size of AMIGetEthIndexReq_T
*/

int AMIGetEthIndex ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,_NEAR_ int BMCInst) 
{
    INT8U EthIndex = 0;
    AMIGetEthIndexReq_T *pAMIGetEthIndexReq = (AMIGetEthIndexReq_T *) pReq;
    AMIGetEthIndexRes_T *pAMIGetEthIndexRes = (AMIGetEthIndexRes_T *) pRes;

    pAMIGetEthIndexRes->CompletionCode = CC_NORMAL;

    EthIndex = GetEthIndex(pAMIGetEthIndexReq->ChannelNum, BMCInst);
    pAMIGetEthIndexRes->EthIndex=EthIndex;

    return sizeof(AMIGetEthIndexRes_T);
}


/*-----------------------------------
* Functions used by internal API
*-----------------------------------*/


/**
 * *@fn AMIGetFruDetails
 * *@brief This command can get the total fru and the repective fru ids
 *            *@param pReq - Request for the command
 *            *@param ReqLen - Request length for the command
 *            *@param pRes - Respose for the command
 *            */

int AMIGetFruDetails( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,int BMCInst )
{
    AMIGetFruDetailReq_T *pAMIFruDetailReq = (AMIGetFruDetailReq_T *) pReq;
    AMIGetFruDetailRes_T *pAMIFruDetailRes = (AMIGetFruDetailRes_T *) pRes;
     _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];

     memset((char *)pRes,0,sizeof(AMIGetFruDetailRes_T));

    if(pAMIFruDetailReq->FruReq==0xFF)
    {                                                 	       
        pAMIFruDetailRes->TotalFru = pBMCInfo->FRUConfig.total_frus;
        pAMIFruDetailRes->CompletionCode = CC_NORMAL;
        return sizeof(pAMIFruDetailRes->TotalFru) + sizeof(pAMIFruDetailRes->CompletionCode);
    }
    else if(pAMIFruDetailReq->FruReq < pBMCInfo->FRUConfig.total_frus)
    {
        pAMIFruDetailRes->TotalFru = pBMCInfo->FRUConfig.total_frus;
        pAMIFruDetailRes->DeviceNo = pBMCInfo->FRUConfig.m_FRUInfo[pAMIFruDetailReq->FruReq]->DeviceID;
        strcpy((char *)pAMIFruDetailRes->FRUName,pBMCInfo->FRUConfig.m_FRUInfo[pAMIFruDetailReq->FruReq]->FRUName);
        pAMIFruDetailRes->CompletionCode = CC_NORMAL;
        return sizeof(AMIGetFruDetailRes_T);	
    }
    else
    {
        pAMIFruDetailRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
        return sizeof(AMIGetFruDetailRes_T);	
    }	
    return 0;	
}

/**
 * *@fn AMISetTriggerEvent
 * *@brief This command is used to enable/disable trigger event based on the parameter input
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int AMISetTriggerEvent( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst )
{
    _NEAR_ AMISetTriggerEventReq_T *pAMISetTriggerEventReq = (AMISetTriggerEventReq_T *)pReq;
    _NEAR_ AMISetTriggerEventRes_T *pAMISetTriggerEventRes = (AMISetTriggerEventRes_T *)pRes;
    INT32U LocalTime,TriggerTime;
    INT32U TriggerLength = 0;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    TriggerLength = TriggerEventParamLength[pAMISetTriggerEventReq->TriggerParam-1];

    if(TriggerLength != 0)
    {
        if((ReqLen - 1) != TriggerLength)
        {
            *pRes = CC_REQ_INV_LEN;
            TDBG("Your entered Parameter %d is not a valid data \n",pAMISetTriggerEventReq->TriggerParam);
            return sizeof (INT8U);
        }
    }
    else
    {
         *pRes = CC_INV_DATA_FIELD;
           return sizeof(INT8U);
    }
    if(1< pAMISetTriggerEventReq->EnableDisableFlag)
    {
        *pRes = CC_INV_DATA_FIELD;
        printf("Your entered Parameter %d is not a valid data \n",pAMISetTriggerEventReq->TriggerParam);
        return sizeof (INT8U);
    }

    switch(pAMISetTriggerEventReq->TriggerParam)
    {
        case CRITICAL:
            pBMCInfo->TriggerEvent.CriticalFlag = pAMISetTriggerEventReq->EnableDisableFlag;
            break;
        case NON_CRITICAL:
            pBMCInfo->TriggerEvent.NONCriticalFlag = pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case NON_RECOVERABLE:
              pBMCInfo->TriggerEvent.NONRecoverableFlag= pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case FAN_TROUBLED:
              pBMCInfo->TriggerEvent.FanTroubled= pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case BMC_WDT_EXPIRE:
              pBMCInfo->TriggerEvent.WDTTimeExpire = pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case SYS_DC_ON:
              pBMCInfo->TriggerEvent.SysDConFlag= pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case SYS_DC_OFF:
              pBMCInfo->TriggerEvent.SysDCoffFlag= pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case SYS_RESET:
              pBMCInfo->TriggerEvent.SysResetFlag = pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case SPEC_DATE_TIME:
              if(pAMISetTriggerEventReq->EnableDisableFlag)
              {
                  if(UNSPECIFIED_UTC_OFFSET == ((INT16)pBMCInfo->GenConfig.SELTimeUTCOffset))
                  {
                      LocalTime = GET_SYSTEM_TIME_STAMP ();
                  }
                  else
                  {
                      LocalTime = GET_SYSTEM_TIME_STAMP() + (((INT16)pBMCInfo->GenConfig.SELTimeUTCOffset) * 60);
                  }

                  TriggerTime = ipmitoh_u32(pAMISetTriggerEventReq->TriggerData.Time);
                  if(TriggerTime<LocalTime)
                  {
                      TDBG("Invalid Time Specified\n");
                     *pRes = OEMCC_INV_DATE_TIME;
                          return sizeof(INT8U);
                  }
                  pBMCInfo->TriggerEvent.Time = pAMISetTriggerEventReq->TriggerData.Time;
              }
              pBMCInfo->TriggerEvent.SpecDateTime = pAMISetTriggerEventReq->EnableDisableFlag;
              break;
          case LPC_RESET_FLAG:
        	  pBMCInfo->TriggerEvent.LPCResetFlag = pAMISetTriggerEventReq->EnableDisableFlag;
        	  break;
           default:
                  pAMISetTriggerEventRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
                  return sizeof(INT8U);
       }

       pAMISetTriggerEventRes->CompletionCode = CC_NORMAL;
       FlushIPMI((INT8U*)&pBMCInfo->TriggerEvent,(INT8U*)&pBMCInfo->TriggerEvent,pBMCInfo->IPMIConfLoc.TriggerEventAddr,
                         sizeof(TriggerEventCfg_T),BMCInst);
       return sizeof(*pAMISetTriggerEventRes);
  }

/**
 * *@fn AMIGetTriggerEvent
 * *@brief This command is used to get the enable/disable trigger event based on the parameter input
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int AMIGetTriggerEvent( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst )
{
    _NEAR_ AMIGetTriggerEventReq_T *pAMIGetTriggerEventReq = (AMIGetTriggerEventReq_T *)pReq;
    _NEAR_ AMIGetTriggerEventRes_T *pAMIGetTriggerEventRes = (AMIGetTriggerEventRes_T *)pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    pAMIGetTriggerEventRes->AMIGetTriggerEvent.CompletionCode = CC_NORMAL;

    switch(pAMIGetTriggerEventReq->TriggerParam)
    {
        case CRITICAL:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.CriticalFlag;
            return sizeof(AMIGetTriggerEvent_T);
        case NON_CRITICAL:
           pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.NONCriticalFlag;
            return sizeof(AMIGetTriggerEvent_T);
        case NON_RECOVERABLE:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.NONRecoverableFlag;
            return sizeof(AMIGetTriggerEvent_T);
        case FAN_TROUBLED:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.FanTroubled;
            return sizeof(AMIGetTriggerEvent_T);
        case BMC_WDT_EXPIRE:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.WDTTimeExpire;
            return sizeof(AMIGetTriggerEvent_T);
        case SYS_DC_ON:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.SysDConFlag;
            return sizeof(AMIGetTriggerEvent_T);
        case SYS_DC_OFF:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.SysDCoffFlag;
            return sizeof(AMIGetTriggerEvent_T);
        case SYS_RESET:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag = pBMCInfo->TriggerEvent.SysResetFlag;
            return sizeof(AMIGetTriggerEvent_T);
        case SPEC_DATE_TIME:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag =pBMCInfo->TriggerEvent.SpecDateTime;
            pAMIGetTriggerEventRes->TriggerData.Time =pBMCInfo->TriggerEvent.Time;
            if(pBMCInfo->TriggerEvent.Time == 0)
               pAMIGetTriggerEventRes->TriggerData.Time = GET_SYSTEM_TIME_STAMP();
            return sizeof(AMIGetTriggerEvent_T)+sizeof(pAMIGetTriggerEventRes->TriggerData.Time);
        case LPC_RESET_FLAG:
        	pAMIGetTriggerEventRes->AMIGetTriggerEvent.EnableDisableFlag =pBMCInfo->TriggerEvent.LPCResetFlag;
        	return sizeof(AMIGetTriggerEvent_T);
        default:
            pAMIGetTriggerEventRes->AMIGetTriggerEvent.CompletionCode = CC_PARAM_NOT_SUPPORTED;
            return sizeof(INT8U);
    }

    pAMIGetTriggerEventRes->AMIGetTriggerEvent.CompletionCode = CC_INV_DATA_FIELD;
   return sizeof(INT8U);
}

/**
 * *@fn AMIGetSolConf
 * *@brief This command is used to get the SOL configuration
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int AMIGetSolConf( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst )
{
     _NEAR_ AMIGetSOLConfRes_T *pAMIGetSOLConfRes = (AMIGetSOLConfRes_T *)pRes;
     BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
     INTU strsize = 0;
     
     memset(pRes,0,sizeof(AMIGetSOLConfRes_T));
	 
     pAMIGetSOLConfRes->SolSessionTimeout = pBMCInfo->IpmiConfig.SOLSessionTimeOut;
     TDBG("SOL Session Timeout is %d \n",pAMIGetSOLConfRes->SolSessionTimeout);

     strsize = strlen(pBMCInfo->IpmiConfig.pSOLPort);
     strncpy(pAMIGetSOLConfRes->SolIfcPort,pBMCInfo->IpmiConfig.pSOLPort,strsize);
     pAMIGetSOLConfRes->SolIfcPort[strsize] = '\0';
     TDBG("SOL Port Configuration is %s \n",pAMIGetSOLConfRes->SolIfcPort);
     
     pAMIGetSOLConfRes->CompletionCode = CC_NORMAL;
     return sizeof(AMIGetSOLConfRes_T);
}

/**
 * *@fn AMISetLoginAuditConfig
 * *@brief This command is used to enable/disable login audit based on the parameter input
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int AMISetLoginAuditConfig( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst )
{
    _NEAR_ AMISetLoginAuditCfgReq_T *pAMISetLoginAuditCfgReq = (AMISetLoginAuditCfgReq_T *)pReq;
    _NEAR_ AMISetLoginAuditCfgRes_T *pAMISetLoginAuditCfgRes = (AMISetLoginAuditCfgRes_T *)pRes;

    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    
    /* Chk request Length */
    if(ReqLen != sizeof(AMISetLoginAuditCfgReq_T) )
    {
        *pRes = CC_REQ_INV_LEN;
        return sizeof (INT8U);
    }

    /* Check Reserved bits */
    if( (pAMISetLoginAuditCfgReq->WebLogAuditCfg & 0xF0) || (pAMISetLoginAuditCfgReq->IPMILogAuditCfg & 0xF0)
        || (pAMISetLoginAuditCfgReq->TelnetLogAuditCfg & 0xF0) ||  (pAMISetLoginAuditCfgReq->SSHLogAuditCfg & 0xF0) 
        || (pAMISetLoginAuditCfgReq->KVMLogAuditCfg & 0xF0)) 
    {
        *pRes = CC_INV_DATA_FIELD;
         return sizeof(INT8U);    	
    }


    pBMCInfo->LoginAuditCfg.WebEventMask = pAMISetLoginAuditCfgReq->WebLogAuditCfg;
    pBMCInfo->LoginAuditCfg.IPMIEventMask = pAMISetLoginAuditCfgReq->IPMILogAuditCfg;
    pBMCInfo->LoginAuditCfg.TelnetEventMask = pAMISetLoginAuditCfgReq->TelnetLogAuditCfg;
    pBMCInfo->LoginAuditCfg.SSHEventMask = pAMISetLoginAuditCfgReq->SSHLogAuditCfg;
    pBMCInfo->LoginAuditCfg.KVMEventMask = pAMISetLoginAuditCfgReq->KVMLogAuditCfg;

    FlushIPMI((INT8U*)&pBMCInfo->LoginAuditCfg,(INT8U*)&pBMCInfo->LoginAuditCfg,pBMCInfo->IPMIConfLoc.LoginAuditCfgAddr,
                      sizeof(LoginAuditConfig_T),BMCInst);
    pAMISetLoginAuditCfgRes->CompletionCode = CC_NORMAL;   
    return sizeof(AMISetLoginAuditCfgRes_T);     

  }

/**
 * *@fn AMIGetLoginAuditConfig
 * *@brief This command is used to get the enable/disable login audit based on the parameter input
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int AMIGetLoginAuditConfig( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst )
{

    _NEAR_ AMIGetLoginAuditCfgRes_T *pAMIGetLoginAuditCfgRes = (AMIGetLoginAuditCfgRes_T *)pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    
    /* Chk request Length */
    if( ReqLen )
    {
        *pRes = CC_REQ_INV_LEN;
        return sizeof (INT8U);
    }    

    pAMIGetLoginAuditCfgRes->CompletionCode = CC_NORMAL;
    pAMIGetLoginAuditCfgRes->WebLogAuditCfg = pBMCInfo->LoginAuditCfg.WebEventMask;
    pAMIGetLoginAuditCfgRes->IPMILogAuditCfg = pBMCInfo->LoginAuditCfg.IPMIEventMask;
    pAMIGetLoginAuditCfgRes->TelnetLogAuditCfg = pBMCInfo->LoginAuditCfg.TelnetEventMask;
    pAMIGetLoginAuditCfgRes->SSHLogAuditCfg = pBMCInfo->LoginAuditCfg.SSHEventMask;
    pAMIGetLoginAuditCfgRes->KVMLogAuditCfg = pBMCInfo->LoginAuditCfg.KVMEventMask;
    return sizeof(AMIGetLoginAuditCfgRes_T);
}

/**
 **@fn AMIGetAllIPv6Address
 **@brief This command is used to get the ipv6 address 
 **@param pReq - Request for the command
 **@param ReqLen - Request length for the command
 **@param pRes - Response for the command
 **@param BMCInst - BMC Instance Value
 **/
int 
AMIGetAllIPv6Address ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes ,int BMCInst)
{
    INT8U EthIndex;
    INT8U netindex= 0xFF;
    INT8U i =0;
    char IfcName[16];
    NWCFG_STRUCT        NWConfig;
    NWCFG6_STRUCT      NWConfig6;
    AMIGetIPv6AddrReq_T *pAMIGetIPv6AddrReq = (AMIGetIPv6AddrReq_T *)pReq;
    AMIGetIPv6AddrRes_T *pAMIGetIPv6AddrRes = (AMIGetIPv6AddrRes_T *)pRes;

    if ((sizeof (pAMIGetIPv6AddrRes->GlobalPrefix) < pAMIGetIPv6AddrReq->IPCnt) || \
          ((pAMIGetIPv6AddrReq->IPCnt + pAMIGetIPv6AddrReq->Index) > sizeof (pAMIGetIPv6AddrRes->GlobalIPAddr[0])))
    {
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }

    EthIndex= GetEthIndex(pAMIGetIPv6AddrReq->ChannelNum & 0x0F, BMCInst);
    if(0xff == EthIndex)
    {
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }

    memset(IfcName,0,sizeof(IfcName));
    /*Get the EthIndex*/
    if(GetIfcName(EthIndex,IfcName, BMCInst) == -1)
    {
        TCRIT("Error in Getting Ifc name\n");
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }

//    for(i=0;i<sizeof(Ifcnametable)/sizeof(IfcName_T);i++)
//    {
//        if(strcmp(Ifcnametable[i].Ifcname,IfcName) == 0)
//        {
//            netindex= Ifcnametable[i].Index;
//            break;
//        }
//    }

    if(netindex == 0xFF)
    {
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }
    memset(pAMIGetIPv6AddrRes,0,sizeof(AMIGetIPv6AddrRes_T));
    pAMIGetIPv6AddrRes->CompletionCode = 0;
    nwReadNWCfg_v4_v6( &NWConfig, &NWConfig6, netindex,g_corefeatures.global_ipv6);
    memcpy (pAMIGetIPv6AddrRes->GlobalIPAddr, &NWConfig6.GlobalIPAddr[pAMIGetIPv6AddrReq->Index], (pAMIGetIPv6AddrReq->IPCnt *sizeof (pAMIGetIPv6AddrRes->GlobalIPAddr[0])));
    memcpy (&pAMIGetIPv6AddrRes->GlobalPrefix, &NWConfig6.GlobalPrefix[pAMIGetIPv6AddrReq->Index], (pAMIGetIPv6AddrReq->IPCnt *sizeof (pAMIGetIPv6AddrRes->GlobalPrefix[0])));
    return sizeof(AMIGetIPv6AddrRes_T);
}

/**
 * *@fn ValidateUsrInput
 * *@brief This function validates the user input..
 * *@param pAMISetPamReq - Req from the user.
 * *@returns 0 on success
 * *              -1 on failure
 **/
int 
ValidateUsrInput (AMISetPamReq_T *pAMISetPamReq)
{
    INT8U Index = 0;
    INT8U Cntr = 0;

    for (Index = 0;Index < MODULES_TO_MODIFIED; Index++)
    {
         /* check for value which is greater than order length*/
        if ((pAMISetPamReq->Sqnce [Index] > MODULES_TO_MODIFIED) || (pAMISetPamReq->Sqnce [Index] < 1))
        {
            TDBG ("Value exceeds the length %d \n", pAMISetPamReq->Sqnce[Index]);
            return ERR_RETRN;
        }
        
        for (Cntr =Index + 1; Cntr < MODULES_TO_MODIFIED; Cntr++)
        {
            /*Check for Duplicate value */
            if ((pAMISetPamReq->Sqnce[Index]==pAMISetPamReq->Sqnce[Cntr]))
            {
                TDBG ("Duplicate value %d \n", pAMISetPamReq->Sqnce[Index]);
                 return ERR_RETRN;
            }
        }
    }
    return 0;
}

/**
 * *@fn GetPamOrder
 * *@brief This function is used to get PAM authentication order sequence (ipmi ldap ad).
 * *@param FileName - name of the file to get the seqence.
 * *@param FileOrder - Used to hold the sequence order.
 * *@returns 0 on success
 * *              -1 on failure
 **/

int 
GetPamOrder (char *FileName, INT8U *FileOrder)
{
    FILE *pfptr;
    char LineBuf [PAM_BUF_LEN];
    INT8U Cnt=0, Index =0, Ndx = 0, Mcnt = 0;
    INT8U TmpBuf [MODULES_TO_MODIFIED + MODULES_TO_MODIFIED];

    pfptr = fopen (FileName, "r");
    if (NULL == pfptr)
    {
       TDBG ("Enable to open %s  file\n", FileName);
       return -1;
    }

    memset (TmpBuf, 0, (2*MODULES_TO_MODIFIED));
    while (!feof(pfptr))
    {
        memset (LineBuf, 0, PAM_BUF_LEN);
        if(NULL == fgets (LineBuf, PAM_BUF_LEN, pfptr))
        {
            continue;
        }
        for (Index = 0;Index < (sizeof (g_DfaultOrder) /sizeof (PamOrder_T)); Index++)
        {
             /*Read the order from file according to Section and store it an array*/
             if (NULL != strstr (LineBuf, g_DfaultOrder[Index].PamModule))
            {
                /*Check the PAM order for Auth section*/
                if (NULL != strstr (LineBuf, "auth"))
                {
                    FileOrder[Cnt] = g_DfaultOrder[Index].SqnceNo;
                    Cnt++;
                    break;
                }
                /*Check the PAM order for Account section*/
                else if (NULL != strstr (LineBuf, "account"))
                {
                    TmpBuf [Ndx] = g_DfaultOrder[Index].SqnceNo;
                    Ndx++;
                    break;
                }
                /*Check the PAM order for Password section*/
                else if (NULL != strstr (LineBuf, "password"))
                {
                    TmpBuf [MODULES_TO_MODIFIED + Mcnt] = g_DfaultOrder[Index].SqnceNo;
                    Mcnt++;
                    break;
                }
            }
        }
    }

     /*Compare All the orders */
    for (Index = 0;Index < (sizeof (g_DfaultOrder) /sizeof (PamOrder_T)); Index++)
    {
        if ((FileOrder [Index] != TmpBuf  [Index]) || (FileOrder [Index] != TmpBuf [MODULES_TO_MODIFIED + Index]))
        {
            fclose(pfptr);	
             return ERR_RETRN;
        }
    }

    fclose (pfptr);
    return 0;
}

/**
 * *@fn CompPamOrder
 * *@brief This function Compares the new pam order with existing order.
 * *@param FileOrder - Existing pam order.
 * *@param FileOrder - New PAM order.
 * *@returns 0 if two orders are equal.
 * *               1 if orders are not equal.
 **/
int 
CompPamOrder (INT8U *FileOrder, INT8U *NewOrder)
{
    INT8U Index = 0;
    for (Index = 0;Index < (sizeof (g_DfaultOrder) /sizeof (PamOrder_T)); Index++)
    {
         if (FileOrder [Index] != NewOrder[Index])
               return 1;
    }
    return 0;
}

/**
 * *@fn SetPamOrder
 * *@brief This function Set the new pam order..
 * *@param FileName - Name of the file.
 * *@param pAMISetPamReq - New pam sequence from user.
 * *@returns 0 on success
 * *              -1 on failure
 **/
int 
SetPamOrder (char *FileName, AMISetPamReq_T *pAMISetPamReq)
{
    FILE *pPamfd, *pNewfd;
    char TmpBuf [PAM_BUF_LEN];
    char LineBuf [PAM_BUF_LEN];
    char *ptr;
    INT8U  Order=0, Cnt=0;
    INT8U Flag=0, Index =0;

    pPamfd = fopen (FileName, "r");
    if (NULL == pPamfd)
    {
       TDBG ("Enable to open %s  file\n", FileName);
       return ERR_RETRN;
    }

    pNewfd = fopen ("/conf/pam_tmpfile", "w");
    if (NULL == pNewfd)
    {
        fclose(pPamfd);	
       TDBG ("Enable to create %s  file\n", "pam_tmpfile");
       return -1;
    }

    while (!feof(pPamfd))
    {
        memset (LineBuf, 0, PAM_BUF_LEN);
        if(NULL == fgets (LineBuf, PAM_BUF_LEN, pPamfd))
        {
            continue;
        }
        Flag = 0;
        for (Index = 0;Index < MODULES_TO_MODIFIED; Index++)
        {
            memset (TmpBuf, 0, PAM_BUF_LEN);
            /*Replace the old sequence with new order*/
            if (NULL != (ptr = strstr (LineBuf, g_DfaultOrder[Index].PamModule)))
            {
                strncpy (TmpBuf, LineBuf, (ptr-LineBuf));
                Order = pAMISetPamReq->Sqnce[Cnt];
                strcat (TmpBuf, g_DfaultOrder[Order -1].PamModule);
                Cnt ++;
                if (Cnt == MODULES_TO_MODIFIED)
                    Cnt = 0;
                Flag = 1;
                break;
            }
        }

        if (Flag)
            fprintf (pNewfd,"%s\n", TmpBuf);
        else
            fprintf (pNewfd,"%s", LineBuf);
    }

    fclose (pNewfd);
    fclose (pPamfd);
    rename("/conf/pam_tmpfile", FileName);
    return 0;
}

/**
 * *@fn SetPamOrder
 * *@brief This function Set the new pam order..
 * *@param FileName - Name of the file.
 * *@param pAMISetPamReq - New pam sequence from user.
 * *@param FileOrder - Existing pam auth sequence order.
 **/
int SetNssFileOrder (char *FileName, AMISetPamReq_T *pAMISetPamReq, INT8U *FileOrder)
{
    char TmpBuf [PAM_BUF_LEN];
    char LineBuf [PAM_BUF_LEN];
    FILE *pPamfd, *pNewfd;
    char *ptr;
    INT8U Order=0;
    INT8U Index =0;

     pPamfd = fopen (FileName, "r");
    if (NULL == pPamfd)
    {
       TDBG ("Enable to open %s  file\n", FileName);
       return ERR_RETRN;
    }

    pNewfd = fopen ("/conf/pam_tmpfile", "w");
    if (NULL == pNewfd)
    {
        fclose(pPamfd);	
       TDBG ("Enable to create %s  file\n", "pam_tmpfile");
       return -1;
    }

    memset (LineBuf, 0, PAM_BUF_LEN);
    memset (TmpBuf, 0, PAM_BUF_LEN);    
    if (NULL == fgets (LineBuf, PAM_BUF_LEN, pPamfd))
    {
        fclose(pPamfd);
        fclose(pNewfd);
        return ERR_RETRN;
    }
    Order = FileOrder[0];
    if (NULL != (ptr = strstr (LineBuf, g_NssOrder[Order -1].PamModule)))
    {
        strncpy (TmpBuf, LineBuf, (ptr-LineBuf));
    }

    for (Index = 0;Index < (sizeof (g_DfaultOrder) /sizeof (PamOrder_T));Index++)
    {
         Order = pAMISetPamReq->Sqnce[Index];
         strcat (TmpBuf, g_NssOrder[Order -1].PamModule);
         strcat (TmpBuf, " ");
    }

    Order = FileOrder[Index -1];
    if (NULL != (ptr = (strstr (LineBuf, g_NssOrder[Order - 1].PamModule))+strlen(g_NssOrder[Order - 1].PamModule)))
    {
        Order = strlen (g_NssOrder[Order - 1].PamModule);
        strcat (TmpBuf, LineBuf + (ptr-LineBuf) + Order);
    }

    fprintf (pNewfd,"%s\n", TmpBuf);
    fclose (pNewfd);
    fclose (pPamfd);
    rename( "/conf/pam_tmpfile", FileName);
    return 0;
}


/**
 * *@fn ArrangOrder
 * *@brief This command is used to to arrange the values to assending order
 * *@param FileOrder - array to store the cuurent order.
 **/

void 
ArrangOrder (INT8U *FileOrder)
{
    INT8U Index =0,Tmp=0, Cntr =0;

    for(Index = 0; Index < sizeof (g_NssOrder)/ sizeof (PamOrder_T); Index++)
   {
        for(Cntr = 0; Cntr < (sizeof (g_NssOrder)/ sizeof (PamOrder_T))-1; Cntr++)
        {
            if(FileOrder[Cntr]> FileOrder[Cntr + 1]) 
            {
                 Tmp = FileOrder[Cntr + 1];
                 FileOrder[Cntr + 1] = FileOrder[Cntr];
                 FileOrder[Cntr] = Tmp;
            }
       }
    }
}

/**
 * *@fn GetNssOrder
 * *@brief This command is used to get NSS sequence (ipmi ldap ad).
 * *@param FileName - Name of the file
 * *@param FileOrder - array to store the cuurent order.
 * *@returns 0 on success
 * *              -1 on failure
 **/
int GetNssOrder (char *FileName, INT8U *FileOrder)
{
    char LineBuf [PAM_BUF_LEN];
    FILE *pPamfd;
    char *ptr = NULL;
    INT8U Index =0,Cntr = 0;
    INT8U TmpBuf [MODULES_TO_MODIFIED];

     pPamfd = fopen (FileName, "r");
    if (NULL == pPamfd)
    {
       TDBG ("Enable to open %s  file\n", FileName);
       return ERR_RETRN;
    }

    memset (LineBuf, 0, PAM_BUF_LEN);
    if (NULL == fgets (LineBuf, PAM_BUF_LEN, pPamfd))
    {
        fclose(pPamfd);
        return ERR_RETRN;
    }

    /*Find the position of the strings (ipmi ldap ad)*/
    for (Index = 0;Index < sizeof (g_NssOrder)/ sizeof (PamOrder_T); Index++)
    {
         if (NULL != (ptr = strstr (LineBuf, g_NssOrder[Index].PamModule)))
         {
             TmpBuf [Cntr] = (ptr -LineBuf);
             Cntr ++;
         }
    }

    if (Cntr != sizeof (g_NssOrder)/ sizeof (PamOrder_T))
    {
        TDBG ("One of the Module not found");
         fclose(pPamfd);
         return ERR_RETRN;
    }

    /* arrenge into assending order*/
    ArrangOrder (TmpBuf);
    Cntr = 0;
    while (Cntr <sizeof (g_NssOrder)/ sizeof (PamOrder_T) )
    {
        for (Index = 0;Index < sizeof (g_NssOrder)/ sizeof (PamOrder_T); Index++)
        {
            if (0 == strncmp (LineBuf + TmpBuf [Cntr], g_NssOrder[Index].PamModule, strlen (g_NssOrder[Index].PamModule)))
            {
                FileOrder[Cntr] = Index + 1;
                Cntr ++;
                break;
            }
        }
    }

    fclose(pPamfd);

    return 0;
}


int 
GetAllFilesOrder (AMIGetPamRes_T *pAMIGetPamRes)
{
    INT8U TmpBuf [MODULES_TO_MODIFIED];

    /*Get the PAM sequence order for file pam_wounix*/
    if (ERR_RETRN == GetPamOrder (PAM_WOUNIX_FILE, pAMIGetPamRes->Seqnce))
    {
         TDBG ("Pam order bw different sec are %s not same\n", PAM_WOUNIX_FILE);
         pAMIGetPamRes->CompletionCode = CC_PAM_ORDER_SEC_DIFERS;
         return ERR_RETRN;
    }
    
    /*Get the PAM sequence order for file pam_witunix*/
    if (ERR_RETRN == GetPamOrder (PAM_WITHUNIX_FILE, TmpBuf))
    {
         TDBG ("Pam order bw different sec are %s not same\n", PAM_WITHUNIX_FILE);
         pAMIGetPamRes->CompletionCode = CC_PAM_ORDER_SEC_DIFERS;
         return ERR_RETRN;
    }

    /*Verify All the orders are Same */
     if (1 == CompPamOrder (TmpBuf, pAMIGetPamRes->Seqnce))
     {
         TDBG ("Orders are not same for files %s & %s \n", PAM_WOUNIX_FILE, PAM_WITHUNIX_FILE);
         pAMIGetPamRes->CompletionCode = CC_PAM_ORDER_FILE_DIFERS;
         return ERR_RETRN;
     }

    /*Get the NSS sequence order for nsswitch file */
    if (ERR_RETRN == GetNssOrder (PAM_NSSWITCH_FILE, pAMIGetPamRes->Seqnce))
    {
         TDBG ("Pam order bw different sec are %s not same\n", PAM_NSSWITCH_FILE);
         pAMIGetPamRes->CompletionCode = CC_PAM_ORDER_SEC_DIFERS;
         return ERR_RETRN;
    }

    /*Verify All the orders are Same */
    if (1 == CompPamOrder (TmpBuf, pAMIGetPamRes->Seqnce))
    {
        TDBG ("Orders are not same for files %s & %s \n", PAM_WOUNIX_FILE, PAM_NSSWITCH_FILE);
        pAMIGetPamRes->CompletionCode = CC_PAM_ORDER_FILE_DIFERS;
        return ERR_RETRN;
    }
    return 0;
}

/**
 * *@fn AMIGetPamOrder
 * *@brief This command is used to get PAM authentication order sequence (ipmi ldap ad).
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int 
AMIGetPamOrder ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMIGetPamRes_T *pAMIGetPamRes = (AMIGetPamRes_T *)pRes;
    
    if(g_corefeatures.pam_reorder == ENABLED)
    {
 
        if (ERR_RETRN == GetAllFilesOrder (pAMIGetPamRes))
        {
            return sizeof (AMISetPamRes_T);
        }
        pAMIGetPamRes->CompletionCode = CC_NORMAL;
    }
    else
    {
        pAMIGetPamRes->CompletionCode = CC_INV_CMD;
    }

    return sizeof (AMIGetPamRes_T);
}

/**
 * *@fn SetPamSqnceOrder
 * *@brief This function Set the new pam order..
 * *@param FileName - Name of the file.
 * *@param pAMISetPamReq - New pam sequence from user.
 * *@returns 0 on success
 **/
int
SetPamSqnceOrder (char *FileName, AMISetPamReq_T *pAMISetPamReq)
{
    INT8U FileOrder [MODULES_TO_MODIFIED];

    /*Get the authentication sequence order from the file */
    if (ERR_RETRN == GetPamOrder (FileName, FileOrder))
    {
         SetPamOrder (FileName, pAMISetPamReq);
         return 0;
    }

    /*Compare the PAM orders if same , do not reorder*/
     if (0 == CompPamOrder (FileOrder, pAMISetPamReq->Sqnce))
     {
         TDBG ("PAM auth orders  are same\n");
         return 1;
     }

    /*reorder the files according to the user input */
    SetPamOrder (FileName, pAMISetPamReq);
    return 0;
}


/**
 * *@fn SetNssSqnceOrder
 * *@brief This function Set the new NSS order..
 * *@param FileName - Name of the file.
 * *@param pAMISetPamReq - New pam sequence from user.
 * *@returns 0 on success
 **/
 
int
SetNssSqnceOrder (char *FileName, AMISetPamReq_T *pAMISetPamReq)
{
    INT8U TmpBuf [MODULES_TO_MODIFIED];

    memset (TmpBuf, 0 , MODULES_TO_MODIFIED);
    if (ERR_RETRN == GetNssOrder (FileName, TmpBuf))
    {
        SetNssFileOrder (FileName, pAMISetPamReq, TmpBuf);
        return 0;
    }
    
    /*Compare the PAM orders if same , do not reorder*/
    if (0 == CompPamOrder (pAMISetPamReq->Sqnce, TmpBuf))
    {
        TDBG ("PAM auth orders  are same\n");
        return 1;
    }
    SetNssFileOrder (FileName, pAMISetPamReq, TmpBuf);
    return 0;
}


/**
 * *@fn AMISetPamOrder
 * *@brief This command is used to set PAM authentication sequence order(ipmi ldap ad).
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int 
AMISetPamOrder ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,int BMCInst)
{
    AMISetPamRes_T *pAMISetPamRes = (AMISetPamRes_T *)pRes;
    INT8U *curchannel;

    if(g_corefeatures.pam_reorder == ENABLED)
    {
        int ret;
        RestartService_T Service;
        AMISetPamReq_T *pAMISetPamReq = (AMISetPamReq_T *)pReq;
        AMIGetPamRes_T pAMIGetPamRes;
    
        memset (&pAMIGetPamRes, 0, sizeof (AMIGetPamRes_T));

        if (ERR_RETRN == ValidateUsrInput (pAMISetPamReq))
        {
            TDBG ("In-Valid  user input\n");
            *pRes = CC_INV_DATA_FIELD;
            return sizeof (AMISetPamRes_T);
        }
    
        /*Check the previous and New order if same, return without changing the order*/
         if (0 == GetAllFilesOrder (&pAMIGetPamRes))
        {
             if (0 == CompPamOrder (pAMIGetPamRes.Seqnce, pAMISetPamReq->Sqnce))
             {
                 TDBG ("PAM auth orders  are same\n");
                 *pRes = CC_SAME_PAM_ORDER;
                 return sizeof (AMISetPamRes_T);
             }
        }
    
        SetPamSqnceOrder (PAM_WOUNIX_FILE, pAMISetPamReq);
        SetPamSqnceOrder (PAM_WITHUNIX_FILE, pAMISetPamReq);
        ret=SetNssSqnceOrder (PAM_NSSWITCH_FILE, pAMISetPamReq);
        if(ret == 0)
        {
              Service.ServiceName = WEBSERVER;
              SetPendStatus(PEND_OP_RESTART_SERVICES, PEND_STATUS_PENDING);    
              OS_THREAD_TLS_GET(g_tls.CurChannel,curchannel);
              PostPendTask(PEND_OP_RESTART_SERVICES, (INT8U *) &Service, 1, *curchannel & 0xF,BMCInst);
        }
    
        pAMISetPamRes->CompletionCode = CC_NORMAL;
    }
    else
    {
        pAMISetPamRes->CompletionCode = CC_INV_CMD;
    }
    return sizeof (AMISetPamRes_T);
}

typedef struct {
    INT8U Length;
} PACKED FWConfParams_T;

FWConfParams_T FWConfParams[] = {
    { 0 },
    { 200 },
    { 200 },
    { 1 },
    { 1 }
};

/**
 * *@fn AMIStartTFTPFwUpdate
 * *@brief This command is used to start  application to do firmware update
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMIStartTFTPFwUpdate ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMIStartFwUpdateReq_T *pAMIStartFwUpdateReq = (AMIStartFwUpdateReq_T *)pReq;
    AMIStartFwUpdateRes_T *pAMIStartFwUpdateRes = (AMIStartFwUpdateRes_T *)pRes;
    FirmwareConfig_T FwConfig;
    INT8U *curchannel;

    if(IsCardInFlashMode()) {
        pAMIStartFwUpdateRes->CompletionCode = CC_DEV_IN_FIRMWARE_UPDATE_MODE;
        return sizeof(INT8U);
    }

     if(g_corefeatures.fwupdate_protocol_select == CORE_FEATURE_ENABLED)
    {
        getFirmwareConfig(&FwConfig);

        if((!FwConfig.Protocol.tftp.Host[0]) ||
           (!FwConfig.Protocol.tftp.RemoteFilePath[0])) {
            pAMIStartFwUpdateRes->CompletionCode = CC_OP_NOT_ALLOWED;
            return sizeof(INT8U);
        }

        FwConfig.Protocol.tftp.PreserveCfg = pAMIStartFwUpdateReq->PreserveCfg;

        IPMI_DBG_PRINT("Starting TFTP firmware update...\n");
        SetPendStatus(PEND_OP_START_FW_UPDATE_TFTP, PEND_STATUS_PENDING);
        setFirmwareConfig(&FwConfig);
        OS_THREAD_TLS_GET(g_tls.CurChannel,curchannel);
        PostPendTask(PEND_OP_START_FW_UPDATE_TFTP, (INT8U*)&FwConfig, sizeof(FirmwareConfig_T), 
                         *curchannel & 0xF, BMCInst);
        LOCK_BMC_SHARED_MEM(BMCInst);
        g_MBMCInfo.FlashType= TFTP_FLASH;
        UNLOCK_BMC_SHARED_MEM(BMCInst);
        pAMIStartFwUpdateRes->CompletionCode = CC_NORMAL;
        return sizeof(AMIStartFwUpdateRes_T);
    }
    else
    {
        pAMIStartFwUpdateRes->CompletionCode = CC_INV_CMD;
        return sizeof(INT8U);
    }
}

int
AMIGetTftpProgressStatus( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    STRUCTURED_PROGRESS_STATUS prog;
    AMIGetTftpProgressStatusRes_T *pAMIGetTftpProgressStatusRes = (AMIGetTftpProgressStatusRes_T *)pRes;

/* 
    if(!IsCardInFlashMode()) {
        pAMIGetTftpProgressStatusRes->CompletionCode = CC_COULD_NOT_PROVIDE_RESP;
        return sizeof(INT8U);
    }
*/
     if(g_corefeatures.fwupdate_protocol_select == CORE_FEATURE_ENABLED)
    {
        memset(&prog, 0, sizeof(STRUCTURED_PROGRESS_STATUS));
        pAMIGetTftpProgressStatusRes->CompletionCode = CC_NORMAL;
        GetProgressStatus(&prog);
        pAMIGetTftpProgressStatusRes->Progress = prog.Progress;
        pAMIGetTftpProgressStatusRes->Overall = prog.Overall;
        return sizeof(AMIGetTftpProgressStatusRes_T);
    }
    else
    {
        pAMIGetTftpProgressStatusRes->CompletionCode = CC_INV_CMD;
        return sizeof(INT8U);
    }
}

/**
 * *@fn AMISetFWCfg
 * *@brief This command is used to set configuration of firmware update
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMISetFWCfg ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMISetFWCfgReq_T *pAMISetFWCfgReq = (AMISetFWCfgReq_T *)pReq;
    AMISetFWCfgRes_T *pAMISetFWCfgRes = (AMISetFWCfgRes_T *)pRes;
    int paramTblSize = sizeof(FWConfParams) / sizeof(FWConfParams_T);
    int dataLen = ReqLen - 1;
    int Parameter = pAMISetFWCfgReq->Parameter;
    int Ret = 0;
    char ipaddrstr[INET6_ADDRSTRLEN];
    FirmwareConfig_T FwConfig;
    char nulldata[SET_FIRM_REQ_BYTES]={0};

    if(IsCardInFlashMode()) {
        pAMISetFWCfgRes->CompletionCode = CC_DEV_IN_FIRMWARE_UPDATE_MODE;
        return sizeof(INT8U);
    }

     if(g_corefeatures.fwupdate_protocol_select == CORE_FEATURE_ENABLED)
     {
        if(Parameter >= paramTblSize) {
            pAMISetFWCfgRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
            return sizeof(INT8U);
        }

        if(dataLen != FWConfParams[Parameter].Length) {
            pAMISetFWCfgRes->CompletionCode = CC_REQ_INV_LEN;
            return sizeof(INT8U);
        }

        getFirmwareConfig(&FwConfig);

        switch(Parameter)
        {
            case CONNECTION_INFO_HOST:
                if(memcmp(pAMISetFWCfgReq->Data,nulldata,SET_FIRM_REQ_BYTES))
                {
                    Ret = GetIPAddrstr(pAMISetFWCfgReq->Data,ipaddrstr);
                    if((Ret == -1) || (strcmp(ipaddrstr,INVALID_IP_ADDR) == 0))
                    {
                        TDBG("Error in getting IP address string\n");
                        pAMISetFWCfgRes->CompletionCode = CC_INV_DATA_FIELD;
                        return sizeof(INT8U);
                    }
                }
                memcpy(&FwConfig.Protocol.tftp.Host, &pAMISetFWCfgReq->Data, FWConfParams[Parameter].Length);
            break;
            case CONNECTION_INFO_FILE_PATH:
                memcpy(&FwConfig.Protocol.tftp.RemoteFilePath, &pAMISetFWCfgReq->Data, FWConfParams[Parameter].Length);
            break;
            case CONNECTION_INFO_RETRY:
                memcpy(&FwConfig.Protocol.tftp.Retry, &pAMISetFWCfgReq->Data, FWConfParams[Parameter].Length);
            break;
            case FW_UPDATE_SELECT :
                memcpy(&FwConfig.FlashFWSelect, &pAMISetFWCfgReq->Data, FWConfParams[Parameter].Length);
                if(FwConfig.FlashFWSelect == FW_BMC)
                    safe_system("rm -f /var/bios_update_selection");
                else if (FwConfig.FlashFWSelect == FW_BIOS)
                safe_system("touch /var/bios_update_selection");
            break;
            default:
                pAMISetFWCfgRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
                return sizeof(INT8U);
            break;
        }
        setFirmwareConfig(&FwConfig);

        pAMISetFWCfgRes->CompletionCode = CC_NORMAL;
        return sizeof(AMISetFWCfgRes_T);
    }
    else
    {
        pAMISetFWCfgRes->CompletionCode = CC_INV_CMD;
        return sizeof(INT8U);
    }
}
/**
 * *@fn AMIGetFWCfg
 * *@brief This command is used to get configuration of firmware update
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int 
AMIGetFWCfg ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMIGetFWCfgReq_T *pAMIGetFWCfgReq = (AMIGetFWCfgReq_T *)pReq;
    AMIGetFWCfgRes_T *pAMIGetFWCfgRes = (AMIGetFWCfgRes_T *)pRes;
    FirmwareConfig_T FwConfig;
    int paramTblSize = sizeof(FWConfParams) / sizeof(FWConfParams_T);
    int parameter = pAMIGetFWCfgReq->Parameter;
    int res_size = 0;

    if(IsCardInFlashMode()) {
        pAMIGetFWCfgRes->CompletionCode = CC_DEV_IN_FIRMWARE_UPDATE_MODE;
        return sizeof(INT8U);
    }

     if(g_corefeatures.fwupdate_protocol_select == CORE_FEATURE_ENABLED)
     {
        if(parameter > paramTblSize) {
            pAMIGetFWCfgRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
            return sizeof(INT8U);
        }

        getFirmwareConfig(&FwConfig);
        res_size = sizeof(pAMIGetFWCfgReq->Parameter) + FWConfParams[parameter].Length;
        switch(parameter)
        {
            case CONNECTION_INFO_HOST:
                memcpy(&pAMIGetFWCfgRes->Data, &FwConfig.Protocol.tftp.Host, FWConfParams[parameter].Length);
            break;
            case CONNECTION_INFO_FILE_PATH:
                memcpy(&pAMIGetFWCfgRes->Data, &FwConfig.Protocol.tftp.RemoteFilePath, FWConfParams[parameter].Length);
            break;
            case CONNECTION_INFO_RETRY:
                memcpy(&pAMIGetFWCfgRes->Data, &FwConfig.Protocol.tftp.Retry, FWConfParams[parameter].Length);
            break;
            case FW_UPDATE_SELECT :
                memcpy(&pAMIGetFWCfgRes->Data, &FwConfig.FlashFWSelect, FWConfParams[parameter].Length);
            break;
            default:
                pAMIGetFWCfgRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
                return sizeof(INT8U);
            break;
        }
        pAMIGetFWCfgRes->CompletionCode = CC_NORMAL;
        return res_size;
    }
     else
    {
         pAMIGetFWCfgRes->CompletionCode = CC_INV_CMD;
         return sizeof(INT8U);
    }
}

/**
 * *@fn SetFirmwareProtocol
 * *@brief This command is used to set protocol type of Firmware update
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMISetFWProtocol ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMISetFWProtocolReq_T *pAMISetFWProtocolReq = (AMISetFWProtocolReq_T *)pReq;
    AMISetFWProtocolRes_T *pAMISetFWProtocolRes = (AMISetFWProtocolRes_T *)pRes;
    FirmwareConfig_T FwConfig;

    if(IsCardInFlashMode()) {
        pAMISetFWProtocolRes->CompletionCode = CC_DEV_IN_FIRMWARE_UPDATE_MODE;
        return sizeof(INT8U);
    }

    getFirmwareConfig(&FwConfig);
    if(g_corefeatures.fwupdate_protocol_select == CORE_FEATURE_ENABLED)
    {
        switch(pAMISetFWProtocolReq->ProtocolType)
        {
            case PROTOCOL_HTTP_HTTPS:
                FwConfig.ProtocolType = PROTOCOL_HTTP_HTTPS;
            break;
            case PROTOCOL_TFTP:
                FwConfig.ProtocolType = PROTOCOL_TFTP;
            break;
            default:
                pAMISetFWProtocolRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
                return sizeof(INT8U);
           break;
        }
        setFirmwareConfig(&FwConfig);
        pAMISetFWProtocolRes->CompletionCode = CC_NORMAL;
     }
    else
    {
        pAMISetFWProtocolRes->CompletionCode = CC_INV_CMD;
       
    }
    return sizeof(AMISetFWProtocolRes_T);
}

/**
 * *@fn GetFWProtocol
 * *@brief This command is used to get protocol type of Firmware update
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMIGetFWProtocol ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
//    AMIGetFWProtocolReq_T *pAMIGetFWProtocolReq = (AMIGetFWProtocolReq_T *)pReq;
    AMIGetFWProtocolRes_T *pAMIGetFWProtocolRes = (AMIGetFWProtocolRes_T *)pRes;
    FirmwareConfig_T FwConfig;

    memset(pAMIGetFWProtocolRes,0,sizeof(AMIGetFWProtocolRes_T));
    getFirmwareConfig(&FwConfig);
    pAMIGetFWProtocolRes->ProtocolType = FwConfig.ProtocolType;

    return sizeof(AMIGetFWProtocolRes_T);
}

/**
 * *@fn AMISetPwdEncryptionKey
 * *@brief This command is used to set the password encryption key
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMISetPwdEncryptionKey(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMISetPwdEncKeyReq_T *pAMISetPwdEncKeyReq = (AMISetPwdEncKeyReq_T *)pReq;
    AMISetPwdEncKeyRes_T *pAMISetPwdEncKeyRes = (AMISetPwdEncKeyRes_T *)pRes;
    _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];

    EncryptedUserInfo_T OldEncUserPaswd[MAX_USER_CFG_MDS];
    INT8S EncryptedUserPswd[MAX_ENCRYPTED_PSWD_LEN] = {0};
    INT8S DecryptedUserPswd[MAX_ENCRYPTED_PSWD_LEN] = {0};

    unsigned char oldEncryptKey[MAX_SIZE_KEY + 1] = {0};
    unsigned char newEncryptKey[MAX_SIZE_KEY + 1] = {0};

    Smtp_Config_T* pm_Smtp_Config;
    INT8S decryptedSMTPPswd[MAX_SMTP_PASSWD_LEN] = {0};
    INT8S encryptedSMTPPswd[MAX_SMTP_PASSWD_LEN] = {0};

    int count = 0;
    AD_Config_T adcfg;
    LDAPCONFIG ldapconf;

    /* First take the backup of old encrypted user passwords to revert in case there is a failure in decrypting/encrypting*/
    LOCK_BMC_SHARED_MEM(BMCInst);
        memcpy(&(OldEncUserPaswd[0]), pBMCInfo->EncryptedUserInfo[0].EncryptedPswd, MAX_USER_CFG_MDS * MAX_ENCRYPTED_PSWD_LEN);
    UNLOCK_BMC_SHARED_MEM(BMCInst);		

    if(ReqLen < 1 || ReqLen > MAX_SIZE_KEY)
    {
        TCRIT("AMISetPwdEncryptionKey(): Request length=%d is invalid\n", ReqLen);
        pAMISetPwdEncKeyRes->CompletionCode = CC_REQ_INV_LEN;
        return sizeof(INT8U);
    }
    if(g_corefeatures.userpswd_encryption != ENABLED)
    {
        TCRIT("AMISetPwdEncryptionKey(): Password Encryption Feature is NOT enabled.\n");
        pAMISetPwdEncKeyRes->CompletionCode = CC_INV_CMD;
        return sizeof(INT8U);
    }

    TDBG("AMISetPwdEncryptionKey(): REQUEST Len=%d    Bytes: %s\n", ReqLen, pAMISetPwdEncKeyReq->PwdEncryptKey);

	/* Copy the old/current encryption key to a buffer */
    LOCK_BMC_SHARED_MEM(BMCInst);
        memcpy(oldEncryptKey, &(g_MBMCInfo.PwdEncKey), MAX_SIZE_KEY);
    UNLOCK_BMC_SHARED_MEM(BMCInst);

	/* Copy the new encryption key to a buffer */
    memcpy(newEncryptKey, pAMISetPwdEncKeyReq->PwdEncryptKey, ReqLen);

	/* Do nothing if there is no change in the encryption keys */
    if(memcmp(oldEncryptKey, newEncryptKey, MAX_SIZE_KEY) == 0)
    {
        TCRIT("AMISetPwdEncryptionKey(): Both the new and the existing encryption keys are same.\n");
        pAMISetPwdEncKeyRes->CompletionCode = CC_NORMAL;
        return sizeof(INT8U);
    }

	/* Decrypt all the IPMI User passwords with the old encrypt key and encrypt those with the new encrypt key */
    for(count = 0; count < MAX_USER_CFG_MDS; count++)
    {
        /* Check if User ID is 0; if it is 0, skip the user as there is no need to set the password for empty slots*/
        if((pBMCInfo->UserInfo[count].UserId) == 0)
            continue;	//No need to set the password for empty slots

        /* Check if password is encrypted */
        if(_fmemcmp(pBMCInfo->UserInfo[count].UserPassword, "$ENCRYPTED$", 11) == 0)
        {
        	/* Decrypt the password with old key */
            if(DecryptPassword((INT8S *)(pBMCInfo->EncryptedUserInfo[count].EncryptedPswd), MAX_PASSWORD_LEN, DecryptedUserPswd, MAX_PASSWORD_LEN, oldEncryptKey))
            {
                TCRIT("Error in Decrypting the IPMI User Password for user id = %d \n", count+1);
                goto error;
            }
            /* Encrypt the password with new key */
            if(EncryptPassword(DecryptedUserPswd, MAX_PASSWORD_LEN, EncryptedUserPswd, MAX_PASSWORD_LEN, newEncryptKey))
            {
                TCRIT("Error in Encrypting the IPMI User Password for user with ID = %d..\n", count+1);
                goto error;
            }
            LOCK_BMC_SHARED_MEM(BMCInst);
                memset(&(pBMCInfo->EncryptedUserInfo[count].EncryptedPswd), 0, MAX_ENCRYPTED_PSWD_LEN);
                memcpy(&(pBMCInfo->EncryptedUserInfo[count].EncryptedPswd), EncryptedUserPswd, MAX_ENCRYPTED_PSWD_LEN);
            UNLOCK_BMC_SHARED_MEM(BMCInst);
        }
    }


    	// Get the LDAP Configurations
    memset((unsigned char*)&ldapconf, 0, sizeof(LDAPCONFIG));
    if(getldapconfig(&ldapconf) != 0) //This will decrypt the password as well
    {
        TCRIT("Couldn't able to get the ldap configuration\n");
        goto error;
    }

    	// Get the AD Configurations
    memset((unsigned char*)&adcfg, 0, sizeof(AD_Config_T));
    if(GetADConfig (&adcfg) != 0) //This will decrypt the password as well
    {
        TCRIT("Could not get Active Directory Configuration\n");
        goto error;
    }

    //For SMTP
    for(count = 0; count < MAX_LAN_CHANNELS; count++)
    {
        pm_Smtp_Config = &pBMCInfo->SmtpConfig[count];

        // For Primary SMTP Server
        if(pm_Smtp_Config->EnableDisableSMTP == 1 && pm_Smtp_Config->EnableDisableSmtpAuth == 1) 
        {
            // First decrypt with the old encryption key
            if(DecryptPassword((INT8S *)pm_Smtp_Config->Passwd, MAX_SMTP_PASSWD_LEN-1, decryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1, oldEncryptKey))
            {
                TCRIT("\n Error in Decrypting the Primary SMTP Password. \n");
                goto error;
            }

            // Now encrypt with the new encryption key
            if(EncryptPassword(decryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1, encryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1, newEncryptKey))
            {
                TCRIT("Error in encrypting the Primary SMTP password.\n");
                goto error;
            }

            memset(&(pm_Smtp_Config->Passwd),0, MAX_SMTP_PASSWD_LEN-1);
            memcpy(&(pm_Smtp_Config->Passwd), encryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1);
        }
        // For Secondary SMTP Server
        if(pm_Smtp_Config->EnableDisableSMTP2 == 1 && pm_Smtp_Config->EnableDisableSmtp2Auth == 1)
        {
            memset(decryptedSMTPPswd, 0, MAX_SMTP_PASSWD_LEN);
            memset(encryptedSMTPPswd, 0, MAX_SMTP_PASSWD_LEN);

            // First decrypt with the old encryption key
            if(DecryptPassword((INT8S *)pm_Smtp_Config->Passwd2, MAX_SMTP_PASSWD_LEN-1, decryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1, oldEncryptKey))
            {
                TCRIT("\n Error in Decrypting the Secondary SMTP Password. \n");
                goto error;
            }

            // Now encrypt with the new encryption key
            if(EncryptPassword(decryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1, encryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1, newEncryptKey))
            {
                TCRIT("Error in encrypting the Secondary SMTP password.\n");
                goto error;
            }

            memset(&(pm_Smtp_Config->Passwd2),0, MAX_SMTP_PASSWD_LEN-1);
            memcpy(&(pm_Smtp_Config->Passwd2), encryptedSMTPPswd, MAX_SMTP_PASSWD_LEN-1);

            FlushIPMI((INT8U*)&pBMCInfo->SmtpConfig[0], (INT8U*)&pBMCInfo->SmtpConfig[count],
                        pBMCInfo->IPMIConfLoc.SmtpConfigAddr, sizeof(Smtp_Config_T), BMCInst);

        }
    }

    // Now set the new encryption Key to the /conf/pwdEncKey file
    if(setEncryptKey(newEncryptKey))
    {
        TCRIT("Error in writing the new encryption key to /conf/pwdEncKey file. quitting...\n");
        goto error;
    }

    LOCK_BMC_SHARED_MEM(BMCInst);
        memset(&(g_MBMCInfo.PwdEncKey), 0 , MAX_SIZE_KEY);
        memcpy(&(g_MBMCInfo.PwdEncKey), &(pAMISetPwdEncKeyReq->PwdEncryptKey), ReqLen);
    UNLOCK_BMC_SHARED_MEM(BMCInst);

    // Encryption Key is set. Now, save the LDAP configurations.
    if(ldapconf.Enable == 1)
    {
        if(setldapconfig(&ldapconf) != 0) //This will encrypt the password as well
        {
            TCRIT("Error in setting LDAP configuration\n");
            goto error;
        }
    }
    else
    {
        TDBG("LDAP Disabled !! ldap login works when its enabled \n");
    }

    // Encryption Key is set. Now, save the AD configurations.
    if(adcfg.ADEnable == 1)
    {
        if(SetADConfig(&adcfg) != 0) //This will encrypt the password as well
        {
            TCRIT("Error in setting AD configuration:\n");
            goto error;
        }
    }
    else
    {
        TDBG("AD is Not Enabled !! AD login works when its enabled.\n");
        pAMISetPwdEncKeyRes->CompletionCode = CC_NORMAL;
    }

    TDBG("The new encryption key has set.\n");
    FlushIPMI((INT8U*)&pBMCInfo->EncryptedUserInfo[0], (INT8U*)&pBMCInfo->EncryptedUserInfo[0], pBMCInfo->IPMIConfLoc.EncUserPasswdAddr,
                sizeof(EncryptedUserInfo_T) * MAX_USER_CFG_MDS, BMCInst);

    pAMISetPwdEncKeyRes->CompletionCode = CC_NORMAL;
    return sizeof(AMISetPwdEncKeyRes_T);

error:
    /* There is a failure in Decryption/Encryption; so reverting to the old values */
    LOCK_BMC_SHARED_MEM(BMCInst);
    memcpy(&(pBMCInfo->EncryptedUserInfo[0].EncryptedPswd), &(OldEncUserPaswd[0]), MAX_USER_CFG_MDS * MAX_ENCRYPTED_PSWD_LEN);
    UNLOCK_BMC_SHARED_MEM(BMCInst);

    pAMISetPwdEncKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
    return sizeof(INT8U);
}

/**
 * *@fn AMISetUBootMemtest
 * *@brief This command is used to Enable/Disable the U-Boot Memory Test 
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMISetUBootMemtest(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMISetUBootMemtestReq_T *pAMISetUBootMemtestReq = (AMISetUBootMemtestReq_T *)pReq;
    AMISetUBootMemtestRes_T *pAMISetUBootMemtestRes = (AMISetUBootMemtestRes_T *)pRes;
    int RetVal;
    char BootVal[5];
    memset(BootVal,0,sizeof(BootVal));

    /*Check the Reserved value ( 0 - Disable; 1 - Enable memory Test)*/
    if(1 < pAMISetUBootMemtestReq->EnableMemoryTest)
    {
        *pRes = CC_INV_DATA_FIELD;
        return sizeof(INT8U);
    }

    /*Enable/Disable the U-Boot Memory Test*/
    sprintf(BootVal,"%d",pAMISetUBootMemtestReq->EnableMemoryTest);

    RetVal = SetUBootParam(UBOOT_MEMTEST_ENABLE_VAR,BootVal);
    if(0 != RetVal)
    {
        *pRes = CC_UNSPECIFIED_ERR;
        return sizeof(INT8U);
    }

    pAMISetUBootMemtestRes->CompletionCode = CC_NORMAL;
    return sizeof(INT8U);
}

/**
 * *@fn AMIGetUBootMemtestStatus
 * *@brief This command is used to get the status of U-Boot Memory Test
 * *@param pReq - Request for the command
 * *@param ReqLen - Request length for the command
 * *@param pRes - Response for the command
 * *@param BMCInst - BMC Instance Value
 **/
int
AMIGetUBootMemtestStatus(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMIGetUBootMemtestStatusRes_T *pAMIGetUBootMemtestStatusRes = (AMIGetUBootMemtestStatusRes_T *)pRes;
    char BootVal[10] = {0};
    char Memtest[10] = {0};
    int RetVal;

    /*Get the U-Boot Memory Test Result*/
    RetVal = GetUBootParam(UBOOT_MEMTEST_STATUS_VAR,BootVal);
    if(0 != RetVal)
    {
        *pRes = CC_UNSPECIFIED_ERR;
        return sizeof(INT8U);
    }

    /*Get the do_memtest U-Boot Env Value*/
    RetVal = GetUBootParam(UBOOT_MEMTEST_ENABLE_VAR,Memtest);
    if(0 != RetVal)
    {
        *pRes = CC_UNSPECIFIED_ERR;
        return sizeof(INT8U);
    }

    /*Memory Test idle (0)*/
    pAMIGetUBootMemtestStatusRes->MemtestStatus = 0;

    if(strcmp(BootVal,MEMTEST_PASS) == 0)
    {
        /*Memory Test Success (1)*/
        pAMIGetUBootMemtestStatusRes->MemtestStatus = 1;
    }
    else if(strcmp(BootVal,MEMTEST_FAIL) == 0)
    {
        /*Memory Test Fail (2)*/
        pAMIGetUBootMemtestStatusRes->MemtestStatus = 2;
    }

    /*Memory Test diable (0)*/
    pAMIGetUBootMemtestStatusRes->IsMemtestEnable = 0;

    if(strcmp(Memtest,MEMTEST_ENABLE) == 0)
    {
        /*Memory Test is Enabled (1)*/
        pAMIGetUBootMemtestStatusRes->IsMemtestEnable = 1;
    }

    pAMIGetUBootMemtestStatusRes->CompletionCode = CC_NORMAL;
    return sizeof(AMIGetUBootMemtestStatusRes_T);
}

/**
 **@fn SetDefaultTimezone
 **@brief This command is used set the defalut timezone value.
 **@param TimeZone - Timezone string -initial zone name.
 **@param BMCInst - BMC Instance Value
 **@return  0 on success -1 on failure
 **/
int 
SetDefaultTimezone (INT8U *TimeZone, int BMCInst)
{
    _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];
    INT16 UTCOffset = 0;
    time_t Curtime = 0;
    char Cmd [ZONE_PATH_SIZE];
    char Zonepath [ZONE_PATH_SIZE];
    struct stat sb, buf;
    struct tm *loctm = NULL;
    INT8U Size = 0;
    INT8U Zonename [TIME_ZONE_LEN];
    char Filename[MAXFILESIZE];

    if (NULL == TimeZone)
    {
        return -1;
    }
    
    IPMI_CONFIGS_FILE(BMCInst,Filename);
    memset (Zonepath, 0, ZONE_PATH_SIZE);
    memset (Cmd, 0, ZONE_PATH_SIZE);
    memset (Zonename, 0, TIME_ZONE_LEN);
    memcpy (Zonename,TimeZone, TIME_ZONE_LEN);

    if (0 == memcmp (TimeZone, TIMEZONE_OFFSET_PVE, strlen(TIMEZONE_OFFSET_PVE)))
    {
        Size = strlen (TIMEZONE_OFFSET_PVE) - sizeof (INT8U);
        TimeZone [Size] = '-';
    }
    else if (0 == memcmp (TimeZone, TIMEZONE_OFFSET_NVE, strlen(TIMEZONE_OFFSET_NVE)))
    {
        Size = strlen (TIMEZONE_OFFSET_NVE) - sizeof (INT8U);
        TimeZone [Size] = '+';
    }
    snprintf (Zonepath, ZONE_PATH_SIZE, "%s%s", TIME_ZONE_PATH,(char*)TimeZone);
    /*Verify the file presence*/
    if (stat (Zonepath, &sb))
    {
        return -1;
    }
    if (!S_ISREG (sb.st_mode))
    {
        return -1;
    }
    snprintf (Cmd, ZONE_PATH_SIZE, "%s %s %s", LINK_CMD, Zonepath, LOCALTIME);
    safe_system (Cmd);

    /*Getting UTC offset and updating*/
    time(&Curtime);
    loctm = localtime(&Curtime);
    UTCOffset = (loctm->tm_gmtoff/MAX_MINS);
    if (((UTCOffset <= SEL_UTC_MAX_RANGE) && (UTCOffset >= SEL_UTC_MIN_RANGE)) || (UTCOffset == UNSPECIFIED_UTC_OFFSET))
    {
        pBMCInfo->GenConfig.SELTimeUTCOffset = UTCOffset;
    }
    memcpy (pBMCInfo->GenConfig.TimeZone, Zonename, sizeof (pBMCInfo->GenConfig.TimeZone));
    /*Write to NVRAM*/
    if (stat(Filename, &buf) == 0)
    {
        FlushIPMI((INT8U*)&pBMCInfo->GenConfig,(INT8U*)&pBMCInfo->GenConfig,pBMCInfo->IPMIConfLoc.GenConfigAddr, 
                          sizeof(GENConfig_T),BMCInst); 
    }

    return 0; 
}

/**
 **@fn AMISetTimeZone
 **@brief This command is used to set the timezone.
 **@param pReq - Request for the command
 **@param ReqLen - Request length for the command
 **@param pRes - Response for the command
 **@param BMCInst - BMC Instance Value
 **/
int
AMISetTimeZone (_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMISetTimeZone_T *pAMISetTimeZoneReq = (AMISetTimeZone_T *)pReq;
    if(g_corefeatures.time_zone_support == ENABLED)
    {
        if ((ReqLen <= 0) || (ReqLen >= sizeof (AMISetTimeZone_T)))
        {
            *pRes = CC_REQ_INV_LEN;
            return sizeof(INT8U);
        }
        if (pAMISetTimeZoneReq->ZoneName [0] == '\0')
        {
            *pRes = CC_INV_DATA_FIELD;
            return sizeof(INT8U);
        }
        pAMISetTimeZoneReq->ZoneName [ReqLen] = '\0';
        if (-1 == SetDefaultTimezone (pAMISetTimeZoneReq->ZoneName, BMCInst))
        {
            *pRes = CC_INV_DATA_FIELD;
            return sizeof(INT8U);
        }
        *pRes = CC_NORMAL;
    }
    else
    {
        *pRes = CC_INV_CMD;
    }
    return sizeof(INT8U);
}

/**
 **@fn AMIGetTimeZone
 **@brief This command is used to get the timezone.
 **@param pReq - Request for the command
 **@param ReqLen - Request length for the command
 **@param pRes - Response for the command
 **@param BMCInst - BMC Instance Value
 **/
int
AMIGetTimeZone (_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMIGetTimeZone_T *pAMISetTimeZoneRes = (AMIGetTimeZone_T *)pRes;

    if(g_corefeatures.time_zone_support == ENABLED)
    {
        _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];
        memset (pAMISetTimeZoneRes, 0, sizeof(AMIGetTimeZone_T));
        pAMISetTimeZoneRes->CompletionCode = CC_NORMAL;
        memcpy (pAMISetTimeZoneRes->ZoneName, pBMCInfo->GenConfig.TimeZone, sizeof (pBMCInfo->GenConfig.TimeZone));
        ReqLen = strlen ((char *)pAMISetTimeZoneRes->ZoneName);
    }
    else
    {
        pAMISetTimeZoneRes->CompletionCode = CC_INV_CMD;
        ReqLen = 0;
    }
    return ReqLen + sizeof (INT8U);
}

/**
 **@fn AMIGetNTPCfg
 **@brief This command is used to get the NTP configs.
 **@param pReq - Request for the command
 **@param ReqLen - Request length for the command
 **@param pRes - Response for the command
 **@param BMCInst - BMC Instance Value
 **/

int AMIGetNTPCfg(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
   
    AMIGetNTPCfgRes_T *pAMIGetNTPCfgRes = (AMIGetNTPCfgRes_T *)pRes;
    if(g_corefeatures.ntp_server_support == ENABLED)
    {
        INT8U PrimServer[MAX_SERVER_LEN]={0};
        INT8U SecServer[MAX_SERVER_LEN]={0};
        INT8U Status[MAX_STATUS_LEN]={0};
        void *dl_handle = NULL;
        int ( *dl_func_ser )( char *, char *,unsigned int );
        int ( *dl_func_stat )( char * );
        dl_handle = NULL;

        dl_handle = dlopen ( "/usr/local/lib/libntpconf.so", RTLD_NOW );
        if(NULL == dl_handle)
        {
            IPMI_ERROR("Error in loading libntpconf.so library %s\n", dlerror() );
            pAMIGetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(INT8U);
        }

        dl_func_ser =  dlsym( dl_handle, "libami_getntpServer" );
        if(NULL == dl_func_ser)
        {
            IPMI_ERROR("Error in loading symbol libami_getntpServer %s\n", dlerror() );
            dlclose(dl_handle);
            pAMIGetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(INT8U);
        }

        dl_func_stat =  dlsym( dl_handle, "libami_getntpStatus" );
        if(NULL == dl_func_stat)
        {
            IPMI_ERROR("Error in loading symbol libami_getntpStatus %s\n", dlerror() );
            dlclose(dl_handle);
            pAMIGetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(INT8U);
        }

        dl_func_ser((char*)PrimServer,(char*)SecServer, MAX_SERVER_LEN);
        dl_func_stat((char*)Status);
        memset(pAMIGetNTPCfgRes,0,sizeof(AMIGetNTPCfgRes_T));
        strncpy((char*) pAMIGetNTPCfgRes->PrimServer,(char*)PrimServer,MAX_SERVER_LEN);
        strncpy((char*)pAMIGetNTPCfgRes->SecServer,(char*)SecServer,MAX_SERVER_LEN);
        if(!strncmp((char*)Status ,"Auto" ,MAX_STATUS_LEN))
        {
            pAMIGetNTPCfgRes->Status = AUTO;
        }
        else if(!strncmp((char*)Status ,"Manual" ,MAX_STATUS_LEN))
        {
            pAMIGetNTPCfgRes->Status = MANUAL;
        }
        else
        {
            pAMIGetNTPCfgRes->Status = FAIL;
        }
        dlclose(dl_handle);
        return sizeof(AMIGetNTPCfgRes_T);
    }
    else
    {
        pAMIGetNTPCfgRes->CompletionCode = CC_INV_CMD;
        return sizeof(INT8U);
    }

}

/**
 **@fn AMISetNTPCfg
 **@brief This command is used to set the NTP configs.
 **@param pReq - Request for the command
 **@param ReqLen - Request length for the command
 **@param pRes - Response for the command
 **@param BMCInst - BMC Instance Value
 **/

int AMISetNTPCfg(_NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, int BMCInst)
{
    AMISetNTPCfgReq_T *pAMISetNTPCfgReq = (AMISetNTPCfgReq_T *)pReq;
    AMISetNTPCfgRes_T *pAMISetNTPCfgRes = (AMISetNTPCfgRes_T *)pRes;
    
    if(g_corefeatures.ntp_server_support == ENABLED)
    {
        void *dl_handle = NULL;
        int ( *dl_func_ser )( unsigned char, char * );
        int ( *dl_func_stat )( char * );
        int ( *dl_func_get_ser )( char * , char *, unsigned int ); 
        INT8U PrimServer[MAX_SERVER_LEN]={0}; 
        INT8U SecServer[MAX_SERVER_LEN]={0};
        INT8U Status[MAX_STATUS_LEN]="Manual";
        INT8U update_ntp[MAX_SERVER_LEN]={0}; 
        int ret; 

        dl_handle = NULL;
        dl_handle = dlopen ( "/usr/local/lib/libntpconf.so", RTLD_NOW );
        if(NULL == dl_handle)
        {
            IPMI_ERROR("Error in loading libntpconf.so library %s\n", dlerror() );
            pAMISetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(AMISetNTPCfgRes_T);
        }

        switch (pAMISetNTPCfgReq->param)
        {
            case PARAM_SERVER_PRIM: // for setting primary server
                
            case PARAM_SERVER_SEC: // for setting secondary server
                if(ReqLen != sizeof(AMISetNTPCfgReq_T))
                {
                    pAMISetNTPCfgRes->CompletionCode=CC_REQ_INV_LEN;
                    break;
                }
                dl_func_ser =  dlsym( dl_handle, "libami_setntpServer" );
                if(NULL == dl_func_ser)
                {
                    IPMI_ERROR("Error in loading symbol libami_setntpServer %s\n", dlerror() );
                    pAMISetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR;
                    break;
                }
                dl_func_ser(pAMISetNTPCfgReq->param,(char*)pAMISetNTPCfgReq->ntpconf.Server);
                pAMISetNTPCfgRes->CompletionCode=CC_NORMAL;
                break;
            
            case PARAM_STATUS: //for setting the status 
                if(ReqLen != (1+ sizeof(pAMISetNTPCfgReq->ntpconf.Status)))
                {
                    pAMISetNTPCfgRes->CompletionCode=CC_REQ_INV_LEN;
                    break;
                }
                if(pAMISetNTPCfgReq->ntpconf.Status != AUTO && pAMISetNTPCfgReq->ntpconf.Status != MANUAL) 
                { 
                	pAMISetNTPCfgRes->CompletionCode=CC_INV_DATA_FIELD; 
                	break; 
                } 

                dl_func_stat =  dlsym( dl_handle, "libami_setntpStatus" );
                if(NULL == dl_func_stat)
                {
                    IPMI_ERROR("Error in loading symbol libami_setntpStatus %s\n", dlerror() );
                    pAMISetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR;
                    break;
                }
                if(pAMISetNTPCfgReq->ntpconf.Status == AUTO)
                { 
                    strncpy((char*)Status, "Auto", MAX_STATUS_LEN); 
	                dl_func_get_ser = dlsym(dl_handle, "libami_getntpServer"); 
	                if(NULL == dl_func_get_ser) 
	                { 
		                IPMI_ERROR("Error in loading symbol libami_getntpServer %s\n", dlerror() ); 
		                dlclose(dl_handle); 
		                pAMISetNTPCfgRes->CompletionCode = CC_UNSPECIFIED_ERR; 
		                return sizeof(INT8U); 
	                } 
	                dl_func_get_ser((char*)PrimServer,(char*)SecServer, MAX_SERVER_LEN); 
	                sprintf((char*)update_ntp, "ntpdate -b -s -u %s", PrimServer); 
	                ret = safe_system((char*)update_ntp); 
	                if(0 != ret) 
	                { 
		                TCRIT("\n NTP update failure in primary server::%d\n", ret); 
		                sprintf((char*)update_ntp, "ntpdate -b -s -u %s", SecServer); 
		                ret = safe_system((char*)update_ntp); 
		                if(0 != ret) 
		                { 
			               TCRIT("\n NTP update failure in secondary server::%d\n", ret); 
			               strncpy((char*)Status, "Failure", MAX_STATUS_LEN); 
			               TCRIT("Error in restarting NTP Date\n"); 
			               pAMISetNTPCfgRes->CompletionCode = CC_NTP_RESTART_ERROR;
                           dl_func_stat((char*)Status); 
			               break; 
		                } 
	                } 
                }   

                dl_func_stat((char*)Status);
                pAMISetNTPCfgRes->CompletionCode=CC_NORMAL;
                break;
            
            default:
                pAMISetNTPCfgRes->CompletionCode=CC_INV_DATA_FIELD;
            
       }
       dlclose(dl_handle);
       return sizeof(AMISetNTPCfgRes_T);
    }
     else
    {
        pAMISetNTPCfgRes->CompletionCode = CC_INV_CMD;
        return sizeof(AMISetNTPCfgRes_T);
    }
}

/*---------------------------------------
 * AMIYAFUReplaceSignedImageKey
 *---------------------------------------*/
int AMIYAFUReplaceSignedImageKey ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIYafuSignedImageKeyReq_T *pAMIYafuSignedImageReq = (AMIYafuSignedImageKeyReq_T *)pReq;
    AMIYafuSignedImageKeyRes_T *pAMIYafuSignedImageRes = (AMIYafuSignedImageKeyRes_T *)pRes;
    int SizeWritten = 0;
    FILE *fp =NULL;

    if(g_corefeatures.signed_hashed_image_support == ENABLED)
    {
        /* Check Requested Length */
        if(((ReqLen) > MAX_PERMITTED_KEY_SIZE) || ((ReqLen) <= 0))
        {
            IPMI_ERROR("Invalid Request Length\n");
           pAMIYafuSignedImageRes->CompletionCode = CC_REQ_INV_LEN;
           return sizeof(AMIYafuSignedImageKeyRes_T);
        }

        fp = fopen(TEMP_PUB_KEY, "wb");
        if(fp == NULL)
        {
           IPMI_ERROR("Error in Opening File\n");
           pAMIYafuSignedImageRes->CompletionCode = CC_UNSPECIFIED_ERR;
           return sizeof(AMIYafuSignedImageKeyRes_T);
        }

        SizeWritten = fwrite(&pAMIYafuSignedImageReq->PubKey[0],1,(ReqLen),fp);
        if(SizeWritten != (ReqLen))
        {
           IPMI_ERROR("Error in Writing into the file\n");
           pAMIYafuSignedImageRes->CompletionCode = CC_UNSPECIFIED_ERR;
           fclose(fp);
           return sizeof(AMIYafuSignedImageKeyRes_T);
        }

       fclose(fp);

       /* Now Open the File in Read Mode */
        fp = fopen(TEMP_PUB_KEY, "rb");
        if(fp == NULL)
        {
           IPMI_ERROR("Error in Opening File\n");
           pAMIYafuSignedImageRes->CompletionCode = CC_UNSPECIFIED_ERR;
           unlink(TEMP_PUB_KEY);
           return sizeof(AMIYafuSignedImageKeyRes_T);
        }

        if(PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL) == NULL)
        {
           IPMI_ERROR("Error in loading RSA public key file %s\n", TEMP_PUB_KEY);
           fclose(fp);
           unlink(TEMP_PUB_KEY);
           pAMIYafuSignedImageRes->CompletionCode = CC_PUBLICKEY_VALIDATION_FAILED;
           return sizeof(AMIYafuSignedImageKeyRes_T);
        }

        fclose(fp);

        if(moveFile(TEMP_PUB_KEY,CONF_PUB_KEY) != 0)
        {
            IPMI_ERROR("Cannot Move File Named as %s\n",CONF_PUB_KEY);
            pAMIYafuSignedImageRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(AMIYafuSignedImageKeyRes_T);
        }

        pAMIYafuSignedImageRes->CompletionCode = CC_NORMAL;
        return sizeof(AMIYafuSignedImageKeyRes_T);
    }
    else
    {
        pAMIYafuSignedImageRes->CompletionCode = CC_INV_CMD;
        return sizeof(AMIYafuSignedImageKeyRes_T);
    }
}
#define USB_DEVICE "/dev/usb"
int IsKVMSessionRunning()
{
	int ServiceRet;
	SERVICE_CONF_STRUCT KVMServiceConf;
	
	int activecount = 0;
	if(g_corefeatures.service_config == ENABLED)
	{
		ServiceRet = get_service_configurations(KVM_SERVICE_NAME,&KVMServiceConf);
		if(ServiceRet == -1)
		{
			IPMI_ERROR("\nCannot get Service Configurations\n");
			return 1;
		}
	}
	if(isNotEditable((unsigned char *)&(KVMServiceConf.CurrentActiveSession),sizeof(KVMServiceConf.CurrentActiveSession)) )
	{
		getNotEditableData((unsigned char *)&(KVMServiceConf.CurrentActiveSession),sizeof(KVMServiceConf.CurrentActiveSession), (unsigned char *)&(activecount));
		
		IPMI_ERROR("KVM Session, setting CurrentActiveSession value After Mask::%d\n", KVMServiceConf.CurrentActiveSession);
	}
	if(activecount)
	{
		IPMI_ERROR("\nKVM Running::%d:activecount:%d\n",KVMServiceConf.CurrentActiveSession,activecount);
		return 1;
	}
	return 0;
}

int OngetSetVirtualDevice(int cmd,u8 *deviceStatus)
{
	int usbfd;
	u8 status=0;
	/* Open the USB Device */
	usbfd=open(USB_DEVICE,O_RDWR);
	
	if (usbfd < 0)
	{
		TCRIT("Error:AMIVirtualDeviceEnable Unable to open USB Device\n");
		return CC_NODE_BUSY;
	}
	if(cmd == USB_GET_ALL_DEVICE_STATUS)
	{
		if (ioctl (usbfd, cmd, &status))
		{
			TWARN ("Error: AMIVirtualDeviceEnable() USB_ENABLE_ALL_DEVICE  IOCTL Failed\n");
			close(usbfd);
			return CC_NODE_BUSY;
		}
		*deviceStatus = status;
	}
	else
	{
		if(IsVirtualMediaRunning() || IsKVMSessionRunning() || IsLmediaRmediaRunning())
		{
			if(cmd == USB_ENABLE_ALL_DEVICE)
			{
				if (ioctl (usbfd, USB_GET_ALL_DEVICE_STATUS, &status))
				{
					TWARN ("Error: AMIVirtualDeviceEnable() USB_GET_ALL_DEVICE_STATUS  IOCTL Failed\n");
					close(usbfd);
					return CC_NODE_BUSY;
				}
				if(status == 0)
				{
					if (ioctl (usbfd, cmd, NULL))
					{
						TWARN ("Error: AMIVirtualDeviceEnable() USB_ENABLE_ALL_DEVICE  IOCTL Failed\n");
						close(usbfd);
						return CC_NODE_BUSY;
					}
				}
				else
				{
					close(usbfd);
					return CC_NODE_BUSY;
				}
			}
			else
			{
				close(usbfd);
				return CC_NODE_BUSY;
			}
		}
		else if (ioctl (usbfd, cmd, NULL))
		{
			TWARN ("Error: AMIVirtualDeviceEnable() USB_ENABLE_ALL_DEVICE  IOCTL Failed\n");
			close(usbfd);
			return CC_NODE_BUSY;
		}
	}
	
	close(usbfd);
	return 0;
}

int AMIVirtualDeviceSetStatus ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIVirtualDeviceSetStatusReq_T *pAMIVirtualDeviceSetStatusReq = (AMIVirtualDeviceSetStatusReq_T *)pReq;
    AMIVirtualDeviceSetStatusRes_T *pAMIVirtualDeviceSetStatusRes = (AMIVirtualDeviceSetStatusRes_T *)pRes;

    void *pHandle = NULL;
    INT16 (*GetLicenseStatus)(const char*, BOOL*);
    
    if(g_corefeatures.power_consumption_virtual_device_usb == ENABLED)
    {
        
        if ((ReqLen <= 0) || (ReqLen > sizeof (AMIVirtualDeviceSetStatusReq_T)))
        {
            *pRes = CC_REQ_INV_LEN;
            return sizeof(INT8U);
        }
        
        //check if license is proper to run this command
        if (g_PDKHandle[PDK_LICENSE_STATUS] != NULL)
        {
            int retval = 0;
            retval = ((int(*)(char *))g_PDKHandle[PDK_LICENSE_STATUS]) ( "MEDIA" );
            //if proper license is not there then return from the command
            if ( retval <= 0 ) 
            {
                TCRIT("Licenseing error : No proper license to run this command");
                pAMIVirtualDeviceSetStatusRes->CompletionCode = CC_OP_NOT_SUPPORTED;
                return sizeof(INT8U);
            }
        }
        else
        {
            pHandle = dlopen("/usr/local/lib/liblicense.so",RTLD_NOW);
            BOOL IsValidApp = TRUE;
            if(NULL != pHandle)
            {
                GetLicenseStatus = dlsym(pHandle, "GetLicenseStatus");
                if(NULL != GetLicenseStatus)
                {
                    GetLicenseStatus("MEDIA", &IsValidApp);
                }
                dlclose(pHandle);
            }
            
            if ( TRUE != IsValidApp ) 
            {
                TDBG("Licenseing error : No proper license to run this command\n");
                pAMIVirtualDeviceSetStatusRes->CompletionCode = CC_OP_NOT_SUPPORTED;
                return sizeof(INT8U);
            }
        }
        
        switch (pAMIVirtualDeviceSetStatusReq->Status)
        {
          case VIRTUAL_DEVICE_DISABLE:
              pAMIVirtualDeviceSetStatusRes->CompletionCode = OngetSetVirtualDevice(USB_DISABLE_ALL_DEVICE,0);
              break;
          case VIRTUAL_DEVICE_ENABLE:
              pAMIVirtualDeviceSetStatusRes->CompletionCode = OngetSetVirtualDevice(USB_ENABLE_ALL_DEVICE,0);
              break;
          default:
          {
            TDBG("\n Case Failure in device status\n");
            *pRes =CC_INV_DATA_FIELD;
            return sizeof(INT8U);
          }
        }
    }
    else
    {
        *pRes =CC_INV_CMD;
        return sizeof(INT8U);
    }

    return sizeof(AMIVirtualDeviceSetStatusRes_T);
}     


int AMIVirtualDeviceGetStatus ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
	u8 Status;
	if(g_corefeatures.power_consumption_virtual_device_usb == ENABLED)
	{
	AMIVirtualDeviceGetStatusRes_T *pAMIVirtualDeviceSetStatusRes = (AMIVirtualDeviceGetStatusRes_T *)pRes;
	
	pAMIVirtualDeviceSetStatusRes->CompletionCode = OngetSetVirtualDevice(USB_GET_ALL_DEVICE_STATUS,(u8 *)&Status);
	pAMIVirtualDeviceSetStatusRes->Status = Status;
	
	return sizeof(AMIVirtualDeviceGetStatusRes_T);
	}
	else
	{
		*pRes =CC_INV_CMD;
		return sizeof(INT8U);	
	}
}

int AMIGetLicenseValidity ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes,_NEAR_ int BMCInst )
{
    AMIGetLicenseValidityRes_T * AMIGetLicenseValidityRes = (AMIGetLicenseValidityRes_T * )pRes;
    FILE *fd_St;
    char  OldAppCode[APPCODE_LEN] = {0}, NewAppCode[APPCODE_LEN] = {0}, StatusInfo[BUFFER_LENGTH];
    BOOL Status = FALSE;
    INT8U Validity = -1;
    void *pHandle = NULL;
    INT16 (*GetLicenseStatus)(const char*, BOOL*);
    
    if(g_corefeatures.runtime_license_support != ENABLED)
    {
        AMIGetLicenseValidityRes->CompletionCode = CC_INV_CMD;
        return sizeof(AMIGetLicenseValidityRes->CompletionCode);
    }
    
    memset(AMIGetLicenseValidityRes, 0, sizeof(AMIGetLicenseValidityRes_T));
    
    fd_St = fopen(LICENSE_CONF, "r");
    if(fd_St == NULL)
    {
       TDBG("\n problem in opening file");
       AMIGetLicenseValidityRes->CompletionCode = CC_UNSPECIFIED_ERR;
       return sizeof(INT8U);
    }

    AMIGetLicenseValidityRes->CompletionCode = CC_NORMAL;
    pHandle = dlopen("/usr/local/lib/liblicense.so",RTLD_NOW);
    
    while(fgets((char *)StatusInfo, BUFFER_LENGTH, fd_St) != NULL)
    {
        sscanf(StatusInfo, "%[^:]", NewAppCode);
        if(strcmp(OldAppCode, NewAppCode) == 0)
            continue;
        memcpy(AMIGetLicenseValidityRes-> Lic_Info[AMIGetLicenseValidityRes->NumOfFeatures].FeatureName, NewAppCode, strlen(NewAppCode));
       
        Status = FALSE;
        if(NULL != pHandle)
        {
            GetLicenseStatus = dlsym(pHandle, "GetLicenseStatus");
            if(NULL != GetLicenseStatus)
            {
                Validity = GetLicenseStatus(NewAppCode, &Status);
            }
        }
        
        if(0 > Validity)
        {
            fclose(fd_St);
            if(NULL != pHandle)
            {
                dlclose(pHandle);
            }
            AMIGetLicenseValidityRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(INT8U);
        }
        strcpy(OldAppCode,NewAppCode);
        
        memcpy(&AMIGetLicenseValidityRes->Lic_Info[AMIGetLicenseValidityRes->NumOfFeatures].Validity, &Validity, sizeof(Validity));
        AMIGetLicenseValidityRes->NumOfFeatures += 1;
    }
    fclose(fd_St);
    dlclose(pHandle);
    
    return (sizeof(INT8U) + sizeof(AMIGetLicenseValidityRes->NumOfFeatures) + (AMIGetLicenseValidityRes->NumOfFeatures * sizeof(LicenseInfo_T)));
}

int AMIAddLicenseKey ( _NEAR_ INT8U *pReq, INT32U ReqLen, _NEAR_ INT8U *pRes, _NEAR_ int BMCInst )
{
    AMIAddLicenseKeyReq_T AMIAddLicenseKeyReq;
    AMIAddLicenseKeyRes_T *AMIAddLicenseKeyRes = (AMIAddLicenseKeyRes_T *)pRes;
    
    FILE *fd_conf, *fd_st, *fd_tmp, *fd_key, *fd_cnt;
    char ConfBf[BUFFER_LENGTH], StatusBf[BUFFER_LENGTH], KeyBf[LIC_KEY_LEN + 1]= {0};
    
    char App_Conf[APPCODE_LEN] = {0}, App_St[APPCODE_LEN] = {0};
    INT16U St_Vdt = 0, St_Cnt = 0;
    char IfcName[16];
    INT16S BitVal, pos = 0;
    INT16U InitDayCnt;
    int i;
    INT32U FtrList = 0;
  
    NWCFG_STRUCT  NWConfig;
    INT8U EthIndex = 0x0;
    LicenseKeyInfo_T LicStr;
    
    if(g_corefeatures.runtime_license_support != ENABLED)
    {
        AMIAddLicenseKeyRes->CompletionCode = CC_INV_CMD;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
    memset(AMIAddLicenseKeyReq.LicenseKey, 0, sizeof(AMIAddLicenseKeyReq_T));
    for(i = 0; i < ReqLen; i++)
    {
        if(pReq[i] != '-')
        {
            AMIAddLicenseKeyReq.LicenseKey[pos++] = pReq[i];
        }
    }
    if(strlen((char *)AMIAddLicenseKeyReq.LicenseKey) != LIC_KEY_LEN)
    {
        TDBG("\nAMIAddLicenseKey():Request length invalid\n");
        AMIAddLicenseKeyRes->CompletionCode = CC_REQ_INV_LEN;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }

    if(0 != IsDuplicateKey(AMIAddLicenseKeyReq.LicenseKey))
    {
        AMIAddLicenseKeyRes->CompletionCode = CC_INVALID_KEY;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
    if(0 != Decrypt_LicenseKey(AMIAddLicenseKeyReq.LicenseKey, strlen((char *)AMIAddLicenseKeyReq.LicenseKey), (char *)&LicStr))
    {
        TDBG("Problem in decrypting\n");
        AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
   
    if((0 != memcmp(LicStr.Signature, LIC_SIGNATURE, LIC_SIGNATURE_LEN)) ||
       (0 == LicStr.Lic_Validity ) || (0 == LicStr.FtrList))
    {
        AMIAddLicenseKeyRes->CompletionCode = CC_INVALID_KEY;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }

    if(0 != GetIfcName(EthIndex, IfcName, BMCInst))
    {
        TCRIT("\nAMIAddLicenseKey(): Error in Getting IfcName\n");
        AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
        return sizeof (AMIAddLicenseKeyRes->CompletionCode);
    }
    
    if(0 != nwGetNWInformations(&NWConfig, IfcName))
    {
        TDBG("\nAMIAddLicenseKey(): Problem in loading MAC address\n");
        AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
    if(LicStr.MACAddr[3] == 0xFF && LicStr.MACAddr[4] == 0xFF && LicStr.MACAddr[5] == 0xFF )
    {
        if(LicStr.MACAddr[0] != 0xFF || LicStr.MACAddr[1] != 0xFF || LicStr.MACAddr[2] != 0xFF)
        {
            if((memcmp(LicStr.MACAddr, NWConfig.MAC, MAC_OUI_LEN) != 0))
            {
                TDBG("\nAMIAddLicenseKey(): Invalid MAC address\n");
                AMIAddLicenseKeyRes->CompletionCode = CC_INVALID_KEY;
                return sizeof(AMIAddLicenseKeyRes->CompletionCode);
            }
        }
    }
    else
    {
        if(memcmp(LicStr.MACAddr, NWConfig.MAC, sizeof(LicStr.MACAddr)) != 0)
        {
            TDBG("\nAMIAddLicenseKey(): Invalid MAC address\n");
            AMIAddLicenseKeyRes->CompletionCode = CC_INVALID_KEY;
            return sizeof(AMIAddLicenseKeyRes->CompletionCode);
        }
    }
    fd_conf = fopen(LICENSE_CONF, "r");
    if(fd_conf == NULL)
    {
       TDBG("\nAMIAddLicenseKey(): Problem in opening %s file\n", LICENSE_CONF);
       AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
       return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
    fd_st = fopen(LICENSE_STATUS_FILE, "a+");
    if(fd_st == NULL)
    {
       TDBG("\nAMIAddLicenseKey(): Problem in opening %s file\n", LICENSE_STATUS_FILE);
       fclose(fd_conf);
       AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
       return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
    fd_cnt = fopen(LICENSE_CNT_DAYS_FILE,"r");
    if(fd_cnt == NULL)
    {
        TDBG("\nAMIAddLicenseKey(): Problem in opening %s file\n", LICENSE_CNT_DAYS_FILE);
        fclose(fd_conf);
        fclose(fd_st);
        AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    
    fscanf(fd_cnt, "%hd", &InitDayCnt);
    if(0 == InitDayCnt && 0xFF != LicStr.Lic_Validity)
    {
        InitDayCnt++;
    }
    fclose(fd_cnt);
    FtrList = LicStr.FtrList;
    while(fgets(ConfBf, BUFFER_LENGTH, fd_conf) != NULL)
    {
       INT16U Validity;
       BOOL IsDelApp = FALSE;
       BitVal = FtrList & 0x1;
       FtrList = FtrList >> 1;
       
       if(BitVal != 1)
       {
           continue;
       }
       sscanf(ConfBf, "%[^:]", App_Conf); 
       fseek(fd_st, 0, SEEK_SET);
       while( fgets(StatusBf, BUFFER_LENGTH, fd_st) != NULL)
       {
           sscanf(StatusBf, "%[^:]:%hd", App_St, &Validity);
          // check if app is already licensed and its validity /
           if(0 ==strcmp(App_Conf, App_St))
           {
               if(0xFF == LicStr.Lic_Validity || Validity < LicStr.Lic_Validity)
               {
                   IsDelApp = TRUE;
                   break;
               }
               else
               {           
                   TDBG("\nAMIAddLicenseKey(): Invalid Validity\n");
                   AMIAddLicenseKeyRes->CompletionCode = CC_INVALID_KEY;
                   return sizeof(AMIAddLicenseKeyRes->CompletionCode);
               }
           }
       }
       
       if(IsDelApp)
       {
           fd_tmp = fopen(LICENSE_TEMP_FILE, "w");
           if(fd_tmp == NULL)
           {
               TDBG("\nAMIAddLicenseKey(): Problem in creating %s file\n", LICENSE_TEMP_FILE);
               fclose(fd_st);
               fclose(fd_conf);
           }
           
           fseek(fd_st, 0, SEEK_SET);
           while(fgets(StatusBf, BUFFER_LENGTH, fd_st) != NULL)
           {
               sscanf(StatusBf, "%[^:]:%hd:%hd", App_St, &St_Vdt, &St_Cnt);
               if(strcmp(App_Conf, App_St) != 0 )
               {
                   fprintf(fd_tmp, "%s:%hd:%hd",App_St,St_Vdt,St_Cnt);
               }
           }
           fclose(fd_st);
           
           fd_st=fopen(LICENSE_STATUS_FILE,"w");
           if(NULL == fd_st)
           {
               printf("Problem in opening %s file\n", LICENSE_STATUS_FILE);
               return -1;
           }
           fseek(fd_tmp, 0, SEEK_SET);
           while(!feof(fd_tmp))
           {
               if(fgets(StatusBf, BUFFER_LENGTH, fd_tmp) == NULL)
                   break;
               fputs(StatusBf, fd_st);
           }
         
           fclose(fd_st);
           fclose(fd_tmp);
           fd_st =NULL;
           IsDelApp = FALSE;
       }
       if(fd_st == NULL)
       {
           fd_st = fopen(LICENSE_STATUS_FILE, "a+");
           if(fd_st == NULL)
           {
               TDBG("\nAMIAddLicenseKey(): Problem in opening %s file\n", LICENSE_STATUS_FILE);
               AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
               return sizeof(AMIAddLicenseKeyRes->CompletionCode);
           }
       }
       else
       {
           fseek(fd_st, 0, SEEK_END);
       }
       fprintf(fd_st, "%s:%hd:%hd", App_Conf, (short int)LicStr.Lic_Validity, InitDayCnt);
       fprintf(fd_st,"\n");
    }
    fclose(fd_st);
    fclose(fd_conf);
    if( FtrList > 0)
    {
       TDBG("\nAMIAddLicenseKey(): NON-Existing App \n");
       AMIAddLicenseKeyRes->CompletionCode = CC_INVALID_KEY;
       return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    fd_key = fopen(LICENSE_KEY_FILE, "a+");
    if(NULL == fd_key)
    {
        TDBG("\nAMIAddLicenseKey(): problem in opening license_keys file");
        AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
        return sizeof(AMIAddLicenseKeyRes->CompletionCode);
    }
    memcpy(KeyBf, AMIAddLicenseKeyReq.LicenseKey, LIC_KEY_LEN);
    fputs(KeyBf, fd_key);
    fprintf(fd_key,"\n");
    fclose(fd_key);
    if(0xFF != LicStr.Lic_Validity)
    {
        fd_cnt = fopen(LICENSE_CNT_DAYS_FILE, "w");
        if(NULL == fd_cnt)
        {
            TDBG("\nProblem in Creating %s file\n", fd_cnt);
            AMIAddLicenseKeyRes->CompletionCode = CC_UNSPECIFIED_ERR;
            return sizeof(AMIAddLicenseKeyRes->CompletionCode);
        }
        fprintf(fd_cnt, "%hd", InitDayCnt);
        fclose(fd_cnt);
    }
    safe_system("/etc/init.d/licenseapp.sh manual");
    AMIAddLicenseKeyRes->CompletionCode = CC_NORMAL;
    return sizeof (AMIAddLicenseKeyRes_T);
}


int Decrypt_LicenseKey(unsigned char * LicenseKey, int Size, char *DecryptedLicenseKey)
{
    unsigned char UnMap[Size], DecodedPasswd[Size];
    INT8U key[MAX_SIZE_KEY] = {0};
    memset(UnMap, 0, Size);
    
    if(0 == UnMap32(LicenseKey, Size, UnMap))
    {
        TDBG("\n Decrypt_LicenseKey():Problem in reverse mapping");
        return -1;
    }
    
    memset(DecodedPasswd, 0, Size);
    if(0 == Decode32(UnMap, Size, DecodedPasswd))
    {
        TDBG("\n Decrypt_LicenseKey():Problem in Decoding\n");
        return -1;
    }
   
    /* Get the encryption key from /conf/pwdEncKey file */
    if(getEncryptKey(key))
    {
        TDBG("Unable to get the Decryption key. So, quitting...\n");
        return -1;
    }
    
    return DecryptPassword((char *)DecodedPasswd, Size, DecryptedLicenseKey, Size, (unsigned char *)key);
}

int IsDuplicateKey(unsigned char *LicenseKey)
{
     FILE *fd_Key;
     char LicKeyBf[LIC_KEY_LEN + 1];
   
     fd_Key = fopen (LICENSE_KEY_FILE, "r");
     if(fd_Key == NULL)
     {
         fd_Key = fopen (LICENSE_KEY_FILE, "a+");
         if(fd_Key == NULL)
         {
             TDBG("\nproblem in opening license/keysfile\n");
             return -1;
         }
     }
     
     fseek(fd_Key, 0, SEEK_SET);
     while( NULL != fgets(LicKeyBf, LIC_KEY_LEN + 1, fd_Key))
     {
         if(memcmp(LicKeyBf, LicenseKey, strlen((char *)LicenseKey))== 0)
         {
             fclose(fd_Key);
             return -2;
         }
     }
     
     fclose(fd_Key);
     return 0;
}


