/*=========================================================================== FILE: GobiQMICoreNAS.cpp DESCRIPTION: QUALCOMM Gobi QMI Based API Core (NAS Service) PUBLIC CLASSES AND FUNCTIONS: cGobiQMICore 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 "GobiQMICore.h" #include "QMIBuffers.h" //--------------------------------------------------------------------------- // Definitions //--------------------------------------------------------------------------- // Maximum length for a scanned network description const ULONG MAX_SNI_DESCRIPTION_LEN = 255; //--------------------------------------------------------------------------- // Pragmas (pack structs) //--------------------------------------------------------------------------- #pragma pack( push, 1 ) /*=========================================================================*/ // Struct sEVDOCustomSCPConfig // Struct to represent CDMA 1xEV-DO custom SCP config /*=========================================================================*/ struct sEVDOCustomSCPConfig { public: BYTE mbActive; ULONG mProtocolMask; ULONG mBroadcastMask; ULONG mApplicationMask; }; /*=========================================================================*/ // Struct sScannedNetworkInfo // Struct to represent scanned network information /*=========================================================================*/ struct sScannedNetworkInfo { public: USHORT mMCC; USHORT mMNC; ULONG mInUse; ULONG mRoaming; ULONG mForbidden; ULONG mPreferred; CHAR mDescription[MAX_SNI_DESCRIPTION_LEN]; }; /*=========================================================================*/ // Struct sScannedNetworkRATInfo // Struct to represent scanned network RAT information /*=========================================================================*/ struct sScannedNetworkRATInfo { public: USHORT mMCC; USHORT mMNC; ULONG mRAT; }; //--------------------------------------------------------------------------- // Pragmas //--------------------------------------------------------------------------- #pragma pack( pop ) /*=========================================================================*/ // cGobiQMICore Methods /*=========================================================================*/ /*=========================================================================== METHOD: GetANAAAAuthenticationStatus (Public Method) DESCRIPTION: This function gets the AN-AAA authentication status PARAMETERS: pStatus [ O ] - AN-AAA authentication status RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetANAAAAuthenticationStatus( ULONG * pStatus ) { // Validate arguments if (pStatus == 0) { return eGOBI_ERR_INVALID_ARG; } // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_AAA_AUTH_STATUS; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() < 1) { return eGOBI_ERR_INVALID_RSP; } // Populate the index *pStatus = (ULONG)pf[0].mValue.mU32; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetSignalStrengths (Public Method) DESCRIPTION: This function gets the current available signal strengths (in dBm) as measured by the device PARAMETERS: pArraySizes [I/O] - Upon input the maximum number of elements that each array can contain can contain. Upon successful output the actual number of elements in each array pSignalStrengths [ O ] - Received signal strength array (dBm) pRadioInterfaces [ O ] - Radio interface technology array RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetSignalStrengths( ULONG * pArraySizes, INT8 * pSignalStrengths, ULONG * pRadioInterfaces ) { // Validate arguments if ( (pArraySizes == 0) || (*pArraySizes == 0) || (pSignalStrengths == 0) || (pRadioInterfaces == 0) ) { return eGOBI_ERR_INVALID_ARG; } ULONG maxSignals = (ULONG)*pArraySizes; // Assume failure *pArraySizes = 0; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_RSSI; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() < 2) { return eGOBI_ERR_INVALID_RSP; } // Remove any values outside the legal range std::map sigMap; INT8 sigVal = pf[0].mValue.mS8; ULONG radioVal = pf[1].mValue.mU32; if (sigVal <= -30 && sigVal > -125 && radioVal != 0) { sigMap[radioVal] = sigVal; } // Parse the TLV we want (by DB key) tlvKey = sProtocolEntityKey( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() > 2) { ULONG fi = 0; ULONG auxSigs = (ULONG)pf[fi++].mValue.mU16; if (pf.size() >= 1 + 2 * auxSigs) { for (ULONG s = 0; s < auxSigs; s++, fi += 2) { sigVal = pf[fi].mValue.mS8; radioVal = pf[fi + 1].mValue.mU32; if (sigVal <= -30 && sigVal > -125 && radioVal != 0) { sigMap[radioVal] = sigVal; } } } } ULONG sigCount = 0; std::map ::const_iterator pIter; for (pIter = sigMap.begin(); pIter != sigMap.end(); pIter++, sigCount++) { if (sigCount < maxSignals) { pSignalStrengths[sigCount] = pIter->second; pRadioInterfaces[sigCount] = pIter->first; *pArraySizes = sigCount + 1; } } // No valid signals? if (sigCount == 0) { return eGOBI_ERR_NO_SIGNAL; } return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetRFInfo (Public Method) DESCRIPTION: This function gets the current RF information PARAMETERS: pInstanceSize [I/O] - Upon input the maximum number of elements that the RF info instance array can contain. Upon success the actual number of elements in the RF info instance array pInstances [ O ] - The RF info instance array RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetRFInfo( BYTE * pInstanceSize, BYTE * pInstances ) { // Validate arguments if (pInstanceSize == 0 || *pInstanceSize == 0 || pInstances == 0) { return eGOBI_ERR_INVALID_ARG; } // Assume failure BYTE maxInstances = *pInstanceSize; *pInstanceSize = 0; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_RF_INFO; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); ULONG fieldCount = (ULONG)pf.size(); if (fieldCount < 1) { return eGOBI_ERR_INVALID_RSP; } BYTE ifaceCount = pf[0].mValue.mU8; if (fieldCount < 1 + ((ULONG)ifaceCount * 3)) { return eGOBI_ERR_INVALID_RSP; } if (ifaceCount > maxInstances) { ifaceCount = maxInstances; } ULONG * pOutput = (ULONG *)pInstances; for (BYTE i = 0; i < ifaceCount; i++) { ULONG offset = 3 * (ULONG)i; *pOutput++ = pf[offset + 1].mValue.mU32; *pOutput++ = pf[offset + 2].mValue.mU32; *pOutput++ = (ULONG)pf[offset + 3].mValue.mU16; } *pInstanceSize = ifaceCount; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: PerformNetworkScan (Public Method) DESCRIPTION: This function performs a scan for available networks PARAMETERS: pInstanceSize [I/O] - Upon input the maximum number of elements that the network info instance array can contain. Upon success the actual number of elements in the network info instance array pInstances [ O ] - The network info instance array RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::PerformNetworkScan( BYTE * pInstanceSize, BYTE * pInstances ) { // Validate arguments if ( (pInstanceSize == 0) || (*pInstanceSize == 0) || (pInstances == 0) ) { return eGOBI_ERR_INVALID_ARG; } BYTE maxInstances = *pInstanceSize; // Assume failure *pInstanceSize = 0; // This can take a really long time ULONG to = MAX_REQ_TIMEOUT; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_SCAN_NETS; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID, to ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); ULONG maxIdx = (ULONG)pf.size(); if (maxIdx-- < 1) { return eGOBI_ERR_INVALID_RSP; } ULONG idx = 0; BYTE netCount = pf[idx++].mValue.mU8; if (netCount > maxInstances) { netCount = maxInstances; } sScannedNetworkInfo * pNet = (sScannedNetworkInfo *)pInstances; for (BYTE i = 0; i < netCount; i++) { // Validate field count if (idx + 6 > maxIdx) { return eGOBI_ERR_INVALID_RSP; } pNet->mMCC = pf[idx++].mValue.mU16; pNet->mMNC = pf[idx++].mValue.mU16; pNet->mInUse = pf[idx++].mValue.mU32; pNet->mRoaming = pf[idx++].mValue.mU32; pNet->mForbidden = pf[idx++].mValue.mU32; pNet->mPreferred = pf[idx++].mValue.mU32; memset( &pNet->mDescription[0], 0, (SIZE_T)MAX_SNI_DESCRIPTION_LEN ); BYTE descLen = pf[idx++].mValue.mU8; if (descLen > 0) { std::string netDesc( pf[idx++].mValueString ); ULONG actualLen = netDesc.size(); if (actualLen >= MAX_SNI_DESCRIPTION_LEN) { actualLen = MAX_SNI_DESCRIPTION_LEN - 1; } memcpy( (LPVOID)&pNet->mDescription[0], (LPCSTR)netDesc.c_str(), (SIZE_T)actualLen ); } pNet++; } *pInstanceSize = netCount; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: PerformNetworkRATScan (Public Method) DESCRIPTION: This function performs a scan for available networks (includes RAT) PARAMETERS: pInstanceSize [I/O] - Upon input the maximum number of elements that the network info instance array can contain. Upon success the actual number of elements in the network info instance array pInstances [ O ] - The network info instance array pRATSize [I/O] - Upon input the maximum number of elements that the RAT info instance array can contain. Upon success the actual number of elements in the RAT info instance array pRATInstances [ O ] - The RAT info instance array RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::PerformNetworkRATScan( BYTE * pInstanceSize, BYTE * pInstances, BYTE * pRATSize, BYTE * pRATInstances ) { // Validate arguments if ( (pInstanceSize == 0) || (*pInstanceSize == 0) || (pInstances == 0) || (pRATSize == 0) || (*pRATSize == 0) || (pRATInstances == 0) ) { return eGOBI_ERR_INVALID_ARG; } BYTE maxInstances = *pInstanceSize; BYTE maxRATInstances = *pRATSize; // Assume failure *pInstanceSize = 0; *pRATSize = 0; // This can take a really long time ULONG to = MAX_REQ_TIMEOUT; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_SCAN_NETS; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID, to ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); ULONG maxIdx = (ULONG)pf.size(); if (maxIdx-- < 1) { return eGOBI_ERR_INVALID_RSP; } ULONG idx = 0; BYTE netCount = pf[idx++].mValue.mU8; if (netCount > maxInstances) { netCount = maxInstances; } sScannedNetworkInfo * pNet = (sScannedNetworkInfo *)pInstances; for (BYTE i = 0; i < netCount; i++) { // Validate field count if (idx + 6 > maxIdx) { return eGOBI_ERR_INVALID_RSP; } pNet->mMCC = pf[idx++].mValue.mU16; pNet->mMNC = pf[idx++].mValue.mU16; pNet->mInUse = pf[idx++].mValue.mU32; pNet->mRoaming = pf[idx++].mValue.mU32; pNet->mForbidden = pf[idx++].mValue.mU32; pNet->mPreferred = pf[idx++].mValue.mU32; memset( &pNet->mDescription[0], 0, (SIZE_T)MAX_SNI_DESCRIPTION_LEN ); BYTE descLen = pf[idx++].mValue.mU8; if (descLen > 0) { std::string netDesc( pf[idx++].mValueString ); ULONG actualLen = netDesc.size(); if (actualLen >= MAX_SNI_DESCRIPTION_LEN) { actualLen = MAX_SNI_DESCRIPTION_LEN - 1; } LPCSTR pNetDesc = netDesc.c_str(); memcpy( (LPVOID)&pNet->mDescription[0], (LPCVOID)pNetDesc, (SIZE_T)actualLen ); } pNet++; } // Parse the TLV we want (by DB key) tlvKey = sProtocolEntityKey( eDB2_ET_QMI_NAS_RSP, msgID, 17 ); pf = ParseTLV( db, rsp, tlvs, tlvKey ); maxIdx = (ULONG)pf.size(); if (maxIdx-- < 1) { return eGOBI_ERR_INVALID_RSP; } idx = 0; BYTE ratCount = pf[idx++].mValue.mU8; if (ratCount > maxRATInstances) { ratCount = maxRATInstances; } sScannedNetworkRATInfo * pRAT = (sScannedNetworkRATInfo *)pRATInstances; for (BYTE r = 0; r < ratCount; r++) { // Validate field count if (idx + 2 > maxIdx) { return eGOBI_ERR_INVALID_RSP; } pRAT->mMCC = pf[idx++].mValue.mU16; pRAT->mMNC = pf[idx++].mValue.mU16; pRAT->mRAT = pf[idx++].mValue.mU32; pRAT++; } *pInstanceSize = netCount; *pRATSize = ratCount; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: InitiateNetworkRegistration (Public Method) DESCRIPTION: This function initiates a network registration PARAMETERS: regType [ I ] - Registration type mcc [ I ] - Mobile country code (ignored for auto registration) mnc [ I ] - Mobile network code (ignored for auto registration) rat [ I ] - Radio access type (ignored for auto registration) RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::InitiateNetworkRegistration( ULONG regType, WORD mcc, WORD mnc, ULONG rat ) { WORD msgID = (WORD)eQMI_NAS_REGISTER_NET; std::vector piv; std::ostringstream tmp; tmp << (UINT)regType; sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 1 ); sDB2PackingInput pi( pek, (LPCSTR)tmp.str().c_str() ); piv.push_back( pi ); if (regType == 2) { // We need to add the manual registration data // "%hu %hu %u" std::ostringstream tmp2; tmp2 << (USHORT)mcc << " " << (USHORT)mnc << " " << (UINT)rat; pek = sProtocolEntityKey( eDB2_ET_QMI_NAS_REQ, msgID, 16 ); pi = sDB2PackingInput( pek, (LPCSTR)tmp2.str().c_str() ); piv.push_back( pi ); } // Pack up the QMI request const cCoreDatabase & db = GetDatabase(); sSharedBuffer * pRequest = DB2PackQMIBuffer( db, piv ); // Send the QMI request, check result, and return return SendAndCheckReturn( eQMI_SVC_NAS, pRequest, 30000 ); } /*=========================================================================== METHOD: InitiateDomainAttach (Public Method) DESCRIPTION: This function initiates a domain attach (or detach) PARAMETERS: action [ I ] - PS attach action (attach or detach) RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::InitiateDomainAttach( ULONG action ) { WORD msgID = (WORD)eQMI_NAS_ATTACH_DETACH; std::vector piv; std::ostringstream tmp; tmp << (UINT)action; sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 16 ); sDB2PackingInput pi( pek, (LPCSTR)tmp.str().c_str() ); piv.push_back( pi ); // Pack up the QMI request const cCoreDatabase & db = GetDatabase(); sSharedBuffer * pRequest = DB2PackQMIBuffer( db, piv ); // Send the QMI request, check result, and return return SendAndCheckReturn( eQMI_SVC_NAS, pRequest, 30000 ); } /*=========================================================================== METHOD: GetServingNetwork (Public Method) DESCRIPTION: Gets information regarding the system that currently provides service to the device PARAMETERS: pRegistrationState [ O ] - Registration state pCSDomain [ O ] - Circuit switch domain status pPSDomain [ O ] - Packet switch domain status pRAN [ O ] - Radio access network pRadioIfacesSize [I/O] - Upon input the maximum number of elements that the radio interfaces can contain. Upon successful output the actual number of elements in the radio interface array pRadioIfaces [ O ] - The radio interface array pRoaming [ O ] - Roaming indicator (0xFFFFFFFF - Unknown) pMCC [ O ] - Mobile country code (0xFFFF - Unknown) pMNC [ O ] - Mobile network code (0xFFFF - Unknown) nameSize [ I ] - The maximum number of characters (including NULL terminator) that the network name array can contain pName [ O ] - The network name or description represented as a NULL terminated string (empty string returned when unknown) RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetServingNetwork( ULONG * pRegistrationState, ULONG * pCSDomain, ULONG * pPSDomain, ULONG * pRAN, BYTE * pRadioIfacesSize, BYTE * pRadioIfaces, ULONG * pRoaming, WORD * pMCC, WORD * pMNC, BYTE nameSize, CHAR * pName ) { // Validate arguments if ( (pRegistrationState == 0) || (pCSDomain == 0) || (pPSDomain == 0) || (pRAN == 0) || (pRadioIfacesSize == 0) || (*pRadioIfacesSize == 0) || (pRadioIfaces == 0) || (pRoaming == 0) || (pMCC == 0) || (pMNC == 0) || (nameSize == 0) || (pName == 0) ) { return eGOBI_ERR_INVALID_ARG; } BYTE maxRadioIfaces = *pRadioIfacesSize; // Assume failure *pRadioIfacesSize = 0; *pRoaming = ULONG_MAX; *pMCC = USHRT_MAX; *pMNC = USHRT_MAX; *pName = 0; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_SS_INFO; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey1( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); cDataParser::tParsedFields pf1 = ParseTLV( db, rsp, tlvs, tlvKey1 ); if (pf1.size() < 5) { return eGOBI_ERR_INVALID_RSP; } // Populate the variables *pRegistrationState = pf1[0].mValue.mU32; *pCSDomain = pf1[1].mValue.mU32; *pPSDomain = pf1[2].mValue.mU32; *pRAN = pf1[3].mValue.mU32; BYTE activeRadioIfaces = pf1[4].mValue.mU8; if (pf1.size() < 5 + (ULONG)activeRadioIfaces) { return eGOBI_ERR_INVALID_RSP; } if (activeRadioIfaces > maxRadioIfaces) { activeRadioIfaces = maxRadioIfaces; } ULONG * pOutRadioIfaces = (ULONG *)pRadioIfaces; for (ULONG r = 0; r < activeRadioIfaces; r++) { *pOutRadioIfaces++ = pf1[5 + r].mValue.mU32; } *pRadioIfacesSize = activeRadioIfaces; // Parse the optional TLV we want (by DB key) sProtocolEntityKey tlvKey2( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); cDataParser::tParsedFields pf2 = ParseTLV( db, rsp, tlvs, tlvKey2 ); if (pf2.size() >= 1) { *pRoaming = pf2[0].mValue.mU32; } // Parse the optional TLV we want (by DB key) sProtocolEntityKey tlvKey3( eDB2_ET_QMI_NAS_RSP, msgID, 18 ); cDataParser::tParsedFields pf3 = ParseTLV( db, rsp, tlvs, tlvKey3 ); if (pf3.size() >= 3) { *pMCC = pf3[0].mValue.mU16; *pMNC = pf3[1].mValue.mU16; // Network name? if (pf3[2].mValue.mU8 > 0 && pf3.size() >= 4) { LONG strLen = pf3[3].mValueString.size(); if (strLen > 0) { // Space to perform the copy? if (nameSize < strLen + 1) { return eGOBI_ERR_BUFFER_SZ; } memcpy( (LPVOID)pName, (LPCSTR)pf3[3].mValueString.c_str(), strLen ); pName[strLen] = 0; } } } return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetServingNetworkCapabilities (Public Method) DESCRIPTION: Gets information regarding the data capabilities of the system that currently provides service to the device PARAMETERS: pDataCapsSize [I/O] - Upon input the maximum number of elements that the data capabilities array can contain. Upon success the actual number of elements in the data capabilities array pDataCaps [ O ] - The data capabilities array RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetServingNetworkCapabilities( BYTE * pDataCapsSize, BYTE * pDataCaps ) { // Validate arguments if ( (pDataCapsSize == 0) || (*pDataCapsSize == 0) || (pDataCaps == 0) ) { return eGOBI_ERR_INVALID_ARG; } BYTE maxDataCaps = *pDataCapsSize; // Assume failure *pDataCapsSize = 0; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_SS_INFO; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 17 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() < 1) { return eGOBI_ERR_INVALID_RSP; } BYTE activeDataCaps = pf[0].mValue.mU8; if (pf.size() < 1 + (ULONG)activeDataCaps) { return eGOBI_ERR_INVALID_RSP; } if (activeDataCaps > maxDataCaps) { activeDataCaps = maxDataCaps; } ULONG * pOutDataCaps = (ULONG *)pDataCaps; for (ULONG d = 0; d < activeDataCaps; d++) { *pOutDataCaps++ = pf[1 + d].mValue.mU32; } *pDataCapsSize = activeDataCaps; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetDataBearerTechnology (Public Method) DESCRIPTION: This function retrieves the current data bearer technology (only valid when connected) PARAMETERS: pDataCaps [ O ] - The data bearer technology RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetDataBearerTechnology( ULONG * pDataBearer ) { // Validate arguments if (pDataBearer == 0) { return eGOBI_ERR_INVALID_ARG; } // Generate and send the QMI request WORD msgID = (WORD)eQMI_WDS_GET_DATA_BEARER; sProtocolBuffer rsp = SendSimple( eQMI_SVC_WDS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_WDS_RSP, msgID, 1 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() < 1) { return eGOBI_ERR_INVALID_RSP; } // Populate the state *pDataBearer = pf[0].mValue.mU32; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetHomeNetwork (Public Method) DESCRIPTION: This function retrieves information about the home network of the device PARAMETERS: pMCC [ O ] - Mobile country code pMNC [ O ] - Mobile network code nameSize [ I ] - The maximum number of characters (including NULL terminator) that the network name array can contain pName [ O ] - The network name or description represented as a NULL terminated string (empty string returned when unknown) pSID [ O ] - Home network system ID (0xFFFF - Unknown) pNID [ O ] - Home network ID (0xFFFF - Unknown) RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetHomeNetwork( WORD * pMCC, WORD * pMNC, BYTE nameSize, CHAR * pName, WORD * pSID, WORD * pNID ) { // Validate arguments if ( (pMCC == 0) || (pMNC == 0) || (nameSize == 0) || (pName == 0) || (pSID == 0) ) { return eGOBI_ERR_INVALID_ARG; } // Assume failure *pName = 0; *pSID = USHRT_MAX; *pNID = USHRT_MAX; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_HOME_INFO; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey1( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); cDataParser::tParsedFields pf1 = ParseTLV( db, rsp, tlvs, tlvKey1 ); if (pf1.size() < 3) { return eGOBI_ERR_INVALID_RSP; } // Populate the variables *pMCC = pf1[0].mValue.mU16; *pMNC = pf1[1].mValue.mU16; // Network name? if (pf1[2].mValue.mU8 > 0 && pf1.size() >= 4) { LONG strLen = pf1[3].mValueString.size(); if (strLen > 0) { // Space to perform the copy? if (nameSize < strLen + 1) { return eGOBI_ERR_BUFFER_SZ; } memcpy( (LPVOID)pName, (LPCSTR)pf1[3].mValueString.c_str(), strLen ); pName[strLen] = 0; } } // Parse the optional TLV we want (by DB key) sProtocolEntityKey tlvKey2( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); cDataParser::tParsedFields pf2 = ParseTLV( db, rsp, tlvs, tlvKey2 ); if (pf2.size() >= 2) { *pSID = pf2[0].mValue.mU16; *pNID = pf2[1].mValue.mU16; } return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: SetNetworkPreference (Public Method) DESCRIPTION: This function sets the network registration preference PARAMETERS: technologyPref [ I ] - Technology preference bitmap duration [ I ] - Duration of active preference RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::SetNetworkPreference( ULONG technologyPref, ULONG duration ) { // Buffer to hold technology preference TLV (ID = 1) const ULONG TLV_HDR_SZ = (ULONG)sizeof( sQMIRawContentHeader ); BYTE req[3 + TLV_HDR_SZ]; // Fill out TLV header sQMIRawContentHeader * pTLV = (sQMIRawContentHeader *)&req[0]; pTLV->mLength = 3; pTLV->mTypeID = 1; // Copy packed technology preference WORD as-is WORD * pTmp = (WORD *)&req[TLV_HDR_SZ]; *pTmp = (WORD)technologyPref; // Fill out duration req[TLV_HDR_SZ + 2] = (BYTE)duration; // Pack TLV into a QMI NAS request sSharedBuffer * pRequest = 0; pRequest = sQMIServiceBuffer::BuildBuffer( eQMI_SVC_NAS, eQMI_NAS_SET_TECH_PREF, false, false, &req[0], 3 + TLV_HDR_SZ ); // Send the QMI request, check result, and return return SendAndCheckReturn( eQMI_SVC_NAS, pRequest ); } /*=========================================================================== METHOD: GetNetworkPreference (Public Method) DESCRIPTION: This function returns the network registration preference PARAMETERS: pTechnologyPref [ O ] - Technology preference bitmap pDuration [ O ] - Duration of active preference pPersistentTechnologyPref [ O ] - Persistent technology preference bitmap RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetNetworkPreference( ULONG * pTechnologyPref, ULONG * pDuration, ULONG * pPersistentTechnologyPref ) { // Validate arguments if ( (pTechnologyPref == 0) || (pDuration == 0) || (pPersistentTechnologyPref == 0) ) { return eGOBI_ERR_INVALID_ARG; } // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_TECH_PREF; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey1( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); sDB2NavInput ni1 = FindTLV( tlvs, tlvKey1 ); if (ni1.mPayloadLen < 3) { return eGOBI_ERR_INVALID_RSP; } const BYTE * pData = ni1.mpPayload; const WORD * pTmp = (const WORD *)pData; pData += 2; // Populate the variables *pTechnologyPref = (ULONG)*pTmp; *pDuration = (ULONG)*pData; // Until we know any better the persistent setting is the current setting *pPersistentTechnologyPref = *pTechnologyPref; // Parse the optional TLV we want (by DB key) sProtocolEntityKey tlvKey2( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); sDB2NavInput ni2 = FindTLV( tlvs, tlvKey2 ); if (ni2.mPayloadLen >= 2) { pTmp = (const WORD *)ni2.mpPayload; *pPersistentTechnologyPref = (ULONG)*pTmp; } return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: SetCDMANetworkParameters (Public Method) DESCRIPTION: This function sets the desired CDMA network parameters PARAMETERS: pSPC [ I ] - Six digit service programming code pForceRev0 [ I ] - (Optional) Force CDMA 1x-EV-DO Rev. 0 mode? pCustomSCP [ I ] - (Optional) Use a custom config for CDMA 1x-EV-DO SCP? pProtocol [ I ] - (Optional) Protocol mask for custom SCP config pBroadcast [ I ] - (Optional) Broadcast mask for custom SCP config pApplication [ I ] - (Optional) Application mask for custom SCP config pRoaming [ I ] - (Optional) Roaming preference RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::SetCDMANetworkParameters( CHAR * pSPC, BYTE * pForceRev0, BYTE * pCustomSCP, ULONG * pProtocol, ULONG * pBroadcast, ULONG * pApplication, ULONG * pRoaming ) { // If you specify one of the custom SCP config fields then you must // specify them all ULONG scpCount = 0; if (pCustomSCP != 0) { scpCount++; } if (pProtocol != 0) { scpCount++; } if (pBroadcast != 0) { scpCount++; } if (pApplication != 0) { scpCount++; } if (scpCount != 0 && scpCount != 4) { return eGOBI_ERR_INVALID_ARG; } // Rev. 0 and SCP custom config are mutually exclusive if (pForceRev0 != 0 && scpCount == 4) { if (*pForceRev0 != 0 && *pCustomSCP != 0) { return eGOBI_ERR_INVALID_ARG; } } WORD msgID = (WORD)eQMI_NAS_SET_NET_PARAMS; std::vector piv; // Need to start with SPC? if (pForceRev0 != 0 || scpCount == 4) { // Validate arguments if (pSPC == 0 || pSPC[0] == 0) { return eGOBI_ERR_INVALID_ARG; } std::string spc( pSPC ); if (spc.size() > 6) { return eGOBI_ERR_INVALID_ARG; } int nNonDigit = spc.find_first_not_of( "0123456789" ); std::string digitSPC = spc.substr( 0, nNonDigit ); if (digitSPC.size() != spc.size()) { return eGOBI_ERR_INVALID_ARG; } sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 16 ); sDB2PackingInput pi( pek, (LPCSTR)spc.c_str() ); piv.push_back( pi ); } if (pForceRev0 != 0) { // "%u" std::ostringstream tmp; tmp << (UINT)(*pForceRev0 == 0 ? 0 : 1); sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 20 ); sDB2PackingInput pi( pek, (LPCSTR)tmp.str().c_str() ); piv.push_back( pi ); } if (scpCount == 4) { // "%u %u %u %u %u %u %u %u %u %u %u %u" std::ostringstream tmp; tmp << (UINT)(*pCustomSCP == 0 ? 0 : 1) << (UINT)(*pProtocol & 0x00000001 ? 1 : 0) << (UINT)(*pProtocol & 0x00000002 ? 1 : 0) << (UINT)(*pProtocol & 0x00000004 ? 1 : 0) << (UINT)(*pProtocol & 0x00000008 ? 1 : 0) << (UINT)(*pProtocol & 0x00000010 ? 1 : 0) << (UINT)(*pProtocol & 0x00000020 ? 1 : 0) << (UINT)(*pProtocol & 0x00000040 ? 1 : 0) << (UINT)(*pProtocol & 0x00000080 ? 1 : 0) << (UINT)(*pBroadcast & 0x00000001 ? 1 : 0) << (UINT)(*pApplication & 0x00000001 ? 1 : 0) << (UINT)(*pApplication & 0x00000002 ? 1 : 0); sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 21 ); sDB2PackingInput pi( pek, (LPCSTR)tmp.str().c_str() ); piv.push_back( pi ); } if (pRoaming != 0) { // "%u" std::ostringstream tmp; tmp << (UINT)*pRoaming; sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 22 ); sDB2PackingInput pi( pek, (LPCSTR)tmp.str().c_str() ); piv.push_back( pi ); } // We require something to actually configure if (piv.size() == 0) { // Much ado about nothing return eGOBI_ERR_INVALID_ARG; } // Pack up the QMI request const cCoreDatabase & db = GetDatabase(); sSharedBuffer * pRequest = DB2PackQMIBuffer( db, piv ); // Send the QMI request, check result, and return return SendAndCheckReturn( eQMI_SVC_NAS, pRequest, 5000 ); } /*=========================================================================== METHOD: GetCDMANetworkParameters (Public Method) DESCRIPTION: This function gets the current CDMA network parameters PARAMETERS: pSCI [ O ] - Slot cycle index pSCM [ O ] - Station class mark pRegHomeSID [ O ] - Register on home SID? pRegForeignSID [ O ] - Register on foreign SID? pRegForeignNID [ O ] - Register on foreign NID? pForceRev0 [ O ] - Force CDMA 1x-EV-DO Rev. 0 mode? pCustomSCP [ O ] - Use a custom config for CDMA 1x-EV-DO SCP? pProtocol [ O ] - Protocol mask for custom SCP config pBroadcast [ O ] - Broadcast mask for custom SCP config pApplication [ O ] - Application mask for custom SCP config pRoaming [ O ] - Roaming preference RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetCDMANetworkParameters( BYTE * pSCI, BYTE * pSCM, BYTE * pRegHomeSID, BYTE * pRegForeignSID, BYTE * pRegForeignNID, BYTE * pForceRev0, BYTE * pCustomSCP, ULONG * pProtocol, ULONG * pBroadcast, ULONG * pApplication, ULONG * pRoaming ) { // Validate arguments if ( (pSCI == 0) || (pSCM == 0) || (pRegHomeSID == 0) || (pRegForeignSID == 0) || (pRegForeignNID == 0) || (pForceRev0 == 0) || (pCustomSCP == 0) || (pProtocol == 0) || (pBroadcast == 0) || (pApplication == 0) || (pRoaming == 0) ) { return eGOBI_ERR_INVALID_ARG; } *pSCI = UCHAR_MAX; *pSCM = UCHAR_MAX; *pRegHomeSID = UCHAR_MAX; *pRegForeignSID = UCHAR_MAX; *pRegForeignNID = UCHAR_MAX; *pForceRev0 = UCHAR_MAX; *pCustomSCP = UCHAR_MAX; *pProtocol = ULONG_MAX; *pBroadcast = ULONG_MAX; *pApplication = ULONG_MAX; *pRoaming = UCHAR_MAX; // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_NET_PARAMS; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLVs we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 17 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() >= 1) { *pSCI = pf[0].mValue.mU8; } tlvKey = sProtocolEntityKey( eDB2_ET_QMI_NAS_RSP, msgID, 18 ); pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() >= 1) { *pSCM = pf[0].mValue.mU8; } tlvKey = sProtocolEntityKey( eDB2_ET_QMI_NAS_RSP, msgID, 19 ); pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() >= 3) { *pRegHomeSID = pf[0].mValue.mU8; *pRegForeignSID = pf[0].mValue.mU8; *pRegForeignNID = pf[0].mValue.mU8; } tlvKey = sProtocolEntityKey( eDB2_ET_QMI_NAS_RSP, msgID, 20 ); pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() >= 1) { *pForceRev0 = pf[0].mValue.mU8; } tlvKey = sProtocolEntityKey ( eDB2_ET_QMI_NAS_RSP, msgID, 21 ); sDB2NavInput ni = FindTLV( tlvs, tlvKey ); if (ni.mPayloadLen >= (ULONG)sizeof( sEVDOCustomSCPConfig )) { const sEVDOCustomSCPConfig * pData = 0; pData = (const sEVDOCustomSCPConfig *)ni.mpPayload; *pCustomSCP = pData->mbActive; *pProtocol = pData->mProtocolMask; *pBroadcast = pData->mBroadcastMask; *pApplication = pData->mApplicationMask; } tlvKey = sProtocolEntityKey( eDB2_ET_QMI_NAS_RSP, msgID, 22 ); pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() >= 1) { *pRoaming = pf[0].mValue.mU32; } return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetACCOLC (Public Method) DESCRIPTION: This function returns the Access Overload Class (ACCOLC) of the device PARAMETERS: pACCOLC [ O ] - The ACCOLC RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetACCOLC( BYTE * pACCOLC ) { // Validate arguments if (pACCOLC == 0) { return eGOBI_ERR_INVALID_ARG; } // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_ACCOLC; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 1 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() < 1) { return eGOBI_ERR_INVALID_RSP; } // Populate the ACCOLC *pACCOLC = pf[0].mValue.mU8; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: SetACCOLC (Public Method) DESCRIPTION: This function sets the Access Overload Class (ACCOLC) of the device PARAMETERS: pSPC [ I ] - NULL terminated string representing the six digit service programming code accolc [ I ] - The ACCOLC RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::SetACCOLC( CHAR * pSPC, BYTE accolc ) { // Validate arguments if (pSPC == 0 || pSPC[0] == 0) { return eGOBI_ERR_INVALID_ARG; } std::string spc( pSPC ); if (spc.size() > 6) { return eGOBI_ERR_INVALID_ARG; } int nNonDigit = spc.find_first_not_of( "0123456789" ); std::string digitSPC = spc.substr( 0, nNonDigit ); if (digitSPC.size() != spc.size()) { return eGOBI_ERR_INVALID_ARG; } WORD msgID = (WORD)eQMI_NAS_SET_ACCOLC; std::vector piv; // "%s %u" std::ostringstream tmp; tmp << spc << " " << (UINT)accolc; sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 1 ); sDB2PackingInput pi( pek, (LPCSTR)tmp.str().c_str() ); piv.push_back( pi ); // Pack up the QMI request const cCoreDatabase & db = GetDatabase(); sSharedBuffer * pRequest = DB2PackQMIBuffer( db, piv ); // Send the QMI request, check result, and return return SendAndCheckReturn( eQMI_SVC_NAS, pRequest, 5000 ); } /*=========================================================================== METHOD: GetPLMNMode (Public Method) DESCRIPTION: This function returns the PLMN mode from the CSP PARAMETERS: pMode [ O ] - PLMN mode RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetPLMNMode( ULONG * pMode ) { // Validate arguments if (pMode == 0) { return eGOBI_ERR_INVALID_ARG; } // Generate and send the QMI request WORD msgID = (WORD)eQMI_NAS_GET_PLMN_MODE; sProtocolBuffer rsp = SendSimple( eQMI_SVC_NAS, msgID ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Prepare TLVs for parsing std::vector tlvs = DB2ReduceQMIBuffer( qmiRsp ); const cCoreDatabase & db = GetDatabase(); // Parse the TLV we want (by DB key) sProtocolEntityKey tlvKey( eDB2_ET_QMI_NAS_RSP, msgID, 16 ); cDataParser::tParsedFields pf = ParseTLV( db, rsp, tlvs, tlvKey ); if (pf.size() < 1) { return eGOBI_ERR_INVALID_RSP; } // Populate the PLMN mode *pMode = (ULONG)pf[0].mValue.mU8; return eGOBI_ERR_NONE; } /*=========================================================================== METHOD: GetPLMNName (Public Method) DESCRIPTION: This function returns PLMN name information for the given MCC/MNC PARAMETERS: mcc [ I ] - Mobile country code mnc [ I ] - Mobile network code pNamesSize [I/O] - Upon input the size in BYTEs of the name structure array. Upon success the actual number of BYTEs copied to the name structure array pNames [ O ] - The name structure array RETURN VALUE: eGobiError - Return code ===========================================================================*/ eGobiError cGobiQMICore::GetPLMNName( USHORT mcc, USHORT mnc, ULONG * pNamesSize, BYTE * pNames ) { // Validate arguments if ( (pNamesSize == 0) || (*pNamesSize == 0) || (pNames == 0) ) { return eGOBI_ERR_INVALID_ARG; } ULONG maxSz = *pNamesSize; *pNamesSize = 0; WORD msgID = (WORD)eQMI_NAS_GET_PLMN_NAME; std::vector piv; // "%hu %hu" std::ostringstream tmp; tmp << mcc << " " << mnc; sProtocolEntityKey pek( eDB2_ET_QMI_NAS_REQ, msgID, 1 ); sDB2PackingInput pi( pek, tmp.str().c_str() ); piv.push_back( pi ); // Pack up the QMI request const cCoreDatabase & db = GetDatabase(); sSharedBuffer * pRequest = DB2PackQMIBuffer( db, piv ); sProtocolBuffer rsp = Send( eQMI_SVC_NAS, pRequest ); if (rsp.IsValid() == false) { return GetCorrectedLastError(); } // Did we receive a valid QMI response? sQMIServiceBuffer qmiRsp( rsp.GetSharedBuffer() ); if (qmiRsp.IsValid() == false) { return eGOBI_ERR_MALFORMED_RSP; } // Check the mandatory QMI result TLV for success ULONG rc = 0; ULONG ec = 0; bool bResult = qmiRsp.GetResult( rc, ec ); if (bResult == false) { return eGOBI_ERR_MALFORMED_RSP; } else if (rc != 0) { return GetCorrectedQMIError( ec ); } // Try to find TLV ID 16 std::map tlvs; tlvs = qmiRsp.GetContents(); std::map ::const_iterator pIter; pIter = tlvs.find( 16 ); if (pIter == tlvs.end()) { return eGOBI_ERR_INVALID_RSP; } // Enough space to copy result? const sQMIRawContentHeader * pHdr = pIter->second; ULONG needSz = (ULONG)pHdr->mLength; if (needSz == 0) { return eGOBI_ERR_INVALID_RSP; } *pNamesSize = needSz; if (needSz > maxSz) { return eGOBI_ERR_BUFFER_SZ; } pHdr++; const BYTE * pData = (const BYTE *)pHdr; memcpy( (LPVOID)pNames, (LPCVOID)pData, (SIZE_T)needSz ); return eGOBI_ERR_NONE; }