/*=========================================================================== FILE: DB2Utilities.cpp DESCRIPTION: Utility functions for packing/parsing protocol entities using the database PUBLIC ENUMERATIONS AND METHODS: sProtocolEntityKey sDB2PackingInput sDB2NavInput MapQMIEntityTypeToProtocolType MapQMIEntityTypeToQMIServiceType MapQMIProtocolTypeToEntityType DB2GetMaxBufferSize DB2BuildQMIBuffer DB2PackQMIBuffer DB2ReduceQMIBuffer Copyright (c) 2011, Code Aurora Forum. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Code Aurora Forum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ===========================================================================*/ //--------------------------------------------------------------------------- // Include Files //--------------------------------------------------------------------------- #include "StdAfx.h" #include "DB2Utilities.h" #include "QMIBuffers.h" #include "DataPacker.h" #include "ProtocolEntityFieldEnumerator.h" //--------------------------------------------------------------------------- // Definitions //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Free Methods //--------------------------------------------------------------------------- /*=========================================================================== METHOD: MapQMIEntityTypeToQMIServiceType (Public Free Method) DESCRIPTION: Map a DB protocol entity type (for QMI) to a QMI service type PARAMETERS: et [ I ] - Protocol entity type RETURN VALUE: eQMIService ===========================================================================*/ eQMIService MapQMIEntityTypeToQMIServiceType( eDB2EntityType et ) { eQMIService st = eQMI_SVC_ENUM_BEGIN; switch (et) { case eDB2_ET_QMI_CTL_REQ: case eDB2_ET_QMI_CTL_RSP: case eDB2_ET_QMI_CTL_IND: st = eQMI_SVC_CONTROL; break; case eDB2_ET_QMI_WDS_REQ: case eDB2_ET_QMI_WDS_RSP: case eDB2_ET_QMI_WDS_IND: st = eQMI_SVC_WDS; break; case eDB2_ET_QMI_DMS_REQ: case eDB2_ET_QMI_DMS_RSP: case eDB2_ET_QMI_DMS_IND: st = eQMI_SVC_DMS; break; case eDB2_ET_QMI_NAS_REQ: case eDB2_ET_QMI_NAS_RSP: case eDB2_ET_QMI_NAS_IND: st = eQMI_SVC_NAS; break; case eDB2_ET_QMI_QOS_REQ: case eDB2_ET_QMI_QOS_RSP: case eDB2_ET_QMI_QOS_IND: st = eQMI_SVC_QOS; break; case eDB2_ET_QMI_WMS_REQ: case eDB2_ET_QMI_WMS_RSP: case eDB2_ET_QMI_WMS_IND: st = eQMI_SVC_WMS; break; case eDB2_ET_QMI_PDS_REQ: case eDB2_ET_QMI_PDS_RSP: case eDB2_ET_QMI_PDS_IND: st = eQMI_SVC_PDS; break; case eDB2_ET_QMI_AUTH_REQ: case eDB2_ET_QMI_AUTH_RSP: case eDB2_ET_QMI_AUTH_IND: st = eQMI_SVC_AUTH; break; case eDB2_ET_QMI_VOICE_REQ: case eDB2_ET_QMI_VOICE_RSP: case eDB2_ET_QMI_VOICE_IND: st = eQMI_SVC_VOICE; break; case eDB2_ET_QMI_CAT_REQ: case eDB2_ET_QMI_CAT_RSP: case eDB2_ET_QMI_CAT_IND: st = eQMI_SVC_CAT; break; case eDB2_ET_QMI_RMS_REQ: case eDB2_ET_QMI_RMS_RSP: case eDB2_ET_QMI_RMS_IND: st = eQMI_SVC_RMS; break; case eDB2_ET_QMI_OMA_REQ: case eDB2_ET_QMI_OMA_RSP: case eDB2_ET_QMI_OMA_IND: st = eQMI_SVC_OMA; break; } return st; } /*=========================================================================== METHOD: MapQMIEntityTypeToProtocolType (Public Free Method) DESCRIPTION: Map a DB protocol entity type (for QMI) to a buffer protocol type PARAMETERS: et [ I ] - Protocol entity type RETURN VALUE: eProtocolType ===========================================================================*/ eProtocolType MapQMIEntityTypeToProtocolType( eDB2EntityType et ) { eProtocolType pt = ePROTOCOL_ENUM_BEGIN; switch (et) { case eDB2_ET_QMI_WDS_REQ: pt = ePROTOCOL_QMI_WDS_TX; break; case eDB2_ET_QMI_WDS_RSP: case eDB2_ET_QMI_WDS_IND: pt = ePROTOCOL_QMI_WDS_RX; break; case eDB2_ET_QMI_DMS_REQ: pt = ePROTOCOL_QMI_DMS_TX; break; case eDB2_ET_QMI_DMS_RSP: case eDB2_ET_QMI_DMS_IND: pt = ePROTOCOL_QMI_DMS_RX; break; case eDB2_ET_QMI_NAS_REQ: pt = ePROTOCOL_QMI_NAS_TX; break; case eDB2_ET_QMI_NAS_RSP: case eDB2_ET_QMI_NAS_IND: pt = ePROTOCOL_QMI_NAS_RX; break; case eDB2_ET_QMI_QOS_REQ: pt = ePROTOCOL_QMI_QOS_TX; break; case eDB2_ET_QMI_QOS_RSP: case eDB2_ET_QMI_QOS_IND: pt = ePROTOCOL_QMI_QOS_RX; break; case eDB2_ET_QMI_WMS_REQ: pt = ePROTOCOL_QMI_WMS_TX; break; case eDB2_ET_QMI_WMS_RSP: case eDB2_ET_QMI_WMS_IND: pt = ePROTOCOL_QMI_WMS_RX; break; case eDB2_ET_QMI_PDS_REQ: pt = ePROTOCOL_QMI_PDS_TX; break; case eDB2_ET_QMI_PDS_RSP: case eDB2_ET_QMI_PDS_IND: pt = ePROTOCOL_QMI_PDS_RX; break; case eDB2_ET_QMI_AUTH_REQ: pt = ePROTOCOL_QMI_AUTH_TX; break; case eDB2_ET_QMI_AUTH_RSP: case eDB2_ET_QMI_AUTH_IND: pt = ePROTOCOL_QMI_AUTH_RX; break; case eDB2_ET_QMI_VOICE_REQ: pt = ePROTOCOL_QMI_VOICE_TX; break; case eDB2_ET_QMI_VOICE_RSP: case eDB2_ET_QMI_VOICE_IND: pt = ePROTOCOL_QMI_VOICE_RX; break; case eDB2_ET_QMI_CAT_REQ: pt = ePROTOCOL_QMI_CAT_TX; break; case eDB2_ET_QMI_CAT_RSP: case eDB2_ET_QMI_CAT_IND: pt = ePROTOCOL_QMI_CAT_RX; break; case eDB2_ET_QMI_RMS_REQ: pt = ePROTOCOL_QMI_RMS_TX; break; case eDB2_ET_QMI_RMS_RSP: case eDB2_ET_QMI_RMS_IND: pt = ePROTOCOL_QMI_RMS_RX; break; case eDB2_ET_QMI_OMA_REQ: pt = ePROTOCOL_QMI_OMA_TX; break; case eDB2_ET_QMI_OMA_RSP: case eDB2_ET_QMI_OMA_IND: pt = ePROTOCOL_QMI_OMA_RX; break; case eDB2_ET_QMI_CTL_REQ: pt = ePROTOCOL_QMI_CTL_TX; break; case eDB2_ET_QMI_CTL_RSP: case eDB2_ET_QMI_CTL_IND: pt = ePROTOCOL_QMI_CTL_RX; break; } return pt; } /*=========================================================================== METHOD: MapQMIProtocolTypeToEntityType (Public Free Method) DESCRIPTION: Map a buffer protocol type to a DB protocol entity type PARAMETERS: pt [ I ] - Protocol type bIndication [ I ] - Is this for an indication? RETURN VALUE: eDB2EntityType ===========================================================================*/ eDB2EntityType MapQMIProtocolTypeToEntityType( eProtocolType pt, bool bIndication ) { eDB2EntityType et = eDB2_ET_ENUM_BEGIN; switch (pt) { case ePROTOCOL_QMI_WDS_RX: if (bIndication == true) { et = eDB2_ET_QMI_WDS_IND; } else { et = eDB2_ET_QMI_WDS_RSP; } break; case ePROTOCOL_QMI_WDS_TX: et = eDB2_ET_QMI_WDS_REQ; break; case ePROTOCOL_QMI_DMS_RX: if (bIndication == true) { et = eDB2_ET_QMI_DMS_IND; } else { et = eDB2_ET_QMI_DMS_RSP; } break; case ePROTOCOL_QMI_DMS_TX: et = eDB2_ET_QMI_DMS_REQ; break; case ePROTOCOL_QMI_NAS_RX: if (bIndication == true) { et = eDB2_ET_QMI_NAS_IND; } else { et = eDB2_ET_QMI_NAS_RSP; } break; case ePROTOCOL_QMI_NAS_TX: et = eDB2_ET_QMI_NAS_REQ; break; case ePROTOCOL_QMI_QOS_RX: if (bIndication == true) { et = eDB2_ET_QMI_QOS_IND; } else { et = eDB2_ET_QMI_QOS_RSP; } break; case ePROTOCOL_QMI_QOS_TX: et = eDB2_ET_QMI_QOS_REQ; break; case ePROTOCOL_QMI_WMS_RX: if (bIndication == true) { et = eDB2_ET_QMI_WMS_IND; } else { et = eDB2_ET_QMI_WMS_RSP; } break; case ePROTOCOL_QMI_WMS_TX: et = eDB2_ET_QMI_WMS_REQ; break; case ePROTOCOL_QMI_PDS_RX: if (bIndication == true) { et = eDB2_ET_QMI_PDS_IND; } else { et = eDB2_ET_QMI_PDS_RSP; } break; case ePROTOCOL_QMI_PDS_TX: et = eDB2_ET_QMI_PDS_REQ; break; case ePROTOCOL_QMI_AUTH_RX: if (bIndication == true) { et = eDB2_ET_QMI_AUTH_IND; } else { et = eDB2_ET_QMI_AUTH_RSP; } break; case ePROTOCOL_QMI_AUTH_TX: et = eDB2_ET_QMI_AUTH_REQ; break; case ePROTOCOL_QMI_VOICE_RX: if (bIndication == true) { et = eDB2_ET_QMI_VOICE_IND; } else { et = eDB2_ET_QMI_VOICE_RSP; } break; case ePROTOCOL_QMI_VOICE_TX: et = eDB2_ET_QMI_VOICE_REQ; break; case ePROTOCOL_QMI_CAT_RX: if (bIndication == true) { et = eDB2_ET_QMI_CAT_IND; } else { et = eDB2_ET_QMI_CAT_RSP; } break; case ePROTOCOL_QMI_CAT_TX: et = eDB2_ET_QMI_CAT_REQ; break; case ePROTOCOL_QMI_RMS_RX: if (bIndication == true) { et = eDB2_ET_QMI_RMS_IND; } else { et = eDB2_ET_QMI_RMS_RSP; } break; case ePROTOCOL_QMI_RMS_TX: et = eDB2_ET_QMI_RMS_REQ; break; case ePROTOCOL_QMI_OMA_RX: if (bIndication == true) { et = eDB2_ET_QMI_OMA_IND; } else { et = eDB2_ET_QMI_OMA_RSP; } break; case ePROTOCOL_QMI_OMA_TX: et = eDB2_ET_QMI_OMA_REQ; break; case ePROTOCOL_QMI_CTL_RX: if (bIndication == true) { et = eDB2_ET_QMI_CTL_IND; } else { et = eDB2_ET_QMI_CTL_RSP; } break; case ePROTOCOL_QMI_CTL_TX: et = eDB2_ET_QMI_CTL_REQ; break; } return et; } /*=========================================================================== METHOD: DB2GetMaxBufferSize (Public Free Method) DESCRIPTION: Return the maximum size of a payload buffer for given type of protocol entity PARAMETERS: et [ I ] - Protocol entity type RETURN VALUE: ULONG - Maximum ===========================================================================*/ ULONG DB2GetMaxBufferSize( eDB2EntityType et ) { ULONG maxSzInBytes = MAX_SHARED_BUFFER_SIZE; if (IsQMIEntityType( et ) == true) { // QMI items are further constrained in size maxSzInBytes = QMI_MAX_BUFFER_SIZE; } return maxSzInBytes; } /*=========================================================================== METHOD: DB2BuildQMIBuffer (Internal Method) DESCRIPTION: Build and return an allocated shared buffer for the QMI protocol using the specified DB keys and payloads (one per TLV content) PARAMETERS: input [ I ] - Protocol entity key and payload RETURN VALUE: sSharedBuffer * (0 upon failure) ===========================================================================*/ sSharedBuffer * DB2BuildQMIBuffer( const std::vector & input ) { // Assume failure sSharedBuffer * pRef = 0; const ULONG szTransHdr = (ULONG)sizeof(sQMIServiceRawTransactionHeader); const ULONG szMsgHdr = (ULONG)sizeof(sQMIRawMessageHeader); const ULONG szTLVHdr = (ULONG)sizeof(sQMIRawContentHeader); // Need something to build (but not too much) ULONG tlvs = (ULONG)input.size(); if (tlvs == 0 || tlvs > (ULONG)UCHAR_MAX) { return pRef; } // The protocol entity keys need to be consistent const sDB2NavInput & tlvInput = input[0]; if (tlvInput.IsValid() == false || tlvInput.mKey.size() < 3) { return pRef; } eDB2EntityType et = (eDB2EntityType)tlvInput.mKey[0]; if (IsQMIEntityType( et ) == false) { return pRef; } ULONG t = 0; for (t = 0; t < tlvs; t++) { const sDB2NavInput & tlvInput = input[t]; if (tlvInput.mPayloadLen > QMI_MAX_BUFFER_SIZE) { return pRef; } } ULONG szReq = szTransHdr + szMsgHdr + (tlvs * szTLVHdr); szReq += tlvInput.mPayloadLen; for (t = 1; t < tlvs; t++) { const sDB2NavInput & tlv2Input = input[t]; if (tlv2Input.IsValid() == false || tlv2Input.mKey.size() < 3) { return pRef; } if ( (tlvInput.mKey[0] != tlv2Input.mKey[0]) || (tlvInput.mKey[1] != tlv2Input.mKey[1]) ) { return pRef; } szReq += tlv2Input.mPayloadLen; } // What we are building cannot be too large if (szReq > QMI_MAX_BUFFER_SIZE) { return pRef; } BYTE buf[QMI_MAX_BUFFER_SIZE]; sQMIRawContentHeader * pTLV = 0; pTLV = (sQMIRawContentHeader *)&buf[0]; for (t = 0; t < tlvs; t++) { const sDB2NavInput & tlv2Input = input[t]; pTLV->mTypeID = (BYTE)tlv2Input.mKey[2]; pTLV->mLength = (WORD)tlv2Input.mPayloadLen; pTLV++; const BYTE * pPayload = (const BYTE *)pTLV; memcpy( (LPVOID)pPayload, (LPCVOID)tlv2Input.mpPayload, (SIZE_T)tlv2Input.mPayloadLen ); pPayload += tlv2Input.mPayloadLen; pTLV = (sQMIRawContentHeader *)pPayload; } ULONG contentLen = szReq - szTransHdr - szMsgHdr; eQMIService st = MapQMIEntityTypeToQMIServiceType( et ); pRef = sQMIServiceBuffer::BuildBuffer( st, (WORD)tlvInput.mKey[1], IsQMIEntityResponseType( et ), IsQMIEntityIndicationType( et ), &buf[0], contentLen ); return pRef; } /*=========================================================================== METHOD: DB2PackQMIBuffer (Internal Method) DESCRIPTION: Build an allocated shared buffer for the QMI protocol PARAMETERS: db [ I ] - Database to use for packing input [ I ] - Protocol entity key and field values RETURN VALUE: sSharedBuffer * (0 upon failure) ===========================================================================*/ sSharedBuffer * DB2PackQMIBuffer( const cCoreDatabase & db, const std::vector & input ) { // Assume failure sSharedBuffer * pRef = 0; // Need something to build (but not too much) ULONG tlvs = (ULONG)input.size(); if (tlvs == 0 || tlvs > (ULONG)UCHAR_MAX) { return pRef; } // The protocol entity keys need to be consistent const sDB2PackingInput & tlvInput = input[0]; if (tlvInput.IsValid() == false || tlvInput.mKey.size() < 3) { return pRef; } eDB2EntityType et = (eDB2EntityType)tlvInput.mKey[0]; if (IsQMIEntityType( et ) == false) { return pRef; } ULONG t = 0; for (t = 0; t < tlvs; t++) { const sDB2PackingInput & tlvInput = input[t]; if (tlvInput.mDataLen > QMI_MAX_BUFFER_SIZE) { return pRef; } } for (t = 1; t < tlvs; t++) { const sDB2PackingInput & tlv2Input = input[t]; if (tlv2Input.IsValid() == false || tlv2Input.mKey.size() < 3) { return pRef; } if ( (tlvInput.mKey[0] != tlv2Input.mKey[0]) || (tlvInput.mKey[1] != tlv2Input.mKey[1]) ) { return pRef; } } BYTE buf[QMI_MAX_BUFFER_SIZE]; ULONG bufLen = 0; sQMIRawContentHeader * pTLV = 0; pTLV = (sQMIRawContentHeader *)&buf[0]; bool bOK = true; for (t = 0; t < tlvs; t++) { ULONG packedLen = 0; const BYTE * pPackedData = 0; const sDB2PackingInput & tlv2Input = input[t]; if (tlv2Input.mbString == true) { if (tlv2Input.mValues.empty() == false) { // Convert field string to input fields std::list fields = cDataPacker::LoadValues( tlv2Input.mValues ); // Now pack cDataPacker dp( db, tlv2Input.mKey, fields ); bOK = dp.Pack(); if (bOK == false) { break; } pPackedData = dp.GetBuffer( packedLen ); if (pPackedData == 0) { bOK = false; break; } } } else { packedLen = tlv2Input.mDataLen; pPackedData = tlv2Input.mpData; } // Check if we need to adjust buffer cProtocolEntityFieldEnumerator pefe( db, tlv2Input.mKey ); bool bEnum = pefe.Enumerate(); if (bEnum == true) { const std::vector & fieldIDs = pefe.GetFields(); ULONG fieldCount = (ULONG)fieldIDs.size(); if (fieldCount == 1) { const tDB2FieldMap & dbFields = db.GetProtocolFields(); tDB2FieldMap::const_iterator pField = dbFields.find( fieldIDs[0] ); if (pField != dbFields.end()) { const sDB2Field & theField = pField->second; if ( (theField.mType == eDB2_FIELD_STD) && (theField.mTypeVal == (ULONG)eDB2_FIELD_STDTYPE_STRING_ANT) ) { // For QMI we need to strip out the trailing NULL // string terminator when the TLV consists solely // of a string since the length contained in the // TLV structure itself renders the trailing NULL // redundant if (packedLen > 2) { packedLen--; } else { // This is the only way to specify an empty string in QMI // when the TLV consists solely of a string if (packedLen == 1) { packedLen--; } } } } } } bufLen += (ULONG)sizeof(sQMIRawContentHeader); bufLen += packedLen; // What we are building cannot be too large if (bufLen > QMI_MAX_BUFFER_SIZE) { bOK = false; break; } pTLV->mTypeID = (BYTE)tlv2Input.mKey[2]; pTLV->mLength = (WORD)packedLen; pTLV++; const BYTE * pPayload = (const BYTE *)pTLV; memcpy( (LPVOID)pPayload, (LPCVOID)pPackedData, (SIZE_T)packedLen ); pPayload += packedLen; pTLV = (sQMIRawContentHeader *)pPayload; } if (bOK == false) { return pRef; } eQMIService st = MapQMIEntityTypeToQMIServiceType( et ); pRef = sQMIServiceBuffer::BuildBuffer( st, (WORD)tlvInput.mKey[1], IsQMIEntityResponseType( et ), IsQMIEntityIndicationType( et ), &buf[0], bufLen ); return pRef; } /*=========================================================================== METHOD: DB2ReduceQMIBuffer (Public Free Method) DESCRIPTION: Reduce a DIAG buffer to a DB key and payload PARAMETERS: buf [ I ] - Protocol buffer being reduced RETURN VALUE: sDB2NavInput (invalid upon failure) ===========================================================================*/ std::vector DB2ReduceQMIBuffer( const sProtocolBuffer & buf ) { std::vector retInput; // We must have a valid protocol buffer if (buf.IsValid() == false) { return retInput; } eProtocolType pt = (eProtocolType)buf.GetType(); if (IsQMIProtocol( pt ) != true) { return retInput; } sQMIServiceBuffer qmiBuf( buf.GetSharedBuffer() ); std::map tlvs = qmiBuf.GetContents(); bool bErr = false; std::map ::const_iterator pIter; for (pIter = tlvs.begin(); pIter != tlvs.end(); pIter++) { const sQMIRawContentHeader * pHdr = pIter->second; if (pHdr == 0) { bErr = true; break; } bool bIndication = qmiBuf.IsIndication(); eProtocolType pt = (eProtocolType)qmiBuf.GetType(); eDB2EntityType et = MapQMIProtocolTypeToEntityType( pt, bIndication ); sDB2NavInput tmp; tmp.mKey.push_back( (ULONG)et ); tmp.mKey.push_back( qmiBuf.GetMessageID() ); tmp.mKey.push_back( (ULONG)pHdr->mTypeID ); tmp.mPayloadLen = pHdr->mLength; pHdr++; tmp.mpPayload = (const BYTE *)pHdr; if (tmp.IsValid() == true) { retInput.push_back( tmp ); } else { // Ignore empty TLVs if (tmp.mPayloadLen != 0) { bErr = true; break; } } } if (bErr == true) { retInput.clear(); } return retInput; }