blob: 7aad59ca46b19eb122ca8cb26b905b128ceec2b3 [file] [log] [blame]
/******************************************************************************
*(C) Copyright 2014 Marvell International Ltd.
* All Rights Reserved
******************************************************************************/
/* -------------------------------------------------------------------------------------------------------------------
*
* Filename: mbim_protocol.c
*
* Authors: Adrian Zelezniak
*
* Description: MBIM protocol functions are defined in this file
*
* HISTORY:
* Jan 7, 2014 - Initial Version
*
* Notes:
*
******************************************************************************/
/******************************************************************************
* Include files
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define LOG_TAG "MBIM"
#include "mbim_types.h"
#include "mbim_protocol.h"
#include "mbim_util.h"
#include "mbim_basic.h"
#include "mbim_sms.h"
#include "mbim_ussd.h"
#include "mbim_basic_extension.h"
#if defined MBIM_MTIL
#include "mbim_mtil_ind.h"
#include "mbim_mtil.h"
#include "mbim_pcap.h"
#else
#include "mbim_ril.h"
#include "mbim_ril_ind.h"
#endif
/******************************************************************************
* Defines
******************************************************************************/
//#define DUMMY 1
/******************************************************************************
* External Variables
******************************************************************************/
extern basicUuidProcessors basicCidProcessor[UUID_BASIC_CID_MAX];
extern smsUuidProcessors smsCidProcessor[UUID_SMS_CID_MAX];
extern ussdUuidProcessors ussdCidProcessor[UUID_USSD_CID_MAX];
extern basicExtUuidProcessors basicExtCidProcessor[UUID_CID_BASICEXT_MAX];
extern UINT32 cidsFilterArray[UUID_MAX_SERVICE_INDEX][2];
extern char basicFilterArray[UUID_BASIC_CID_MAX];
extern char smsFilterArray[UUID_SMS_CID_MAX];
extern char ussdFilterArray[UUID_USSD_CID_MAX];
//BS
extern Boolean disableUnsolCidConnect;
/******************************************************************************
* Macros
******************************************************************************/
#define BASIC_COMMAND_PROCESS(mbimCmd_p) (basicCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define SMS_COMMAND_PROCESS(mbimCmd_p) (smsCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define USSD_COMMAND_PROCESS(mbimCmd_p) (ussdCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define PHONEBOOK_COMMAND_PROCESS(mbimCmd_p) (phonebookCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define STK_COMMAND_PROCESS(mbimCmd_p) (stkCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define AUTH_COMMAND_PROCESS(mbimCmd_p) (authCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define DSS_COMMAND_PROCESS(mbimCmd_p) (dssCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define BASIC_EXT_COMMAND_PROCESS(mbimCmd_p) (basicExtCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
#define UICC_COMMAND_PROCESS(mbimCmd_p) (uiccCidProcessor[mbimCmd_p->cid])( mbimCmd_p->cid, \
mbimCmd_p->messageHeader.transactionId, \
mbimCmd_p->commandType, \
mbimCmd_p->informationBufferLength, \
(char *)(&mbimCmd_p->InformationBuffer.data[0]));
/******************************************************************************
* Global variables
******************************************************************************/
MBIM_DATABASE mbimDb;
/******************************************************************************
* Function prototypes
******************************************************************************/
static void processOpenMsg(char *dataBuf);
static void processCloseMsg(char *dataBuf, Boolean reOpenState);
static void processCommandMsg(char *dataBuf);
static int mbimSend(char *msg, int length);
static void initFragmentDb(P_MBIM_COMMAND_MSG mbimCmd_p);
static void resetFragmentDb(Boolean freeBuffer);
static P_MBIM_COMMAND_MSG processFragment(P_MBIM_COMMAND_MSG mbimCmd_p);
/******************************************************************************
* Code
******************************************************************************/
/*******************************************************************************\
* Function: MbimProcessEncapCommand
* Description: This function is extract the MBIM command from the encapsualted message and call the
* related callback.
* Parameters: dataBuf - String
*
* Returns: 0=OK, <0=Error Code
\*******************************************************************************/
int MbimProcessEncapCommand(char *dataBuf, UINT32 dataLen)
{
//Pick up pointer to struct
int rc = 0;
P_MBIM_MESSAGE_HEADER mbimHdr_p = (P_MBIM_MESSAGE_HEADER)dataBuf;
//Check that we have valid data (DO we need this?)
if (dataBuf == NULL)
{
MBIM_LOGE("MbimProcessEncapCommand ERROR!!! Databug is NULL");
return MBIM_ERROR_UNKNOWN;
}
//Check that the message is at least as big as MBIM Header
if (dataLen < sizeof(MBIM_MESSAGE_HEADER) )
{
MBIM_LOGE("MbimProcessEncapCommand ERROR!!! Data length shorter than sizeof(MBIM_MESSAGE_HEADER)");
return MBIM_ERROR_LENGTH_MISMATCH;
}
//Check the correct size of received message
if (mbimHdr_p->messageLength > dataLen)
{
MBIM_LOGE("MbimProcessEncapCommand ERROR!!! messageLength shorter than data length");
return MBIM_ERROR_LENGTH_MISMATCH;
}
//Log received Message
logReceivedMbimMsg(mbimHdr_p->messageType, mbimHdr_p->transactionId);
//Check the received command
switch( mbimHdr_p->messageType )
{
case MBIM_OPEN_MSG_E:
processOpenMsg(dataBuf);
break;
case MBIM_CLOSE_MSG_E:
processCloseMsg(dataBuf, FALSE);
break;
case MBIM_COMMAND_MSG_E:
processCommandMsg(dataBuf);
break;
case MBIM_HOST_ERROR_MSG_E:
MBIM_LOGD("Received Host Error Message");//[TBD] what to do with the error (Need to read).
break;
//Unknown message type.
default:
MBIM_LOGE("MbimProcessEncapCommand ERROR!!! Uknown message type: %d", mbimHdr_p->messageType);
rc = MBIM_ERROR_UNKNOWN;
break;
}
return rc;
}
/*******************************************************************************\
* Function: MbimProcessOpenCmd
* Description: This function is extract the MBIM command from the encapsualted message and call the
* related callback.
* Parameters: dataBuf - String
*
* Returns:
\*******************************************************************************/
static void processOpenMsg(char *dataBuf)
{
P_MBIM_OPEN_MSG msg_p = (P_MBIM_OPEN_MSG)dataBuf;
UINT32 transId = msg_p->messageHeader.transactionId;
//We need to do re-open
if (mbimDb.open == TRUE)
{
processCloseMsg(dataBuf, TRUE);
}
mbimDb.open = TRUE;
mbimDb.maxControlTransfer = msg_p->maxControlTransfer; //Used to know when to fragment the message
mbimDb.isForceDetach = FALSE;
MBIM_FREE(mbimDb.inBuf);
mbimDb.inBuf = MBIM_MALLOC(mbimDb.maxControlTransfer);
MBIM_LOGD("OPEN: maxControlTransfer = %d", mbimDb.maxControlTransfer);
//Turn on all indications to MBIM
#if defined (MBIM_MTIL)
//It will filter them according to subscriber list
MtilSendInden(NULL, TRUE);
MtilConfigCmtiIndications(TRUE);
#else
MbimTelSetupIndications(TRUE);
#endif
//Send Open Done MSG
MbimSendOpenDone( transId, MBIM_STATUS_SUCCESS);
}
void MbimHandleCommand (char *dataBuf, int len)
{
P_MBIM_OPEN_MSG msg_p = (P_MBIM_OPEN_MSG)dataBuf;
if (len == sizeof (*msg_p))
{
if (msg_p->messageHeader.messageType == MBIM_OPEN_MSG_E)
{
if (msg_p->maxControlTransfer != mbimDb.maxControlTransferFromDrv)
{
mbimDb.maxControlTransferFromDrv = msg_p->maxControlTransfer;
MBIM_FREE(mbimDb.inBufFromDrv);
mbimDb.inBufFromDrv = MBIM_MALLOC(mbimDb.maxControlTransferFromDrv);
MBIM_LOGD("OPEN: maxControlTransferFromDrv = %d", mbimDb.maxControlTransferFromDrv);
}
}
}
}
/*******************************************************************************\
* Function: MbimProcessClose
* Description: This function is extract the MBIM command from the encapsualted message and call the
* related callback.
* Parameters: dataBuf - String
*
* Returns:
\*******************************************************************************/
static void processCloseMsg(char *dataBuf, Boolean reOpenState)
{
P_MBIM_CLOSE_MSG msg_p = (P_MBIM_CLOSE_MSG)dataBuf;
UINT32 transId = msg_p->messageHeader.transactionId;
//Need to discard all commands in transit [TBD]
//Need to reset received fragments
resetFragmentDb(TRUE);
if (reOpenState == FALSE)
{
//In phase II --> (Close indications).
mbimDb.open = FALSE;
mbimDb.maxControlTransfer = MBIM_MAX_CONTROL_TRANS_DEFAULT;
//Turn off all indications to MBIM
#if defined (MBIM_MTIL)
MtilSendInden(NULL, FALSE);
MtilConfigCmtiIndications(FALSE);
#else
MbimTelSetupIndications(FALSE);
#endif
//Send Close Done MSG
MbimSendCloseDone( transId, MBIM_STATUS_SUCCESS);
MBIM_FREE(mbimDb.inBuf);
mbimDb.inBuf = MBIM_MALLOC(MBIM_MAX_CONTROL_TRANS_DEFAULT);
}
}
/*******************************************************************************\
* Function: MbimProcessEncapCommand
* Description: This function is extract the MBIM command from the encapsualted message and call the
* related callback.
* Parameters: dataBuf - String
*
* Returns:
\*******************************************************************************/
static void processCommandMsg(char *dataBuf)
{
//Pick pu pointer to data
P_MBIM_COMMAND_MSG mbimCmd_p = (P_MBIM_COMMAND_MSG)dataBuf;
int uuidIndex;
//check that the MBIM is open
if (mbimDb.open == FALSE)
{
//Send Error Message to host(MBIM Not OPEN)
MbimSendFunctionErrorMsg(mbimCmd_p->messageHeader.transactionId, MBIM_ERROR_NOT_OPENED);
return;
}
//We always go through the (MBIM command is allocated during fragmentation)
mbimCmd_p = processFragment(mbimCmd_p);
if (mbimCmd_p != NULL)
{
if ( (uuidIndex = UUID2Index (&mbimCmd_p->deviceServiceId)) >= 0 )
{
MBIM_LOGD("UUID Index = %d, MessageCID = %d, TansId = %d, Length = %d Type = %d",
uuidIndex,
mbimCmd_p->cid,
mbimCmd_p->messageHeader.transactionId,
mbimCmd_p->messageHeader.messageLength,
mbimCmd_p->commandType);
switch(uuidIndex)
{
case UUID_BASIC_CONNECT_INDEX:
if (mbimCmd_p->cid < UUID_BASIC_CID_MAX)
{
BASIC_COMMAND_PROCESS(mbimCmd_p);
}
break;
case UUID_SMS_INDEX:
if (mbimCmd_p->cid < UUID_SMS_CID_MAX)
{
SMS_COMMAND_PROCESS(mbimCmd_p);
}
break;
case UUID_USSD_INDEX:
if (mbimCmd_p->cid < UUID_USSD_CID_MAX)
{
USSD_COMMAND_PROCESS(mbimCmd_p);
}
break;
case UUID_PHONEBOOK_INDEX:
break;
case UUID_STK_INDEX:
break;
case UUID_AUTH_INDEX:
break;
case UUID_DSS_INDEX:
break;
case UUID_BASIC_CONNECT_EXTENSIONS_INDEX:
if (mbimCmd_p->cid < UUID_CID_BASICEXT_MAX)
{
BASIC_EXT_COMMAND_PROCESS(mbimCmd_p);
}
break;
case UUID_MS_UICC_LOW_LEVEL_INDEX:
break;
default:
break;
}
}
else
{
MBIM_LOGD("UUID is not supported!");
//send unsupported
P_MBIM_COMMAND_DONE cmd_p = (P_MBIM_COMMAND_DONE)MBIM_MALLOC(sizeof(MBIM_COMMAND_DONE));
cmd_p->messageHeader.messageType = MBIM_COMMAND_DONE_E;
cmd_p->messageHeader.messageLength = sizeof(MBIM_COMMAND_DONE);
cmd_p->messageHeader.transactionId = mbimCmd_p->messageHeader.transactionId;
cmd_p->fragmentHeader.totalFragments = 1;
cmd_p->fragmentHeader.currentFragment= 0;
memcpy(cmd_p->deviceServiceId.uuid, mbimCmd_p->deviceServiceId.uuid, 16);
cmd_p->cid = mbimCmd_p->cid;
cmd_p->status = MBIM_STATUS_NO_DEVICE_SUPPORT;
cmd_p->informationBufferLength = 0;
mbimSend((char *)cmd_p, sizeof(MBIM_COMMAND_DONE));
MBIM_FREE(cmd_p);
}
}//end if mbimCmd_P != null
//Free allocated pointer during fragmentation
MBIM_FREE(mbimCmd_p);
}
/*******************************************************************************\
* Function: MbimSendOpenDone
* Description: This function returns Open Done to MBIM Host
* Parameters: int transId - Unique transaction id received from host
MBIM_STATUS_CODE_ENUM statusCode - The status of the command
*
* Returns:
\*******************************************************************************/
int MbimSendOpenDone(UINT32 transId, MBIM_STATUS_CODE_ENUM statusCode)
{
MBIM_OPEN_DONE rsp;
//MBIM MSG Header
rsp.messageHeader.messageType = MBIM_OPEN_DONE_E;
rsp.messageHeader.messageLength = sizeof(MBIM_OPEN_DONE);
rsp.messageHeader.transactionId = transId;
//status Code
rsp.status = statusCode;
memset(basicFilterArray, 1, sizeof(basicFilterArray));
memset(smsFilterArray, 1, sizeof(smsFilterArray));
memset(ussdFilterArray, 1, sizeof(ussdFilterArray));
// LogMessage();
return mbimSend((char *)&rsp, sizeof(MBIM_OPEN_DONE));
}
/*******************************************************************************\
* Function: MbimSendCloseDone
* Description: This function returns Close Done to MBIM Host
* Parameters: int transId - Unique transaction id received from host
MBIM_STATUS_CODE_ENUM statusCode - The status of the command
*
* Returns:
\*******************************************************************************/
int MbimSendCloseDone(UINT32 transId, MBIM_STATUS_CODE_ENUM statusCode)
{
MBIM_CLOSE_DONE rsp;
//MBIM message Header
rsp.messageHeader.messageType = MBIM_CLOSE_DONE_E;
rsp.messageHeader.messageLength = sizeof(MBIM_CLOSE_DONE);
rsp.messageHeader.transactionId = transId;
//status Code
rsp.status = statusCode;
return mbimSend((char *)&rsp, sizeof(MBIM_CLOSE_DONE));
}
/*******************************************************************************\
* Function: MbimSendFunctionErrorMsg
* Description: This function returns Error Message to MBIM Host
* Parameters: int transId - Unique transaction id received from host
MBIM_STATUS_CODE_ENUM statusCode - The status of the command
*
* Returns:
\*******************************************************************************/
int MbimSendFunctionErrorMsg(UINT32 transId, MBIM_PROTOCOL_ERROR_CODES_ENUM statusCode)
{
MBIM_FUNCTION_ERROR_MSG rsp;
MBIM_LOGD("Function Error: TransId = %d, StatusCode = %d", transId, statusCode);
//MBIM message Header
rsp.messageHeader.messageType = MBIM_FUNCTION_ERROR_MSG_E;
rsp.messageHeader.messageLength = sizeof(MBIM_FUNCTION_ERROR_MSG);
rsp.messageHeader.transactionId = transId;
//Status Code
rsp.errorStatusCode = statusCode;
//Send response to MBIM host
return mbimSend((char *)&rsp, sizeof(MBIM_FUNCTION_ERROR_MSG));
}
/*******************************************************************************\
* Function: MbimSendCommandDone
* Description: This function returns Error Message to MBIM Host
* Parameters: int transId - Unique transaction id received from host
MBIM_STATUS_CODE_ENUM statusCode - The status of the command
*
* Returns:
\*******************************************************************************/
int MbimSendCommandDone(UINT32 transId, int uuidIndex, int cid, MBIM_STATUS_CODE_ENUM status, int bufLen, char *rspData_p)
{
P_MBIM_COMMAND_DONE cmd_p;
char *rspBuf_p;
int fragIndex = 0;
int fragmentPayloadSize = mbimDb.maxControlTransfer - FRAGMENT_HDR_SIZE;
int remBufLen = bufLen;
int numOfFragments = getNumOfFragments(sizeof(MBIM_COMMAND_DONE), bufLen);
int rc = MBIM_OK;
//Allocate the needed size for the response
if (numOfFragments == 1)
rspBuf_p = MBIM_MALLOC(sizeof(MBIM_COMMAND_DONE) + bufLen);
else
rspBuf_p = MBIM_MALLOC(mbimDb.maxControlTransfer);
if (rspBuf_p == 0)
{
MBIM_LOGE("Error Cannot allocate memory");
return MBIM_BIND_MEM_ERROR;
}
if (cid == UUID_CONNECT)
{
disableUnsolCidConnect = FALSE;
MBIM_LOGE("%s: disableUnsolCidConnect = FALSE, CID = %d", __FUNCTION__, cid);
}
//Pick up pointer to first fragment
cmd_p = (P_MBIM_COMMAND_DONE)rspBuf_p;
//MBIM message Header
cmd_p->messageHeader.messageType = MBIM_COMMAND_DONE_E;
cmd_p->messageHeader.messageLength = (sizeof(MBIM_COMMAND_DONE) + bufLen);
cmd_p->messageHeader.transactionId = transId;
cmd_p->fragmentHeader.totalFragments = numOfFragments;
cmd_p->fragmentHeader.currentFragment= 0;
//Fill the command fields that are sent olny once in frist fragment
if ( Index2UUID(&cmd_p->deviceServiceId, uuidIndex) != MBIM_OK ) {
MBIM_LOGE("Unknown UUID. uuidIndex = %d, Cid=%d, bufLen = %d, status = %d", uuidIndex, cid, bufLen, status);
MBIM_FREE(rspBuf_p);
return MBIM_UUID_UKNOWN_ERROR;
}
cmd_p->cid = cid;
cmd_p->status = status;
cmd_p->informationBufferLength = bufLen;
/////////////////////////////////////////////////////////////////////////////////////
// Transmit First framgent
/////////////////////////////////////////////////////////////////////////////////////
//Copy payload data
memcpy((char *)&rspBuf_p[sizeof(MBIM_COMMAND_DONE)], (char *)&rspData_p[0], MIN((int)(mbimDb.maxControlTransfer-sizeof(MBIM_COMMAND_DONE)), remBufLen));
//transmit First Fragment(Send response to MBIM host)
if ( (rc = mbimSend(rspBuf_p, MIN(mbimDb.maxControlTransfer, (int)(sizeof(MBIM_COMMAND_DONE) + bufLen)))) < 0)
{
//Log error and break loop, return error value
MBIM_LOGE("MbimSendCommandDone: Error transmitting Fragment %d, from %d", fragIndex, numOfFragments);
MBIM_FREE(rspBuf_p);
return rc;
}
//Advance Pointer and update remaining payload size
rspData_p += MIN(remBufLen,(int)(mbimDb.maxControlTransfer-sizeof(MBIM_COMMAND_DONE)));
remBufLen -= MIN(remBufLen,(int)(mbimDb.maxControlTransfer-sizeof(MBIM_COMMAND_DONE)));
/////////////////////////////////////////////////////////////////////////////////////
// Transmit all other framgents
/////////////////////////////////////////////////////////////////////////////////////
//See if we need to transmit more fragments, and transmit
for (fragIndex = 1 ; fragIndex < numOfFragments ; fragIndex++)
{
//the rest of the header still keeps the same position and value as before
cmd_p->fragmentHeader.currentFragment = fragIndex;
memcpy(&rspBuf_p[FRAGMENT_HDR_SIZE], rspData_p, MIN(remBufLen, fragmentPayloadSize));
//Transmit new fragment
if ( (rc = mbimSend(rspBuf_p, MIN(mbimDb.maxControlTransfer, (int)(FRAGMENT_HDR_SIZE + remBufLen)))) < 0 )
{
//Log error and break loop, return error value
MBIM_LOGE("MbimSendCommandDone: Error transmitting Fragment %d, from %d", fragIndex, numOfFragments);
break;
}
//Advance Pointer and update remaining payload size
rspData_p += MIN(remBufLen,fragmentPayloadSize);
remBufLen -= MIN(remBufLen,fragmentPayloadSize);
}
//Free allocated buffer
MBIM_FREE(rspBuf_p);
return rc;
}
/*******************************************************************************\
* Function: MbimSendIndicateStatusMsg
* Description: This function returns Error Message to MBIM Host
* Parameters:
*
* Returns:
\*******************************************************************************/
int MbimSendIndicateStatusMsg(int uuidIndex, int cid, int bufLen, char *rspData_p)
{
P_MBIM_INDICATION_STATUS_MSG ind_p;
char *rspBuf_p;
int fragIndex = 0;
int fragmentPayloadSize = mbimDb.maxControlTransfer - FRAGMENT_HDR_SIZE;
int remBufLen = bufLen;
int numOfFragments = getNumOfFragments(sizeof(MBIM_INDICATION_STATUS_MSG), bufLen);
int rc = MBIM_OK;
char *pFilterArray;
//When the MBIM is CLose, remaining indication must be discarded
if (mbimDb.open == FALSE)
{
MBIM_LOGE("MBIM CLOSE, discaring Indication with CID = %d", cid);
return rc;
}
MBIM_LOGD("MbimSendIndicateStatusMsg: uuidIndex = %d", uuidIndex);
if (cidsFilterArray[uuidIndex][0] != 0)
{
pFilterArray = (char *)cidsFilterArray[uuidIndex][0];
if (pFilterArray[cid] == 0)
{
MBIM_LOGD("MbimSendIndicateStatusMsg: Indication with CID = %d is filtered out by host", cid);
return rc;
}
}
if ((disableUnsolCidConnect == TRUE) && (cid == UUID_CONNECT))
{
MBIM_LOGE("disableUnsolCidConnect, CID = %d", cid);
return rc;
}
//Allocate the needed size for the response
if (numOfFragments == 1)
rspBuf_p = MBIM_MALLOC(sizeof(MBIM_INDICATION_STATUS_MSG) + bufLen);
else
rspBuf_p = MBIM_MALLOC(mbimDb.maxControlTransfer);
if (rspBuf_p == 0)
{
MBIM_LOGE("Error Cannot allocate memory");
return MBIM_BIND_MEM_ERROR;
}
//Pick up pointer to first fragment
ind_p = (P_MBIM_INDICATION_STATUS_MSG)rspBuf_p;
//MBIM message Header
ind_p->messageHeader.messageType = MBIM_INDICATE_STATUS_MSG_E;
ind_p->messageHeader.messageLength = (sizeof(MBIM_INDICATION_STATUS_MSG) + bufLen);
ind_p->messageHeader.transactionId = 0;
ind_p->fragmentHeader.totalFragments = numOfFragments;
ind_p->fragmentHeader.currentFragment = 0;
//Fill the command fields that are sent olny once in frist fragment
if ( Index2UUID(&ind_p->deviceServiceId, uuidIndex) != MBIM_OK ) {
MBIM_LOGE("Unknown UUID. uuidIndex = %d, Cid=%d, bufLen = %d", uuidIndex, cid, bufLen);
MBIM_FREE(rspBuf_p);
return MBIM_UUID_UKNOWN_ERROR;
}
ind_p->cid = cid;
ind_p->informationBufferLength = bufLen;
/////////////////////////////////////////////////////////////////////////////////////
// Transmit First framgent
/////////////////////////////////////////////////////////////////////////////////////
//Copy payload data
memcpy((char *)&rspBuf_p[sizeof(MBIM_INDICATION_STATUS_MSG)], (char *)&rspData_p[0], MIN((int)(mbimDb.maxControlTransfer-sizeof(MBIM_INDICATION_STATUS_MSG)), remBufLen));
//transmit First Fragment(Send response to MBIM host)
if ( (rc = mbimSend(rspBuf_p, MIN(mbimDb.maxControlTransfer, (int)(sizeof(MBIM_INDICATION_STATUS_MSG) + bufLen)))) < 0)
{
//Log error and break loop, return error value
MBIM_LOGE("MbimSendIndicateStatusMsg: Error transmitting Fragment %d, from %d", fragIndex, numOfFragments);
MBIM_FREE(rspBuf_p);
return rc;
}
//Advance Pointer and update remaining payload size
rspData_p += MIN(remBufLen,(int)(mbimDb.maxControlTransfer-sizeof(MBIM_INDICATION_STATUS_MSG)));
remBufLen -= MIN(remBufLen,(int)(mbimDb.maxControlTransfer-sizeof(MBIM_INDICATION_STATUS_MSG)));
/////////////////////////////////////////////////////////////////////////////////////
// Transmit all other framgents
/////////////////////////////////////////////////////////////////////////////////////
//See if we need to transmit more fragments, and transmit
for (fragIndex = 1 ; fragIndex < numOfFragments ; fragIndex++)
{
//the rest of the header still keeps the same position and value as before
ind_p->fragmentHeader.currentFragment = fragIndex;
memcpy(&rspBuf_p[FRAGMENT_HDR_SIZE], rspData_p, MIN(remBufLen, fragmentPayloadSize));
//Transmit new fragment
if ( (rc = mbimSend(rspBuf_p, MIN(mbimDb.maxControlTransfer, (int)(FRAGMENT_HDR_SIZE + remBufLen)))) < 0 )
{
//Log error and break loop, return error value
MBIM_LOGE("MbimSendIndicateStatusMsg: Error transmitting Fragment %d, from %d", fragIndex, numOfFragments);
break;
}
//Advance Pointer and update remaining payload size
rspData_p += MIN(remBufLen,fragmentPayloadSize);
remBufLen -= MIN(remBufLen,fragmentPayloadSize);
}
//Free allocated buffer
MBIM_FREE(rspBuf_p);
return rc;
}
/*******************************************************************************\
* Function: mbimSend
* Description: This function writes the respond message to the binded MBIM interface
* Parameters: dataBuf - String
*
* Returns: 0=OK, <0=Error Code
\*******************************************************************************/
static int mbimSend(char *msg, int length)
{
int kernelError = 0;
logSentMbimMsg(msg);
if (!mbimDb.open)
{
MBIM_LOGE("%s: MBIM closed.", __FUNCTION__);
return MBIM_BIND_WRITE_ERROR;
}
if (mbimDb.mbimDeviceHandler != 0)
{
/* pcap log */
PCAP_RSP_WRITE(msg,length);
kernelError = write(mbimDb.mbimDeviceHandler, (void*)msg, length);
if ( kernelError < 0 )
{
//Send Error Trace
P_MBIM_MESSAGE_HEADER mbimHdr_p = (P_MBIM_MESSAGE_HEADER)msg;
MBIM_LOGE("Problem sending command %d, transId = %d, Len = %d, Kernel Error = %d", mbimHdr_p->messageType, mbimHdr_p->transactionId ,length, kernelError);
MBIM_LOGE("Kernel Error = %d, closing MBIM", kernelError);
//close indications and Close MBIM
//mbimDb.open = FALSE; // TODO: check if needed
//Turn off all indications to MBIM
#if defined (MBIM_MTIL)
MtilSendInden(NULL, FALSE);
MtilConfigCmtiIndications(FALSE);
#else
MbimTelSetupIndications(FALSE);
#endif
mbimDb.open = FALSE;
return MBIM_BIND_WRITE_ERROR;
}
return MBIM_OK;
}
else
{
MBIM_LOGE("MBIM Kernel not Binded");
//Should I do something more? Recover? Try to rebind? [TBD]
return MBIM_BIND_ERROR;
}
}
/*******************************************************************************\
* Function: MbimKernelBind
* Description: This function bind the MBim device to our code
* Parameters: dataBuf - String
*
* Returns: 0=OK, <0=Error Code
\*******************************************************************************/
int MbimKernelBind(void)
{
char filename[80];
snprintf(filename, 79, "%s", MBIM_DEVICE_FILE);
mbimDb.mbimDeviceHandler = open(filename, O_RDWR);
if (mbimDb.mbimDeviceHandler < 0)
{
MBIM_LOGE("ADRIAN --> BIND ERROR, code %d, error=%s", mbimDb.mbimDeviceHandler, strerror( errno ));
MBIM_LOGE("Driver Filename = %s, define = %s", filename, MBIM_DEVICE_FILE );
return MBIM_BIND_ERROR;
}
return MBIM_OK;
}
/*******************************************************************************\
* Function: initFragmentDb
* Description: Initialize the fragments in the Database
* Parameters: int transactionId, the transaction Id of the new fragmented packets we are going to receive.
*
* Returns: 0=OK, <0=Error Code
\*******************************************************************************/
static void initFragmentDb(P_MBIM_COMMAND_MSG mbimCmd_p)
{
mbimDb.fragmentDb.transactionId = mbimCmd_p->messageHeader.transactionId;
mbimDb.fragmentDb.lastFragment = -1;
mbimDb.fragmentDb.dataOffset = 0;
mbimDb.fragmentDb.TotalAllocSize = mbimCmd_p->informationBufferLength + sizeof(MBIM_COMMAND_MSG);
mbimDb.fragmentDb.mbimCmd_p = (char *)MBIM_MALLOC(mbimDb.fragmentDb.TotalAllocSize);
}
/*******************************************************************************\
* Function: resetFragmentDb
* Description: reset the fragment in the Database
* Parameters: int transactionId, the transaction Id of the new fragmented packets we are going to receive.
*
* Returns: 0=OK, <0=Error Code
\*******************************************************************************/
static void resetFragmentDb(Boolean freeBuffer)
{
mbimDb.fragmentDb.transactionId = 0;
mbimDb.fragmentDb.lastFragment = -1;
mbimDb.fragmentDb.dataOffset = 0;
mbimDb.fragmentDb.TotalAllocSize = 0;
//Check if we need to free the buffer or not.
if (freeBuffer == TRUE)
{
if ( mbimDb.fragmentDb.mbimCmd_p != NULL )
MBIM_FREE(mbimDb.fragmentDb.mbimCmd_p);
}
mbimDb.fragmentDb.mbimCmd_p = NULL;
}
/*******************************************************************************\
* Function: processFragment
* Description: Process the received fragments, and construct the new database.
* Parameters: int transactionId, the transaction Id of the new fragmented packets we are going to receive.
*
* Returns: P_MBIM_COMMAND_MSG - NULL of all fragments were not received are there was an error
* Pointer to complete MBIM message if we received all fragments
\*******************************************************************************/
static P_MBIM_COMMAND_MSG processFragment(P_MBIM_COMMAND_MSG mbimCmd_p)
{
MBIM_PROTOCOL_ERROR_CODES_ENUM errorCode = MBIM_ERROR_NO_ERROR;
char *retPtr = NULL;
///////////////////////////////////////////////////////////////
// No fragmentation needed
///////////////////////////////////////////////////////////////
if (mbimCmd_p->fragmentHeader.totalFragments == 1)
{
//Need to send error for previous transaction ID that was fragmented
if ( mbimDb.fragmentDb.transactionId != 0 )
{
//Send Error to host
MbimSendFunctionErrorMsg(mbimDb.fragmentDb.transactionId, MBIM_ERROR_FRAGMENT_OUT_OF_SEQUENCE);
resetFragmentDb(TRUE);
}
//Allocate and copy data to new buffer
retPtr = MBIM_MALLOC(mbimCmd_p->messageHeader.messageLength);
memcpy(retPtr, (char *)mbimCmd_p, (mbimCmd_p->messageHeader.messageLength));
return (P_MBIM_COMMAND_MSG)retPtr;
}
///////////////////////////////////////////////////////////////
// Take care of fragmented packets
///////////////////////////////////////////////////////////////
if ( mbimDb.fragmentDb.transactionId == 0 )
initFragmentDb(mbimCmd_p);
//check that we received fragment for the correct transaction ID and fragment in sequence
if ( ( (UINT32)mbimDb.fragmentDb.transactionId != mbimCmd_p->messageHeader.transactionId ) ||
((UINT32)(mbimDb.fragmentDb.lastFragment+1) != mbimCmd_p->fragmentHeader.currentFragment ) )
{
errorCode = MBIM_ERROR_FRAGMENT_OUT_OF_SEQUENCE;
}
if ( errorCode == MBIM_ERROR_NO_ERROR )
{
//Copy first fragment
if (mbimCmd_p->fragmentHeader.currentFragment == 0)
{
//Check correct message length
if (mbimCmd_p->messageHeader.messageLength > (UINT32)mbimDb.fragmentDb.TotalAllocSize)
{
errorCode = MBIM_ERROR_LENGTH_MISMATCH;
}
else
{
memcpy(mbimDb.fragmentDb.mbimCmd_p, (char *)mbimCmd_p, mbimCmd_p->messageHeader.messageLength);
mbimDb.fragmentDb.dataOffset = mbimCmd_p->messageHeader.messageLength;
}
}
else
{
if ((mbimDb.fragmentDb.dataOffset + (mbimCmd_p->messageHeader.messageLength-FRAGMENT_HDR_SIZE)) > (UINT32)mbimDb.fragmentDb.TotalAllocSize)
{
errorCode = MBIM_ERROR_LENGTH_MISMATCH;
}
else
{
//Copy another fragment
memcpy(&mbimDb.fragmentDb.mbimCmd_p[mbimDb.fragmentDb.dataOffset], &(((char *)mbimCmd_p)[FRAGMENT_HDR_SIZE]), mbimCmd_p->messageHeader.messageLength-FRAGMENT_HDR_SIZE);
mbimDb.fragmentDb.dataOffset += (mbimCmd_p->messageHeader.messageLength-FRAGMENT_HDR_SIZE);
}
}
}
if (errorCode != MBIM_ERROR_NO_ERROR)
{
//Send error message to Host
MbimSendFunctionErrorMsg(mbimDb.fragmentDb.transactionId, MBIM_ERROR_FRAGMENT_OUT_OF_SEQUENCE);
resetFragmentDb(TRUE);
}
else
{
//Check if we received all fragments
if ( mbimCmd_p->fragmentHeader.totalFragments == (mbimCmd_p->fragmentHeader.currentFragment + 1))
{
//Return pointer to Complete MBIM message
retPtr = mbimDb.fragmentDb.mbimCmd_p;
resetFragmentDb(FALSE);
}
}
return (P_MBIM_COMMAND_MSG)retPtr;
}
void MbimInit(void)
{
//MBIM initial state to Close
mbimDb.mbimDeviceHandler = 0;
mbimDb.open = FALSE;
mbimDb.maxControlTransfer = MBIM_MAX_CONTROL_TRANS_DEFAULT;
mbimDb.inBuf = MBIM_MALLOC(mbimDb.maxControlTransfer);
#if defined (MBIM_USE_RIL)
mbimDb.maxControlTransferFromDrv = MBIM_MAX_CONTROL_TRANS_DEFAULT;
mbimDb.inBufFromDrv = MBIM_MALLOC(mbimDb.maxControlTransfer);
#endif
mbimDb.CimiRetryCounter = 0;
mbimDb.HomeProviderIdSize = 0;
memset(mbimDb.HomeProviderMccMnc, 0, 7);
memset(mbimDb.HomeProviderName, 0, MBIM_MAX_OPERATOR_NAME_SIZE);
mbimDb.mbimRegisterTech = 0;
mbimDb.sim.simReadyState = MBIMSubscriberReadyStateSimNotInserted;
//Added to align packet order
mbimDb.packetServiceIndPending = FALSE;
mbimDb.connectIndPending = FALSE;
mbimDb.connectIndPendingCid = 0;
mbimDb.mbimRegisterState = MBIMRegisterStateDeregistered;
//No loopback on start
mbimDb.loopbackEnabled = FALSE;
mbimDb.loopbackSessionId = -1;
mbimDb.internetSessionId = -1;
mbimDb.cidActivated = -1;
resetFragmentDb(TRUE);
//Init CM values
mbimDb.gbForceVZWOnly = FALSE;
mbimDb.gbIsPlmnVerizonNetwork = FALSE;
mbimDb.gbNVZW = FALSE;
mbimDb.gbNIMS = FALSE;
mbimDb.mbimExVersion = MBIMEx_v3;
mbimDb.mbimNegVersion = MBIMEx_v3;
//Init Mutex
pthread_mutex_init(&mbimDb.ip_connect_mutex, NULL);
}