libqmi-qmuxd/gobi-api/GobiAPI_2013-07-31-1347/Gobi3000Translation/Gobi3000TranslationNAS.cpp

2022 lines
57 KiB
C++

/*===========================================================================
FILE:
Gobi3000TranslationNAS.cpp
DESCRIPTION:
QUALCOMM Translation for Gobi 3000 (NAS Service)
Copyright (c) 2013, The Linux Foundation. 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 The Linux Foundation 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 "Gobi3000Translation.h"
// 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 )
/*===========================================================================
METHOD:
ParseGetANAAAAuthenticationStatus
DESCRIPTION:
This function gets the AN-AAA authentication status
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
pStatus [ O ] - AN-AAA authentication status
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG ParseGetANAAAAuthenticationStatus(
ULONG inLen,
const BYTE * pIn,
ULONG * pStatus )
{
// Validate arguments
if (pIn == 0 || pStatus == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Find the TLV
const sNASGetANAAAAuthenticationStatusResponse_Status * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx01 < sizeof( sNASGetANAAAAuthenticationStatusResponse_Status ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pStatus = pTLVx01->mANAAAAuthenticationStatus;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetSignalStrength
DESCRIPTION:
This function gets the current signal strength (in dBm) as measured by
the device, the signal strength returned will be one of the currently
available technologies with preference CDMA 1xEV-DO, CDMA, AMPS,
WCDMA, GSM
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
pSignalStrength [ O ] - Received signal strength (dBm)
pRadioInterface [ O ] - Radio interface technology
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG ParseGetSignalStrength(
ULONG inLen,
const BYTE * pIn,
INT8 * pSignalStrength,
ULONG * pRadioInterface )
{
// Validate arguments
if (pSignalStrength == 0 || pRadioInterface == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
ULONG sigSz = 12;
INT8 sigs[12];
ULONG radios[12];
ULONG qcErr = ParseGetSignalStrengths( inLen,
pIn,
&sigSz,
&sigs[0],
&radios[0] );
if (qcErr != eGOBI_ERR_NONE)
{
return qcErr;
}
std::map <ULONG, INT8> sigMap;
for (ULONG s = 0; s < sigSz; s++)
{
sigMap[radios[s]] = sigs[s];
}
std::map <ULONG, INT8>::const_iterator pIter;
// HDR?
pIter = sigMap.find( 2 );
if (pIter != sigMap.end())
{
*pSignalStrength = pIter->second;
*pRadioInterface = pIter->first;
return eGOBI_ERR_NONE;
}
// CDMA?
pIter = sigMap.find( 1 );
if (pIter != sigMap.end())
{
*pSignalStrength = pIter->second;
*pRadioInterface = pIter->first;
return eGOBI_ERR_NONE;
}
// AMPS?
pIter = sigMap.find( 3 );
if (pIter != sigMap.end())
{
*pSignalStrength = pIter->second;
*pRadioInterface = pIter->first;
return eGOBI_ERR_NONE;
}
// WCDMA?
pIter = sigMap.find( 5 );
if (pIter != sigMap.end())
{
*pSignalStrength = pIter->second;
*pRadioInterface = pIter->first;
return eGOBI_ERR_NONE;
}
// GSM?
pIter = sigMap.find( 4 );
if (pIter != sigMap.end())
{
*pSignalStrength = pIter->second;
*pRadioInterface = pIter->first;
return eGOBI_ERR_NONE;
}
// Error values
*pSignalStrength = -128;
*pRadioInterface = 0;
return eGOBI_ERR_NO_SIGNAL;
}
/*===========================================================================
METHOD:
ParseGetSignalStrengths
DESCRIPTION:
This function gets the current available signal strengths (in dBm)
as measured by the device
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetSignalStrengths(
ULONG inLen,
const BYTE * pIn,
ULONG * pArraySizes,
INT8 * pSignalStrengths,
ULONG * pRadioInterfaces )
{
// Validate arguments
if (pIn == 0
|| pArraySizes == 0
|| *pArraySizes == 0
|| pSignalStrengths == 0
|| pRadioInterfaces == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
ULONG maxSignals = (ULONG)*pArraySizes;
// Assume failure
*pArraySizes = 0;
// Find the first signal strength value
const sNASGetSignalStrengthResponse_SignalStrength * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx01 < sizeof( sNASGetSignalStrengthResponse_SignalStrength ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Weed out bogus values
std::map <ULONG, INT8> sigMap;
INT8 sigVal = pTLVx01->mSignalStrengthdBm;
ULONG radioVal = pTLVx01->mRadioInterface;
if (sigVal <= -30 && sigVal > -125 && radioVal != 0)
{
sigMap[radioVal] = sigVal;
}
// Handle list, if present
const sNASGetSignalStrengthResponse_SignalStrengthList * pTLVx10;
ULONG outLenx10;
rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx10 < sizeof( sNASGetSignalStrengthResponse_SignalStrengthList ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
ULONG auxSigs = pTLVx10->mNumberOfInfoInstances;
if (auxSigs > maxSignals)
{
auxSigs = maxSignals;
}
const sNASGetSignalStrengthResponse_SignalStrengthList::sInfo * pInfo;
// Verify there is room for the array in the TLV
if (outLenx10 < sizeof( sNASGetSignalStrengthResponse_SignalStrengthList )
+ sizeof( sNASGetSignalStrengthResponse_SignalStrengthList::sInfo )
* auxSigs)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Align to the first array element
pInfo = (const sNASGetSignalStrengthResponse_SignalStrengthList::sInfo *)
((const BYTE *)pTLVx10
+ sizeof( sNASGetSignalStrengthResponse_SignalStrengthList ));
for (ULONG s = 0; s < auxSigs; s++)
{
sigVal = pInfo->mSignalStrengthdBm;
radioVal = pInfo->mRadioInterface;
if (sigVal <= -30 && sigVal > -125 && radioVal != 0)
{
sigMap[radioVal] = sigVal;
}
// Move pInfo forward one element
pInfo++;
}
}
ULONG sigCount = 0;
std::map <ULONG, INT8>::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:
ParseGetRFInfo
DESCRIPTION:
This function gets the current RF information
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetRFInfo(
ULONG inLen,
const BYTE * pIn,
BYTE * pInstanceSize,
BYTE * pInstances )
{
// Validate arguments
if (pIn == 0
|| pInstanceSize == 0
|| *pInstanceSize == 0
|| pInstances == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Assume failure
BYTE maxInstances = *pInstanceSize;
*pInstanceSize = 0;
// Find the TLV
const sNASGetRFInfoResponse_RFInfo * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx01 < sizeof( sNASGetRFInfoResponse_RFInfo ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
BYTE ifaceCount = pTLVx01->mNumberOfInstances;
if (ifaceCount > maxInstances)
{
ifaceCount = maxInstances;
}
const sNASGetRFInfoResponse_RFInfo::sInstance * pInstance;
// Verify there is room for the array in the TLV
if (outLenx01 < sizeof( sNASGetRFInfoResponse_RFInfo )
+ sizeof( sNASGetRFInfoResponse_RFInfo::sInstance )
* ifaceCount)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Align to the first array element
pInstance = (const sNASGetRFInfoResponse_RFInfo::sInstance *)
((const BYTE *)pTLVx01
+ sizeof( sNASGetRFInfoResponse_RFInfo ));
ULONG * pOutput = (ULONG *)pInstances;
for (BYTE i = 0; i < ifaceCount; i++)
{
*pOutput++ = pInstance->mRadioInterface;
*pOutput++ = pInstance->mActiveBandClass;
*pOutput++ = pInstance->mActiveChannel;
// Move pInstance forward one element
pInstance++;
}
*pInstanceSize = ifaceCount;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParsePerformNetworkScan
DESCRIPTION:
This function performs a scan for available networks
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParsePerformNetworkScan(
ULONG inLen,
const BYTE * pIn,
BYTE * pInstanceSize,
BYTE * pInstances )
{
// Validate arguments
if (pIn == 0
|| pInstanceSize == 0
|| *pInstanceSize == 0
|| pInstances == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
BYTE maxInstances = *pInstanceSize;
// Assume failure
*pInstanceSize = 0;
// Find the TLV
const sNASPerformNetworkScanResponse_NetworkInfo * pTLVx10;
ULONG outLenx10;
ULONG rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx10 < sizeof( sNASPerformNetworkScanResponse_NetworkInfo ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
UINT16 netCount = pTLVx10->mNumberOfInfoInstances;
if (netCount > maxInstances)
{
netCount = maxInstances;
}
const sNASPerformNetworkScanResponse_NetworkInfo::sNetworkInfo * pNetInfo;
// Align to the first array element
pNetInfo = (const sNASPerformNetworkScanResponse_NetworkInfo::sNetworkInfo *)
((const BYTE *)pTLVx10
+ sizeof( sNASPerformNetworkScanResponse_NetworkInfo ));
ULONG offset = sizeof( sNASPerformNetworkScanResponse_NetworkInfo );
sScannedNetworkInfo * pNet = (sScannedNetworkInfo *)pInstances;
for (BYTE i = 0; i < netCount; i++)
{
// Check TLV size
if (offset > outLenx10)
{
return eGOBI_ERR_MALFORMED_RSP;
}
pNet->mMCC = pNetInfo->mMobileCountryCode;
pNet->mMNC = pNetInfo->mMobileNetworkCode;
pNet->mInUse = pNetInfo->mInUseStatus;
pNet->mRoaming = pNetInfo->mRoamingStatus;
pNet->mForbidden = pNetInfo->mForbiddenStatus;
pNet->mPreferred = pNetInfo->mPreferredStatus;
memset( &pNet->mDescription[0], 0, MAX_SNI_DESCRIPTION_LEN );
BYTE descLen = pNetInfo->mDescriptionLength;
if (descLen > 0)
{
// Move pNetInfo forward
pNetInfo++;
offset += sizeof( sNASPerformNetworkScanResponse_NetworkInfo::sNetworkInfo );
// Check TLV size
if (offset > outLenx10)
{
return eGOBI_ERR_MALFORMED_RSP;
}
std::string netDesc( (LPCSTR)pNetInfo );
ULONG actualLen = (ULONG)netDesc.size();
if (actualLen >= MAX_SNI_DESCRIPTION_LEN)
{
actualLen = MAX_SNI_DESCRIPTION_LEN - 1;
}
LPCSTR pNetDesc = netDesc.c_str();
memcpy( &pNet->mDescription[0], pNetDesc, actualLen );
// Move pNetInfo past string
pNetInfo = (const sNASPerformNetworkScanResponse_NetworkInfo::sNetworkInfo *)
((const BYTE *)pNetInfo + descLen);
offset += descLen;
}
pNet++;
}
*pInstanceSize = (BYTE)netCount;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParsePerformNetworkRATScan
DESCRIPTION:
This function performs a scan for available networks (includes RAT)
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParsePerformNetworkRATScan(
ULONG inLen,
const BYTE * pIn,
BYTE * pInstanceSize,
BYTE * pInstances,
BYTE * pRATSize,
BYTE * pRATInstances )
{
// Validate arguments
if (pIn == 0
|| pInstanceSize == 0
|| *pInstanceSize == 0
|| pInstances == 0
|| pRATSize == 0
|| *pRATSize == 0
|| pRATInstances == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
BYTE maxRATInstances = *pRATSize;
// Assume failure
*pInstanceSize = 0;
*pRATSize = 0;
// First, generate the instances using ParsePerformNetworkScan
ULONG rc = ParsePerformNetworkScan( inLen, pIn, pInstanceSize, pInstances );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Now find the RAT info too
// Find the TLV
const sNASPerformNetworkScanResponse_NetworkRAT * pTLVx11;
ULONG outLenx11;
rc = GetTLV( inLen, pIn, 0x11, &outLenx11, (const BYTE **)&pTLVx11 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx11 < sizeof( sNASPerformNetworkScanResponse_NetworkRAT ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
UINT16 ratCount = pTLVx11->mNumberOfInfoInstances;
if (ratCount > maxRATInstances)
{
ratCount = maxRATInstances;
}
const sNASPerformNetworkScanResponse_NetworkRAT::sInfo * pRatInfo;
// Verify there is room for the array in the TLV
if (outLenx11 < sizeof( sNASPerformNetworkScanResponse_NetworkRAT )
+ sizeof( sNASPerformNetworkScanResponse_NetworkRAT::sInfo )
* ratCount)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Align to the first array element
pRatInfo = (const sNASPerformNetworkScanResponse_NetworkRAT::sInfo *)
((const BYTE *)pTLVx11
+ sizeof( sNASPerformNetworkScanResponse_NetworkRAT ));
sScannedNetworkRATInfo * pRAT = (sScannedNetworkRATInfo *)pRATInstances;
for (BYTE r = 0; r < ratCount; r++)
{
pRAT->mMCC = pRatInfo->mMobileCountryCode;
pRAT->mMNC = pRatInfo->mMobileNetworkCode;
pRAT->mRAT = pRatInfo->mRadioAccessTechnology;
pRAT++;
pRatInfo++;
}
*pRATSize = (BYTE)ratCount;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
PackInitiateNetworkRegistration
DESCRIPTION:
This function initiates a network registration
PARAMETERS:
pOutLen [I/O] - Upon input the maximum number of BYTEs pOut can
contain, upon output the number of BYTEs copied
to pOut
pOut [ O ] - Output buffer
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:
ULONG - Return code
===========================================================================*/
ULONG PackInitiateNetworkRegistration(
ULONG * pOutLen,
BYTE * pOut,
ULONG regType,
WORD mcc,
WORD mnc,
ULONG rat )
{
// Validate arguments
if (pOut == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Set the action
// Check size
WORD tlvx01Sz = sizeof( sNASInitiateNetworkRegisterRequest_Action );
if (*pOutLen < sizeof( sQMIRawContentHeader ) + tlvx01Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
sQMIRawContentHeader * pHeader = (sQMIRawContentHeader*)pOut;
pHeader->mTypeID = 0x01;
pHeader->mLength = tlvx01Sz;
ULONG offset = sizeof( sQMIRawContentHeader );
sNASInitiateNetworkRegisterRequest_Action * pTLVx01;
pTLVx01 = (sNASInitiateNetworkRegisterRequest_Action*)(pOut + offset);
memset( pTLVx01, 0, tlvx01Sz );
// Set the value
pTLVx01->mRegisterAction = (eQMINASRegisterActions)regType;
offset += tlvx01Sz;
// Set the info
// Check size
WORD tlvx10Sz = sizeof( sNASInitiateNetworkRegisterRequest_ManualInfo );
if (*pOutLen < offset + sizeof( sQMIRawContentHeader ) + tlvx10Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
pHeader = (sQMIRawContentHeader*)(pOut + offset);
pHeader->mTypeID = 0x10;
pHeader->mLength = tlvx10Sz;
offset = sizeof( sQMIRawContentHeader );
sNASInitiateNetworkRegisterRequest_ManualInfo * pTLVx10;
pTLVx10 = (sNASInitiateNetworkRegisterRequest_ManualInfo*)(pOut + offset);
memset( pTLVx10, 0, tlvx10Sz );
// Set the value
pTLVx10->mMobileCountryCode = mcc;
pTLVx10->mMobileNetworkCode = mnc;
pTLVx10->mRadioAccessTechnology = (eQMINASRadioAccessTechnologies)rat;
offset += tlvx10Sz;
*pOutLen = offset;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
PackInitiateDomainAttach
DESCRIPTION:
This function initiates a domain attach (or detach)
PARAMETERS:
pOutLen [I/O] - Upon input the maximum number of BYTEs pOut can
contain, upon output the number of BYTEs copied
to pOut
pOut [ O ] - Output buffer
action [ I ] - PS attach action (attach or detach)
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG PackInitiateDomainAttach(
ULONG * pOutLen,
BYTE * pOut,
ULONG action )
{
// Validate arguments
if (pOut == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Check size
WORD tlvx10Sz = sizeof( sNASInitiateAttachRequest_Action );
if (*pOutLen < sizeof( sQMIRawContentHeader ) + tlvx10Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
sQMIRawContentHeader * pHeader = (sQMIRawContentHeader*)pOut;
pHeader->mTypeID = 0x10;
pHeader->mLength = tlvx10Sz;
ULONG offset = sizeof( sQMIRawContentHeader );
sNASInitiateAttachRequest_Action * pTLVx10;
pTLVx10 = (sNASInitiateAttachRequest_Action*)(pOut + offset);
memset( pTLVx10, 0, tlvx10Sz );
// Set the value
pTLVx10->mPSAttachAction = (eQMINASPSAttachActions)action;
offset += tlvx10Sz;
*pOutLen = offset;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetServingNetwork
DESCRIPTION:
Gets information regarding the system that currently provides service
to the device
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetServingNetwork(
ULONG inLen,
const BYTE * pIn,
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 (pIn == 0
|| 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 = 0xffffffff;
*pMCC = 0xffff;
*pMNC = 0xffff;
*pName = 0;
// Parse the serving system (mandatory)
// Find the TLV
const sNASGetServingSystemResponse_ServingSystem * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx01 < sizeof( sNASGetServingSystemResponse_ServingSystem ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Populate the variables
*pRegistrationState = pTLVx01->mRegistrationState;
*pCSDomain = pTLVx01->mCSAttachState;
*pPSDomain = pTLVx01->mPSAttachState;
*pRAN = pTLVx01->mRegisteredNetwork;
BYTE activeRadioIfaces = pTLVx01->mNumberOfRadioInterfacesInUse;
if (activeRadioIfaces > maxRadioIfaces)
{
activeRadioIfaces = maxRadioIfaces;
}
const eQMINASRadioInterfaces * pRadioInfo;
// Verify there is room for the array in the TLV
if (outLenx01 < sizeof( sNASGetServingSystemResponse_ServingSystem )
+ sizeof( eQMINASRadioInterfaces ) * activeRadioIfaces)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Align to the first array element
pRadioInfo = (const eQMINASRadioInterfaces *)
((const BYTE *)pTLVx01
+ sizeof( sNASGetServingSystemResponse_ServingSystem ));
ULONG * pOutRadioIfaces = (ULONG *)pRadioIfaces;
for (ULONG r = 0; r < activeRadioIfaces; r++)
{
*pOutRadioIfaces = *pRadioInfo;
pOutRadioIfaces++;
pRadioInfo++;
}
*pRadioIfacesSize = activeRadioIfaces;
// Find the roaming indicator (optional)
const sNASGetServingSystemResponse_RoamingIndicator * pTLVx10;
ULONG outLenx10;
rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx10 < sizeof( sNASGetServingSystemResponse_RoamingIndicator ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Get the values
*pRoaming = (eQMINASRoamingIndicators)pTLVx10->mRoamingIndicator;
}
// Find the PLMN (optional)
const sNASGetServingSystemResponse_CurrentPLMN * pTLVx12;
ULONG outLenx12;
rc = GetTLV( inLen, pIn, 0x12, &outLenx12, (const BYTE **)&pTLVx12 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx12 < sizeof( sNASGetServingSystemResponse_CurrentPLMN ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pMCC = pTLVx12->mMobileCountryCode;
*pMNC = pTLVx12->mMobileNetworkCode;
ULONG descLen = pTLVx12->mDescriptionLength;
const CHAR * pDesc;
// Verify there is room for the array in the TLV
if (outLenx12 < sizeof( sNASGetServingSystemResponse_CurrentPLMN )
+ sizeof( CHAR ) * descLen)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Space to perform the copy?
if (nameSize < descLen + 1)
{
return eGOBI_ERR_BUFFER_SZ;
}
// Align to the first array element
pDesc = (const CHAR *)((const BYTE *)pTLVx12
+ sizeof( sNASGetServingSystemResponse_CurrentPLMN ));
memcpy( pName, pDesc, descLen );
pName[descLen] = 0;
}
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetServingNetworkCapabilities
DESCRIPTION:
Gets information regarding the data capabilities of the system that
currently provides service to the device
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetServingNetworkCapabilities(
ULONG inLen,
const BYTE * pIn,
BYTE * pDataCapsSize,
BYTE * pDataCaps )
{
// Validate arguments
if (pIn == 0
|| pDataCapsSize == 0
|| *pDataCapsSize == 0
|| pDataCaps == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
BYTE maxDataCaps = *pDataCapsSize;
// Assume failure
*pDataCapsSize = 0;
// Find the TLV
const sNASGetServingSystemResponse_DataServices * pTLVx11;
ULONG outLenx11;
ULONG rc = GetTLV( inLen, pIn, 0x11, &outLenx11, (const BYTE **)&pTLVx11 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// Is the TLV large enough?
if (outLenx11 < sizeof( sNASGetServingSystemResponse_DataServices ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
BYTE activeDataCaps = pTLVx11->mNumberOfDataCapabilities;
if (activeDataCaps > maxDataCaps)
{
activeDataCaps = maxDataCaps;
}
const eQMINASDataServiceCapabilities2 * pInDataCaps;
// Verify there is room for the array in the TLV
if (outLenx11 < sizeof( sNASGetServingSystemResponse_DataServices )
+ sizeof( eQMINASDataServiceCapabilities2 ) * activeDataCaps)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Align to the first array element
pInDataCaps = (const eQMINASDataServiceCapabilities2 *)
((const BYTE *)pTLVx11
+ sizeof( sNASGetServingSystemResponse_DataServices ));
ULONG * pOutDataCaps = (ULONG *)pDataCaps;
for (ULONG d = 0; d < activeDataCaps; d++)
{
*pOutDataCaps = *pInDataCaps;
pOutDataCaps++;
pInDataCaps++;
}
*pDataCapsSize = activeDataCaps;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetHomeNetwork
DESCRIPTION:
This function retrieves information about the home network of the device
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetHomeNetwork(
ULONG inLen,
const BYTE * pIn,
WORD * pMCC,
WORD * pMNC,
BYTE nameSize,
CHAR * pName,
WORD * pSID,
WORD * pNID )
{
// Validate arguments
if (pIn == 0
|| pMCC == 0
|| pMNC == 0
|| nameSize == 0
|| pName == 0
|| pSID == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Assume failure
*pName = 0;
*pSID = 0xffff;
*pNID = 0xffff;
// Find the name (mandatory)
const sNASGetHomeNetworkResponse_HomeNetwork * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
if (outLenx01 < sizeof( sNASGetHomeNetworkResponse_HomeNetwork ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Populate the variables
*pMCC = pTLVx01->mMobileCountryCode;
*pMNC = pTLVx01->mMobileNetworkCode;
ULONG descLen = pTLVx01->mDescriptionLength;
const CHAR * pDesc;
// Verify there is room for the array in the TLV
if (outLenx01 < sizeof( sNASGetHomeNetworkResponse_HomeNetwork )
+ sizeof( CHAR ) * descLen)
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Space to perform the copy?
if (nameSize < descLen + 1)
{
return eGOBI_ERR_BUFFER_SZ;
}
// Align to the first array element
pDesc = (const CHAR *)((const BYTE *)pTLVx01
+ sizeof( sNASGetHomeNetworkResponse_HomeNetwork ));
memcpy( pName, pDesc, descLen );
pName[descLen] = 0;
// Find the SID/NID (optional)
const sNASGetHomeNetworkResponse_HomeIDs * pTLVx10;
ULONG outLenx10;
rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx10 < sizeof( sNASGetHomeNetworkResponse_HomeIDs ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pSID = pTLVx10->mSystemID;
*pNID = pTLVx10->mNetworkID;
}
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
PackSetNetworkPreference
DESCRIPTION:
This function sets the network registration preference
PARAMETERS:
pOutLen [I/O] - Upon input the maximum number of BYTEs pOut can
contain, upon output the number of BYTEs copied
to pOut
pOut [ O ] - Output buffer
technologyPref [ I ] - Technology preference bitmap
duration [ I ] - Duration of active preference
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG PackSetNetworkPreference(
ULONG * pOutLen,
BYTE * pOut,
ULONG technologyPref,
ULONG duration )
{
// Validate arguments
if (pOut == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Check size
WORD tlvx01Sz = sizeof( sNASSetTechnologyPreferenceRequest_Preference );
if (*pOutLen < sizeof( sQMIRawContentHeader ) + tlvx01Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
sQMIRawContentHeader * pHeader = (sQMIRawContentHeader*)pOut;
pHeader->mTypeID = 0x01;
pHeader->mLength = tlvx01Sz;
ULONG offset = sizeof( sQMIRawContentHeader );
sNASSetTechnologyPreferenceRequest_Preference * pTLVx01;
pTLVx01 = (sNASSetTechnologyPreferenceRequest_Preference*)(pOut + offset);
memset( pTLVx01, 0, tlvx01Sz );
// Copy technology preference WORD as-is
memcpy( &pTLVx01->mValOfTechnology, &technologyPref, 2 );
pTLVx01->mDuration = (eQMINASTechPrefDurations)duration;
offset += tlvx01Sz;
*pOutLen = offset;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetNetworkPreference
DESCRIPTION:
This function returns the network registration preference
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
pTechnologyPref [ O ] - Technology preference bitmap
pDuration [ O ] - Duration of active preference
pPersistentTechnologyPref [ O ] - Persistent technology preference bitmap
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG ParseGetNetworkPreference(
ULONG inLen,
const BYTE * pIn,
ULONG * pTechnologyPref,
ULONG * pDuration,
ULONG * pPersistentTechnologyPref )
{
// Validate arguments
if (pIn == 0
|| pTechnologyPref == 0
|| pDuration == 0
|| pPersistentTechnologyPref == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Find the preference (mandatory)
const sNASGetTechnologyPreferenceResponse_ActivePreference * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
if (outLenx01 < sizeof( sNASGetTechnologyPreferenceResponse_ActivePreference ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Copy technology preference WORD as-is
*pTechnologyPref = 0;
memcpy( pTechnologyPref, &pTLVx01->mValOfTechnology, 2 );
*pDuration = pTLVx01->mDuration;
// Until we know any better the persistent setting is the current setting
*pPersistentTechnologyPref = *pTechnologyPref;
// Find the persistant technology preference (optional)
const sNASGetTechnologyPreferenceResponse_PersistentPreference * pTLVx10;
ULONG outLenx10;
rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx10 < sizeof( sNASGetTechnologyPreferenceResponse_PersistentPreference ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
// Copy technology preference WORD as-is
*pTechnologyPref = 0;
memcpy( pPersistentTechnologyPref, &pTLVx10->mValOfTechnology, 2 );
}
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
PackSetCDMANetworkParameters
DESCRIPTION:
This function sets the desired CDMA network parameters
PARAMETERS:
pOutLen [I/O] - Upon input the maximum number of BYTEs pOut can
contain, upon output the number of BYTEs copied
to pOut
pOut [ O ] - Output buffer
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:
ULONG - Return code
===========================================================================*/
ULONG PackSetCDMANetworkParameters(
ULONG * pOutLen,
BYTE * pOut,
CHAR * pSPC,
BYTE * pForceRev0,
BYTE * pCustomSCP,
ULONG * pProtocol,
ULONG * pBroadcast,
ULONG * pApplication,
ULONG * pRoaming )
{
// Validate arguments
if (pOut == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// 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;
}
}
sQMIRawContentHeader * pHeader;
ULONG offset = 0;
// 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;
}
if (spc.find_first_not_of( "0123456789" ) != std::string::npos )
{
return eGOBI_ERR_INVALID_ARG;
}
// Check size
WORD tlvx10Sz = sizeof( sNASSetNetworkParametersRequest_SPC );
if (*pOutLen < offset + sizeof( sQMIRawContentHeader ) + tlvx10Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
pHeader = (sQMIRawContentHeader*)(pOut + offset);
pHeader->mTypeID = 0x10;
pHeader->mLength = tlvx10Sz;
offset += sizeof( sQMIRawContentHeader );
sNASSetNetworkParametersRequest_SPC * pTLVx10;
pTLVx10 = (sNASSetNetworkParametersRequest_SPC*)(pOut + offset);
memset( pTLVx10, 0, tlvx10Sz );
// Set the values
memcpy( &pTLVx10->mSPC[0], spc.c_str(), spc.size() );
offset += tlvx10Sz;
}
// Force Rev. 0?
if (pForceRev0 != 0)
{
// Check size
WORD tlvx14Sz = sizeof( sNASSetNetworkParametersRequest_CDMA1xEVDORevision );
if (*pOutLen < offset + sizeof( sQMIRawContentHeader ) + tlvx14Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
pHeader = (sQMIRawContentHeader*)(pOut + offset);
pHeader->mTypeID = 0x14;
pHeader->mLength = tlvx14Sz;
offset += sizeof( sQMIRawContentHeader );
sNASSetNetworkParametersRequest_CDMA1xEVDORevision * pTLVx14;
pTLVx14 = (sNASSetNetworkParametersRequest_CDMA1xEVDORevision*)(pOut + offset);
memset( pTLVx14, 0, tlvx14Sz );
// Set the value
pTLVx14->mForceCDMA1xEVDORev0 = (*pForceRev0 == 0 ? 0 : 1);
offset += tlvx14Sz;
}
if (scpCount == 4)
{
// Check size
WORD tlvx15Sz = sizeof( sNASSetNetworkParametersRequest_CDMA1xEVDOSCPCustom );
if (*pOutLen < offset + sizeof( sQMIRawContentHeader ) + tlvx15Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
pHeader = (sQMIRawContentHeader*)(pOut + offset);
pHeader->mTypeID = 0x15;
pHeader->mLength = tlvx15Sz;
offset += sizeof( sQMIRawContentHeader );
sNASSetNetworkParametersRequest_CDMA1xEVDOSCPCustom * pTLVx15;
pTLVx15 = (sNASSetNetworkParametersRequest_CDMA1xEVDOSCPCustom*)(pOut + offset);
memset( pTLVx15, 0, tlvx15Sz );
// Set the values
pTLVx15->mCDMA1xEVDOSCPCustomConfig = (*pCustomSCP == 0 ? 0 : 1);
// The pProtocol bitmask
pTLVx15->mSubtype2PhysicalLayer = (*pProtocol & 0x00000001 ? 1 : 0);
pTLVx15->mEnhancedCCMAC = (*pProtocol & 0x00000002 ? 1 : 0);
pTLVx15->mEnhancedACMAC = (*pProtocol & 0x00000004 ? 1 : 0);
pTLVx15->mEnhancedFTCMAC = (*pProtocol & 0x00000008 ? 1 : 0);
pTLVx15->mSubtype3RTCMAC = (*pProtocol & 0x00000010 ? 1 : 0);
pTLVx15->mSubtype1RTCMAC = (*pProtocol & 0x00000020 ? 1 : 0);
pTLVx15->mEnhancedIdle = (*pProtocol & 0x00000040 ? 1 : 0);
pTLVx15->mGenericMultimodeCapableDiscPort
= (*pProtocol & 0x00000080 ? 1 : 0);
pTLVx15->mGenericBroadcast = (*pBroadcast & 0x00000001 ? 1 : 0);
pTLVx15->mSNMultiflowPacketApplication
= (*pApplication & 0x00000001 ? 1 : 0);
pTLVx15->mSNEnhancedMultiflowPacketApplication
= (*pApplication & 0x00000002 ? 1 : 0);
offset += tlvx15Sz;
}
if (pRoaming != 0)
{
// Check size
WORD tlvx16Sz = sizeof( sNASSetNetworkParametersRequest_Roaming );
if (*pOutLen < offset + sizeof( sQMIRawContentHeader ) + tlvx16Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
pHeader = (sQMIRawContentHeader*)(pOut + offset);
pHeader->mTypeID = 0x16;
pHeader->mLength = tlvx16Sz;
offset += sizeof( sQMIRawContentHeader );
sNASSetNetworkParametersRequest_Roaming * pTLVx16;
pTLVx16 = (sNASSetNetworkParametersRequest_Roaming*)(pOut + offset);
memset( pTLVx16, 0, tlvx16Sz );
// Set the values
pTLVx16->mRoamPreference = (eQMINASRoamingPreferences)*pRoaming;
offset += tlvx16Sz;
}
// At least one of the optional parameters must have been set
if (offset == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
*pOutLen = offset;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetCDMANetworkParameters
DESCRIPTION:
This function gets the current CDMA network parameters
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetCDMANetworkParameters(
ULONG inLen,
const BYTE * pIn,
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 (pIn == 0
|| 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 = 0xff;
*pSCM = 0xff;
*pRegHomeSID = 0xff;
*pRegForeignSID = 0xff;
*pRegForeignNID = 0xff;
*pForceRev0 = 0xff;
*pCustomSCP = 0xff;
*pProtocol = 0xffffffff;
*pBroadcast = 0xffffffff;
*pApplication = 0xffffffff;
*pRoaming = 0xff;
// Find the SCI
const sNASGetNetworkParametersResponse_SCI * pTLVx11;
ULONG outLenx11;
ULONG rc = GetTLV( inLen, pIn, 0x11, &outLenx11, (const BYTE **)&pTLVx11 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx11 < sizeof( sNASGetNetworkParametersResponse_SCI ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pSCI = pTLVx11->mSlotCycleIndex;
}
// Find the SCM
const sNASGetNetworkParametersResponse_SCM * pTLVx12;
ULONG outLenx12;
rc = GetTLV( inLen, pIn, 0x12, &outLenx12, (const BYTE **)&pTLVx12 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx12 < sizeof( sNASGetNetworkParametersResponse_SCM ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pSCM = pTLVx12->mStationClassMark;
}
// Find the Registration
const sNASGetNetworkParametersResponse_Registration * pTLVx13;
ULONG outLenx13;
rc = GetTLV( inLen, pIn, 0x13, &outLenx13, (const BYTE **)&pTLVx13 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx13 < sizeof( sNASGetNetworkParametersResponse_Registration ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pRegHomeSID = pTLVx13->mRegisterOnHomeSystem;
*pRegForeignSID = pTLVx13->mRegisterOnForeignSystem;
*pRegForeignNID = pTLVx13->mRegisterOnForeignNetwork;
}
// Rev. 0?
const sNASGetNetworkParametersResponse_CDMA1xEVDORevision * pTLVx14;
ULONG outLenx14;
rc = GetTLV( inLen, pIn, 0x14, &outLenx14, (const BYTE **)&pTLVx14 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx14 < sizeof( sNASGetNetworkParametersResponse_CDMA1xEVDORevision ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pRegHomeSID = pTLVx14->mForceCDMA1xEVDORev0;
}
// We're lazy, so we'll just typecast all the bitmask members from
// sNASGetNetworkParametersResponse_CDMA1xEVDOSCPCustom into their
// respective container parameters
const sEVDOCustomSCPConfig * pTLVx15;
ULONG outLenx15;
rc = GetTLV( inLen, pIn, 0x15, &outLenx15, (const BYTE **)&pTLVx15 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx15 < sizeof( sEVDOCustomSCPConfig ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pCustomSCP = pTLVx15->mbActive;
*pProtocol = pTLVx15->mProtocolMask;
*pBroadcast = pTLVx15->mBroadcastMask;
*pApplication = pTLVx15->mApplicationMask;
}
// Roaming?
const sNASGetNetworkParametersResponse_Roaming * pTLVx16;
ULONG outLenx16;
rc = GetTLV( inLen, pIn, 0x16, &outLenx16, (const BYTE **)&pTLVx16 );
if (rc == eGOBI_ERR_NONE)
{
if (outLenx16 < sizeof( sNASGetNetworkParametersResponse_Roaming ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pRoaming = (eQMINASRoamingPreferences)pTLVx16->mRoamPreference;
}
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetACCOLC
DESCRIPTION:
This function returns the Access Overload Class (ACCOLC) of the device
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
pACCOLC [ O ] - The ACCOLC
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG ParseGetACCOLC(
ULONG inLen,
const BYTE * pIn,
BYTE * pACCOLC )
{
// Validate arguments
if (pIn == 0 || pACCOLC == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Find the ACCOLC (mandatory)
const sNASGetACCOLCResponse_ACCOLC * pTLVx01;
ULONG outLenx01;
ULONG rc = GetTLV( inLen, pIn, 0x01, &outLenx01, (const BYTE **)&pTLVx01 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
if (outLenx01 < sizeof( sNASGetACCOLCResponse_ACCOLC ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pACCOLC = pTLVx01->mACCOLC;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
PackSetACCOLC
DESCRIPTION:
This function sets the Access Overload Class (ACCOLC) of the device
PARAMETERS:
pOutLen [I/O] - Upon input the maximum number of BYTEs pOut can
contain, upon output the number of BYTEs copied
to pOut
pOut [ O ] - Output buffer
pSPC [ I ] - NULL terminated string representing the six digit
service programming code
accolc [ I ] - The ACCOLC
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG PackSetACCOLC(
ULONG * pOutLen,
BYTE * pOut,
CHAR * pSPC,
BYTE accolc )
{
// Validate arguments
if (pOut == 0 || pSPC == 0 || pSPC[0] == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
std::string spc( pSPC );
if (spc.size() > 6)
{
return eGOBI_ERR_INVALID_ARG;
}
if (spc.find_first_not_of( "0123456789" ) != std::string::npos )
{
return eGOBI_ERR_INVALID_ARG;
}
// Check size
WORD tlvx01Sz = sizeof( sNASSetACCOLCRequest_ACCOLC );
if (*pOutLen < sizeof( sQMIRawContentHeader ) + tlvx01Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
sQMIRawContentHeader * pHeader = (sQMIRawContentHeader*)pOut;
pHeader->mTypeID = 0x01;
pHeader->mLength = tlvx01Sz;
ULONG offset = sizeof( sQMIRawContentHeader );
sNASSetACCOLCRequest_ACCOLC * pTLVx01;
pTLVx01 = (sNASSetACCOLCRequest_ACCOLC*)(pOut + offset);
memset( pTLVx01, 0, tlvx01Sz );
// Set the values
memcpy( &pTLVx01->mSPC[0], spc.c_str(), spc.size() );
pTLVx01->mACCOLC = accolc;
offset += tlvx01Sz;
*pOutLen = offset;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetPLMNMode
DESCRIPTION:
This function returns the PLMN mode from the CSP
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
pMode [ O ] - PLMN mode
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG ParseGetPLMNMode(
ULONG inLen,
const BYTE * pIn,
ULONG * pMode )
{
// Validate arguments
if (pIn == 0 || pMode == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Find the mode (mandatory)
const sNASGetCSPPLMNModeResponse_Mode * pTLVx10;
ULONG outLenx10;
ULONG rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
if (outLenx10 < sizeof( sNASGetCSPPLMNModeResponse_Mode ))
{
return eGOBI_ERR_MALFORMED_RSP;
}
*pMode = pTLVx10->mRestrictManualPLMNSelection;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
PackGetPLMNName
DESCRIPTION:
This function returns PLMN name information for the given MCC/MNC
PARAMETERS:
pOutLen [I/O] - Upon input the maximum number of BYTEs pOut can
contain, upon output the number of BYTEs copied
to pOut
pOut [ O ] - Output buffer
mcc [ I ] - Mobile country code
mnc [ I ] - Mobile network code
RETURN VALUE:
ULONG - Return code
===========================================================================*/
ULONG PackGetPLMNName(
ULONG * pOutLen,
BYTE * pOut,
USHORT mcc,
USHORT mnc )
{
// Validate arguments
if (pOut == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
// Check size
WORD tlvx01Sz = sizeof( sNASGetPLMNNameRequest_PLMN );
if (*pOutLen < sizeof( sQMIRawContentHeader ) + tlvx01Sz)
{
return eGOBI_ERR_BUFFER_SZ;
}
sQMIRawContentHeader * pHeader = (sQMIRawContentHeader*)pOut;
pHeader->mTypeID = 0x01;
pHeader->mLength = tlvx01Sz;
ULONG offset = sizeof( sQMIRawContentHeader );
sNASGetPLMNNameRequest_PLMN * pTLVx01;
pTLVx01 = (sNASGetPLMNNameRequest_PLMN*)(pOut + offset);
memset( pTLVx01, 0, tlvx01Sz );
// Set the values
pTLVx01->mMobileCountryCode = mcc;
pTLVx01->mMobileNetworkCode = mnc;
offset += tlvx01Sz;
*pOutLen = offset;
return eGOBI_ERR_NONE;
}
/*===========================================================================
METHOD:
ParseGetPLMNName
DESCRIPTION:
This function returns PLMN name information for the given MCC/MNC
PARAMETERS:
inLen [ I ] - Length of input buffer
pIn [ I ] - Input buffer
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:
ULONG - Return code
===========================================================================*/
ULONG ParseGetPLMNName(
ULONG inLen,
const BYTE * pIn,
ULONG * pNamesSize,
BYTE * pNames )
{
// Validate arguments
if (pIn == 0 || *pNamesSize == 0 || pNames == 0)
{
return eGOBI_ERR_INVALID_ARG;
}
const BYTE * pTLVx10;
ULONG outLenx10;
ULONG rc = GetTLV( inLen, pIn, 0x10, &outLenx10, (const BYTE **)&pTLVx10 );
if (rc != eGOBI_ERR_NONE)
{
return rc;
}
// The output format just happens to be the same as
// sNASGetPLMNNameResponse_Name. Copy the full TLV to pNames
if (outLenx10 > *pNamesSize)
{
return eGOBI_ERR_BUFFER_SZ;
}
memcpy( pNames, pTLVx10, outLenx10 );
*pNamesSize = outLenx10;
return eGOBI_ERR_NONE;
}