-
Notifications
You must be signed in to change notification settings - Fork 129
Mobile nas messages
All the NAS-related messages are available in the pycrate_mobile directory.
The following modules provide structures for dealing with 2G and 3G NAS messages:
- TS24008_MM: contains all structures for Mobility Management messages
- TS24008_CC: for Call Control
- TS24008_GMM: for GPRS Mobility Management
- TS24008_SM: for GPRS Session Management
- TS44018_RR: for GSM Radio Resources management
All those structures are corresponding mostly to the descriptions from sections 9 of the 3GPP TS 24.008 and TS 44.018 specifications. They are themselves using IEs (Information Elements) defined in section 10 of both specifications, and available in the modules TS24008_IE and TS44018_IE. Moreover, some GSM and GPRS IEs are using CSN.1, which are defined in the pycrate_csn1dir directory.
For SMS and Supplementary Services, other modules are available:
- TS24011_PPSMS: for Point-to-Point Short Message Service, which itself calls
- TS23040_SMS: for SMS itself
- TS24080_SS: for Supplementary Service, which wraps some ASN.1-defined objects from the pycrate_asn1dir/SS module.
For LTE NAS, two main modules are available:
- TS24301_EMM: for EPS Mobility Management
- TS24301_ESM: for EPS Session Management
Those structures are corresponding to the descriptions from section 8 of the 3GPP
TS 24.301 specification. IEs defined in section 9 are available in the module
TS24301_IE.
Moreover, in case the CryptoMobile
library is installed and can be imported, the EMMSecProtNASMessage
and EMMServiceRequest
classes
have methods dedicated to the LTE NAS cryptographic operations.
For 5G NAS, three main modules are available:
- TS24501_FGMM: for 5G Mobility Management
- TS24501_FGSM: for 5G Session Management
- TS24501_UEPOL: for 5G UE Policy
Those structures are corresponding to the descriptions from section 8 and annex D
of the 3GPP TS 24.501 specification. IEs defined in section 9 are available in the module
TS24501_IE.
Moreover, in case the CryptoMobile
library is installed and can be imported, the FGMMSecProtNASMessage
class has methods
dedicated to the 5G NAS cryptographic operations.
All classes representing NAS messages and information elements are deriving from few base classes defined in the TS24007 module, which implements some specific aspects of cellular layer 3 message structures as defined in the TS 24.007 3GPP specification.
Finally, three top-level modules are enabling the import of most of those NAS messages' structures and providing custom functions for decoding any cellular NAS messages:
- NASLTE: for LTE-only EMM and ESM NAS messages,
- NAS5G: for 5G-only 5GMM, 5GSM and 5G UE Policy NAS messages,
- NAS: for all 2G-3G, LTE and 5G NAS messages.
In order to decode NAS messages, the simplest way is to use one of the two functions used in the NAS module:
- parse_NAS_MO(buf) -> (element, err), for parsing Mobile Originating message (i.e. uplink)
- parse_NAS_MT(buf) -> (element, err), for parsing Mobile Terminating message (i.e. downlink)
In case there is an error during the decoding of the buffer, this will be returned in
the err
code, with a code corresponding to standard 3GPP NAS error code (e.g. which can be
used in a Status NAS message in return).
The element
contains an Element's instance (or None, if the whole decoding failed), with
the whole message header and information elements.
Let's see some examples from the test directory:
>>> from pycrate_mobile.NAS import *
>>> Msg, err = parse_NAS_MO(unhexlify('05080200f11040005705f44c6a94c033035758a6'))
>>> err
0
>>> show(Msg)
### MMLocationUpdatingRequest ###
<SkipInd : 0>
<ProtDisc : 5 (MM)>
<Seqn : 0>
<Type : 8 (Registration - LOCATION UPDATING REQUEST)>
<CKSN : 0>
### LocUpdateType ###
<FollowOnReq : 0>
<spare : 0>
<Type : 2 (IMSI attach)>
### LAI ###
<PLMN : 00101>
<LAC : 0x4000>
### MSCm1 ###
<spare : 0>
<RevLevel : 2 (MS supporting R99 or later)>
<EarlyCmCap : 1>
<NoA51 : 0>
<RFClass : 7>
### ID ###
<L : 5>
### ID ###
<Digit1 : 0xf>
<Odd : 0>
<Type : 4 (TMSI)>
<TMSI : 0x4c6a94c0>
### MSCm2 ###
<T : 51>
<L : 3>
### MSCm2 ###
<spare : 0>
<RevLevel : 2 (MS supporting R99 or later)>
<EarlyCmCap : 1>
<NoA51 : 0>
<RFClass : 7>
<spare : 0>
<PSCap : 1>
<SSScreeningCap : 1 (capability of handling of ellipsis notation and phase 2 error handling)>
<MTSMSCap : 1>
<VBSNotifCap : 0>
<VGCSNotifCap : 0>
<FCFreqCap : 0>
<MSCm3Cap : 1>
<spare : 0>
<LCSVACap : 1>
<UCS2 : 0>
<SoLSACap : 0>
<CMServPrompt : 1>
<A53 : 1>
<A52 : 0>
>>> Msg['LAI'].get_val()
['\x00\xf1\x10', 16384]
>>> Msg['LAI'].decode() # some IEs have a specific .decode() method, like the LAI / PLMN, or the ID here
('00101', 16384)
>>> Msg['ID'][1]
<ID [TMSI] : 0x4c6a94c0>
>>> Msg['ID'][1].get_val()
[15, 0, 4, 1282053312]
>>> Msg['ID'][1].decode()
(4, 1282053312)
>>>
>>> Msg, err = parse_NAS_MO(unhexlify('034504066004020005815e068160000000001502010040080402600400021f00'))
>>> err
0
>>> show(Msg)
### CCSetupMO ###
<TIFlag : 0 (initiator)>
<TIO : 0>
<ProtDisc : 3 (CC)>
<Seqn : 1>
<Type : 5 (Call establishment - SETUP)>
### BearerCap1 ###
<T : 4>
<L : 6>
### BearerCap ###
<Ext : 0>
<RadioChanReq : 3 (dual rate support MS/full rate preferred)>
<CodingStd : 0 (GSM standardized coding)>
<TransferMode : 0 (circuit)>
<InfoTransferCap : 0 (speech)>
### Ext3a ###
<Ext : 0>
<Coding : 0 (octet used for extension of information transfer capability)>
<CTM : 0 (CTM text telephony is not supported)>
<spare : 0>
<SpeechVersionInd : 4 (GSM FR v3 (FR AMR))>
### Ext3b ###
### _BearerCapExt3bRec ###
<Ext : 0>
<Coding : 0 (octet used for extension of information transfer capability)>
<spare : 0>
<SpeechVersionInd : 2 (GSM FR v2 (GSM EFR))>
### _BearerCapExt3bRec ###
<Ext : 0>
<Coding : 0 (octet used for extension of information transfer capability)>
<spare : 0>
<SpeechVersionInd : 0 (GSM FR v1 (GSM FR))>
### _BearerCapExt3bRec ###
<Ext : 0>
<Coding : 0 (octet used for extension of information transfer capability)>
<spare : 0>
<SpeechVersionInd : 5 (GSM HR v3 (HR AMR))>
### _BearerCapExt3bRec ###
<Ext : 1>
<Coding : 0 (octet used for extension of information transfer capability)>
<spare : 0>
<SpeechVersionInd : 1 (GSM HR v1 (GSM HR))>
### CalledPartyBCDNumber ###
<T : 94>
<L : 6>
### CalledPartyBCDNumber ###
<Ext : 1>
<Type : 0 (unknown)>
<NumberingPlan : 1 (ISDN / telephony numbering plan (E.164 / E.163))>
<Num : 0600000000>
### CCCap ###
<T : 21>
<L : 2>
### CCCap ###
<MaxNumSupportedBearers : 0>
<MultimediaCAT : 0>
<ENICM : 0>
<PCP : 0>
<DTMF : 1>
<spare : 0>
<MaxNumSpeechBearers : 0>
### SupportedCodecs ###
<T : 64>
<L : 8>
### SupportedCodecs ###
### CodecSysID ###
<SysID : 4 (UMTS)>
<BMLen : 2>
### CodecBM ###
<TDMA_EFR : 0>
<UMTS_AMR2 : 1>
<UMTS_AMR : 1>
<HR_AMR : 0>
<FR_AMR : 0>
<GSM_EFR : 0>
<GSM_HR : 0>
<GSM_FR : 0>
<reserved : 0>
<reserved : 0>
<OHR_AMR-WB : 0>
<OFR_AMR-WB : 0>
<OHR_AMR : 0>
<UMTS_AMR-WB : 1>
<FR_AMR-WB : 0>
<PDC_EFR : 0>
<spare : ''>
### CodecSysID ###
<SysID : 0 (GSM)>
<BMLen : 2>
### CodecBM ###
<TDMA_EFR : 0>
<UMTS_AMR2 : 0>
<UMTS_AMR : 0>
<HR_AMR : 1>
<FR_AMR : 1>
<GSM_EFR : 1>
<GSM_HR : 1>
<GSM_FR : 1>
<reserved : 0>
<reserved : 0>
<OHR_AMR-WB : 0>
<OFR_AMR-WB : 0>
<OHR_AMR : 0>
<UMTS_AMR-WB : 0>
<FR_AMR-WB : 0>
<PDC_EFR : 0>
<spare : ''>
>>> show(Msg['CalledPartyBCDNumber'][2])
### CalledPartyBCDNumber ###
<Ext : 1>
<Type : 0 (unknown)>
<NumberingPlan : 1 (ISDN / telephony numbering plan (E.164 / E.163))>
<Num : 0600000000>
>>> Msg['CalledPartyBCDNumber'][2].get_val()
[1, 0, 1, '`\x00\x00\x00\x00']
>>> Msg['CalledPartyBCDNumber'][2]['Num'].decode()
'0600000000'
>>> Msg, err = parse_NAS_MO(unhexlify('0748610bf602f8108003c8c2e65e9a5804e060c0405202f810c4c25c0a00570220003103e5e0341302f810040511035758a65d0100c1'))
>>> err
0
>>> show(Msg)
### EMMTrackingAreaUpdateRequest ###
<SecHdr : 0 (No security)>
<ProtDisc : 7 (EMM)>
<Type : 72 (Tracking area update request)>
### NAS_KSI ###
<TSC : 0 ( native security context)>
<Value : 6>
### EPSUpdateType ###
<Active : 0 (No bearer establishment requested)>
<Value : 1 (combined TA/LA updating)>
### OldGUTI ###
<L : 11>
### EPSID ###
<Digit1 : 0xf>
<Odd : 0>
<Type : 6 (GUTI)>
<PLMN : 20801 (France.Orange)>
<MMEGroupID : 0x8003>
<MMECode : 0xc8>
<MTMSI : 0xc2e65e9a>
### UENetCap ###
<T : 88>
<L : 4>
### UENetCap ###
<EEA0 : 1>
<EEA1_128 : 1>
<EEA2_128 : 1>
<EEA3_128 : 0>
<EEA4 : 0>
<EEA5 : 0>
<EEA6 : 0>
<EEA7 : 0>
<EIA0 : 0>
<EIA1_128 : 1>
<EIA2_128 : 1>
<EIA3_128 : 0>
<EIA4 : 0>
<EIA5 : 0>
<EIA6 : 0>
<EIA7 : 0>
<UEA0 : 1>
<UEA1 : 1>
<UEA2 : 0>
<UEA3 : 0>
<UEA4 : 0>
<UEA5 : 0>
<UEA6 : 0>
<UEA7 : 0>
<UCS2 : 0>
<UIA1 : 1>
<UIA2 : 0>
<UIA3 : 0>
<UIA4 : 0>
<UIA5 : 0>
<UIA6 : 0>
<UIA7 : 0>
### OldTAI ###
<T : 82>
### TAI ###
<PLMN : 20801 (France.Orange)>
<TAC : 0xc4c2>
### DRXParam ###
<T : 92>
### DRXParam ###
<SPLIT_PG_CYCLE_CODE : 10>
<DRXCycleLen : 0 (DRX not specified by the MS)>
<SPLITonCCCH : 0>
<NonDRXTimer : 0 (no non-DRX mode after transfer state)>
### EPSBearerCtxtStat ###
<T : 87>
<L : 2>
### EPSBearerCtxtStat ###
<EBI_7 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_6 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_5 : 1 (BEARER CONTEXT-ACTIVE)>
<EBI_4 : 0>
<EBI_3 : 0>
<EBI_2 : 0>
<EBI_1 : 0>
<EBI_0 : 0>
<EBI_15 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_14 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_13 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_12 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_11 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_10 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_9 : 0 (BEARER CONTEXT-INACTIVE)>
<EBI_8 : 0 (BEARER CONTEXT-INACTIVE)>
### MSNetCap ###
<T : 49>
<L : 3>
<MS_network_capability_value_part: [
<<GEA1_bits: 1>>
<SM_capabilities_via_dedicated_channels: 1>
<SM_capabilities_via_GPRS_channels: 1>
<UCS2_support: 0>
<SS_Screening_Indicator: 1>
<SoLSA_Capability: 0>
<Revision_level_indicator: 1>
<PFC_feature_mode: 1>
<<Extended_GEA_bits: [
<GEA_2: 1>
<GEA_3: 1>
<GEA_4: 0>
<GEA_5: 0>
<GEA_6: 0>
<GEA_7: 0>]>>
<LCS_VA_capability: 0>
<PS_inter_RAT_HO_from_GERAN_to_UTRAN_Iu_mode_capability: 0>
<PS_inter_RAT_HO_from_GERAN_to_E_UTRAN_S1_mode_capability: 0>
<EMM_Combined_procedures_Capability: 1>
<ISR_support: 1>
<SRVCC_to_GERAN_UTRAN_capability: 0>
<EPC_capability: 1>
<NF_capability: 0>
<GERAN_network_sharing_capability: 0>]>
### OldLAI ###
<T : 19>
### LAI ###
<PLMN : 20801 (France.Orange)>
<LAC : 0x0405>
### MSCm2 ###
<T : 17>
<L : 3>
### MSCm2 ###
<spare : 0>
<RevLevel : 2 (MS supporting R99 or later)>
<EarlyCmCap : 1>
<NoA51 : 0>
<RFClass : 7>
<spare : 0>
<PSCap : 1>
<SSScreeningCap : 1 (capability of handling of ellipsis notation and phase 2 error handling)>
<MTSMSCap : 1>
<VBSNotifCap : 0>
<VGCSNotifCap : 0>
<FCFreqCap : 0>
<MSCm3Cap : 1>
<spare : 0>
<LCSVACap : 1>
<UCS2 : 0>
<SoLSACap : 0>
<CMServPrompt : 1>
<A53 : 1>
<A52 : 0>
### VoiceDomPref ###
<T : 93>
<L : 1>
### VoiceDomPref ###
<spare : 0>
<UEUsage : 0 (Voice centric)>
<VoiceDomPref : 0 (CS Voice only)>
### MSNetFeatSupp ###
<T : 12>
### MSNetFeatSupp ###
<spare : 0>
<ExtPeriodTimers : 1>
>>> Msg['OldGUTI'][1].decode()
(6, '20801', 32771, 200, 3269877402L)
This is basically it. For CSN.1-based information elements, the selection of inner part
is not as friendly as with normal objects: the list of objects is available under
the attribute _list
, and the corresponding value under _val
:
>>> Msg['MSNetCap'][2]._list[3]
<UCS2_support(CSN1Bit)>
>>> Msg['MSNetCap'][2]._list[3]._name
'UCS2_support'
>>> Msg['MSNetCap'][2]._val[3]
0
NAS messages are almost always structured in the same way, with a header indicating the protocol and type of message, a list of mandatory information elements (those with variable length are prefixed with a length field), and a list of optional information elements. Those last ones are all prefixed with a tag field, and eventually a length field if of variable length.
When instantiating a NAS message class, if no values are passed in the initialization, the message builds only with mandatory IEs, set with default values:
>>> Msg = MMLocationUpdatingRequest()
>>> show(Msg)
### MMLocationUpdatingRequest ###
<SkipInd : 0>
<ProtDisc : 5 (MM)>
<Seqn : 0>
<Type : 8 (Registration - LOCATION UPDATING REQUEST)>
<CKSN : 0>
### LocUpdateType ###
<FollowOnReq : 0>
<spare : 0>
<Type : 0 (Normal location updating)>
### LAI ###
<PLMN : 000000>
<LAC : 0x0000>
### MSCm1 ###
<spare : 0>
<RevLevel : 2 (MS supporting R99 or later)>
<EarlyCmCap : 0>
<NoA51 : 0>
<RFClass : 0 (class 1)>
### ID ###
<L : 5>
<V : 0xf400000000>
>>> Msg.to_bytes()
'\x05\x08\x00\x00\x00\x00\x00\x00@\x05\xf4\x00\x00\x00\x00'
From here, it is possible to set IEs one by one, and also the optional ones. A list
with all optional IEs is available under the attribute _opts
. Optional IEs are by
default set to transparent, hence it is require to set them non transparent, to
make them appear in the message encoding.
Moreover, many IEs with a Length-Value or Tag-Length-Value structure have by default
a value which is a bytes buffer, and a complete IE structure available under the
_IE_stat
attribute.
This is used to encode and decode the exact structure and replace the default bytes
buffer. To set the IE exact structure, the method set_IE()
can be used: it will
initialize the IE with provided arguments, and replace the default bytes buffer.
>>> Msg._opts
[(8, 51, <MSCm2 [transparent] : <T : 51><L : 3><V : 0x400000>>), (4, 12, <AddUpdateParams [transparent] : <T : 12><V : 0>>), (4, 13, <DeviceProp [transparent] : <T : 13><V : 0>>), (4, 14, <MSNetFeatSupp [transparent] : <T : 14><V : 0>>)]
>>> Msg['CKSN'].set_val(2)
>>> Msg['LocUpdateType']['Type'].set_val(1)
>>> Msg['LAI'].set_val((u'20810', 0x1234))
>>> Msg['ID'].set_IE(val={'type': 1, 'ident': '208100123456789'}) # Length-Value
>>> Msg['ID']._IE_stat
<ID : >
>>> Msg['ID']._IE
<ID [IMSI] : 208100123456789>
>>> Msg['AddUpdateParams']
<AddUpdateParams [transparent] : <T : 12><V : 0>>
>>> Msg['AddUpdateParams'].set_trans(False)
>>> Msg['AddUpdateParams'].set_IE(val={'CSMO':1, 'CSMT':1})
>>> show(Msg)
### MMLocationUpdatingRequest ###
<SkipInd : 0>
<ProtDisc : 5 (MM)>
<Seqn : 0>
<Type : 8 (Registration - LOCATION UPDATING REQUEST)>
<CKSN : 2>
### LocUpdateType ###
<FollowOnReq : 0>
<spare : 0>
<Type : 1 (Periodic updating)>
### LAI ###
<PLMN : 20810 (France.S.F.R.)>
<LAC : 0x1234>
### MSCm1 ###
<spare : 0>
<RevLevel : 2 (MS supporting R99 or later)>
<EarlyCmCap : 0>
<NoA51 : 0>
<RFClass : 0 (class 1)>
### ID ###
<L : 8>
### ID ###
<Digit1 : 0x2>
<Odd : 1>
<Type : 1 (IMSI)>
<Digits : 0x80011032547698>
### AddUpdateParams ###
<T : 12>
### AddUpdateParams ###
<spare : 0>
<CSMO : 1 (CS fallback MO call)>
<CSMT : 1 (CS fallback MT call)>
>>> Msg.to_bytes()
'\x05\x08!\x02\xf8\x01\x124@\x08)\x80\x01\x102Tv\x98\xc3'
It is also possible to prepare a dict containing all IEs values that are required to appear in the message, and to initialize the message class with it. In this way, all optional IEs that are set, will appear directly in the message encoding:
>>> IEs = {}
>>> IEs['CKSN']= 4
>>> IEs['LocUpdateType'] = {'Type': 1}
>>> IEs['LAI'] = (u'20820', 0x4321)
>>> IEs['ID'] = {'type': 1, 'ident': u'208209876543210'}
>>> IEs['AddUpdateParams'] = {'CSMO': 1, 'CSMT': 1}
>>> IEs
{'LocUpdateType': {'Type': 1}, 'ID': {'ident': u'208209876543210', 'type': 1}, 'AddUpdateParams': {'CSMT': 1, 'CSMO': 1}, 'CKSN': 4, 'LAI': (u'20820', 17185)}
>>> Msg = MMLocationUpdatingRequest(val=IEs)
>>> show(Msg)
### MMLocationUpdatingRequest ###
<SkipInd : 0>
<ProtDisc : 5 (MM)>
<Seqn : 0>
<Type : 8 (Registration - LOCATION UPDATING REQUEST)>
<CKSN : 4>
### LocUpdateType ###
<FollowOnReq : 0>
<spare : 0>
<Type : 1 (Periodic updating)>
### LAI ###
<PLMN : 20820 (France.Bouygues Telecom)>
<LAC : 0x4321>
### MSCm1 ###
<spare : 0>
<RevLevel : 2 (MS supporting R99 or later)>
<EarlyCmCap : 0>
<NoA51 : 0>
<RFClass : 0 (class 1)>
### ID ###
<L : 8>
### ID ###
<Digit1 : 0x2>
<Odd : 1>
<Type : 1 (IMSI)>
<Digits : 0x80028967452301>
### AddUpdateParams ###
<T : 12>
### AddUpdateParams ###
<spare : 0>
<CSMO : 1 (CS fallback MO call)>
<CSMT : 1 (CS fallback MT call)>
>>> Msg.to_bytes()
'\x05\x08A\x02\xf8\x02C!@\x08)\x80\x02\x89gE#\x01\xc3'