mobile: harmonize some _from_char() handling and continue with more 5G IEs

This commit is contained in:
mich 2019-11-26 18:08:23 +01:00
parent 699688373c
commit 33faee13b4
4 changed files with 792 additions and 148 deletions

View File

@ -221,6 +221,7 @@ class EMMAttachAccept(Layer3):
Type1TV('UERadioCapIDDelInd', val={'T':0xB, 'V':0}, IE=UERadioCapIDDelInd())
)
#------------------------------------------------------------------------------#
# Attach complete
# TS 24.301, section 8.2.2

View File

@ -430,43 +430,44 @@ class EPSID(Envelope):
.format(self._name, ident)))
def _from_char(self, char):
if not self.get_trans():
try:
spare = char.get_uint(5)
type = char.get_uint(3)
except CharpyErr as err:
raise(CharpyErr('{0} [_from_char]: {1}'.format(self._name, err)))
except Exception as err:
raise(EltErr('{0} [_from_char]: {1}'.format(self._name, err)))
#
if type in (IDTYPE_IMSI, IDTYPE_IMEISV):
if not hasattr(self, '_IDDigit'):
self._IDDigit = IDDigit()
self._content = self._IDDigit._content
self._by_id = self._IDDigit._by_id
self._by_name = self._IDDigit._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[2]._val = type
self[3]._from_char(char)
#
elif type == IDTYPE_GUTI:
if not hasattr(self, '_IDGUTI'):
self._IDGUTI = IDGUTI()
self._content = self._IDGUTI._content
self._by_id = self._IDGUTI._by_id
self._by_name = self._IDGUTI._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[2]._val = type
self[3]._from_char(char)
self[4]._from_char(char)
self[5]._from_char(char)
self[6]._from_char(char)
#
else:
raise(PycrateErr('{0}: invalid identity to decode, {1}'\
.format(self._name, type)))
if self.get_trans():
return
try:
spare = char.get_uint(5)
type = char.get_uint(3)
except CharpyErr as err:
raise(CharpyErr('{0} [_from_char]: {1}'.format(self._name, err)))
except Exception as err:
raise(EltErr('{0} [_from_char]: {1}'.format(self._name, err)))
#
if type in (IDTYPE_IMSI, IDTYPE_IMEISV):
if not hasattr(self, '_IDDigit'):
self._IDDigit = IDDigit()
self._content = self._IDDigit._content
self._by_id = self._IDDigit._by_id
self._by_name = self._IDDigit._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[2]._val = type
self[3]._from_char(char)
#
elif type == IDTYPE_GUTI:
if not hasattr(self, '_IDGUTI'):
self._IDGUTI = IDGUTI()
self._content = self._IDGUTI._content
self._by_id = self._IDGUTI._by_id
self._by_name = self._IDGUTI._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[2]._val = type
self[3]._from_char(char)
self[4]._from_char(char)
self[5]._from_char(char)
self[6]._from_char(char)
#
else:
raise(PycrateErr('{0}: invalid identity to decode, {1}'\
.format(self._name, type)))
def repr(self):
if not self._content:
@ -516,6 +517,8 @@ class EPSNetFeat(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
if char.len_bit() < 16:
self._set_o2_trans(True)
Envelope._from_char(self, char)
@ -830,6 +833,8 @@ class TAIList(Envelope):
return ret
def _from_char(self, char):
if self.get_trans():
return
self.clear()
if self._ptail2 is not None:
del self._ptail2
@ -848,6 +853,87 @@ class TAIList(Envelope):
self.append(ptl)
'''this will need to be introduced, to be similar as in TS24501_IE
class _PTAIList0(Envelope):
"""List of non-consecutive TACs belonging to one PLMN
"""
_GEN = (
Uint('Num', bl=5),
PLMN(),
Array('TACs', GEN=Uint16('TAC'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: max(0, self[2].get_num()-1))
self[2].set_numauto(lambda: self[0].get_val()+1)
def get_tai(self):
plmn = self['PLMN'].decode()
return set([(plmn, tac) for tac in self['TACs'].get_val()])
class _PTAIList1(Envelope):
"""List of consecutive TACs belonging to one PLMN
"""
_GEN = (
Uint('Num', bl=5),
PLMN(),
Uint16('TAC1'),
)
def get_tai(self):
plmn, tac1 = self['PLMN'].decode(), self['TAC1'].get_val()
return set([(plmn, tac1 + i) for i in range(self['Num'].get_val() + 1)])
class _PTAIList2(Envelope):
"""List of TAI belonging to different PLMNs
"""
_GEN = (
Uint('Num', bl=5),
Sequence('TAIs', GEN=TAI())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: max(0, self[1].get_num()-1))
self[1].set_numauto(lambda: self[0].get_val()+1)
def get_tai(self):
return set([tai.decode() for tai in self['TAIs']])
class PTAIList(Envelope):
_GEN = (
Uint('spare', bl=1),
Uint('Type', bl=2, dic=_PTAIListType_dict),
Alt('PTAI', GEN={
0: _PTAIList0('PTAIList0'),
1: _PTAIList1('PTAIList1'),
2: _PTAIList2('PTAIList2')
},
DEFAULT=_PTAIList1('PTAIList1'),
sel=lambda self: self.get_env()['Type'].get_val())
)
def get_tai(self):
return self['PTAI'].get_tai()
class TAIList(Sequence):
_GEN = PTAIList()
def get_tai(self):
tai = set()
for tl in self:
tai.update(tl.get_tai())
return tai
'''
#------------------------------------------------------------------------------#
# UE network capability
# TS 24.301, 9.9.3.34
@ -918,6 +1004,8 @@ class UENetCap(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
l = char.len_bit()
if l <= 56:
# disable all elements after bit l
@ -997,6 +1085,8 @@ class UESecCap(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
l = char.len_bit()
if l <= 40:
# disable all elements after bit l
@ -1494,6 +1584,8 @@ class APN_AMBR(Envelope):
Envelope.set_val(self, vals)
def _from_char(self, char):
if self.get_trans():
return
# in case long-enough buffer is available, make extended fields non-transparent
l = char.len_byte()
if l == 6:
@ -1577,6 +1669,8 @@ class EPSQoS(Envelope):
Envelope.set_val(self, vals)
def _from_char(self, char):
if self.get_trans():
return
# in case long-enough buffer is available, make extended fields non-transparent
l = char.len_byte()
if l == 13:
@ -1789,35 +1883,36 @@ class RemoteUEID(Envelope):
self[3]._val = encode_bcd(ident[1:])
def _from_char(self, char):
if not self.get_trans():
try:
spare = char.get_uint(5)
type = char.get_uint(3)
except CharpyErr as err:
raise(CharpyErr('{0} [_from_char]: {1}'.format(self._name, err)))
except Exception as err:
raise(EltErr('{0} [_from_char]: {1}'.format(self._name, err)))
#
if type == 1:
if not hasattr(self, '_IDEncIMSI'):
self._IDEncIMSI = RemUEIDEncIMSI()
self._content = self._IDTemp._content
self._by_id = self._IDTemp._by_id
self._by_name = self._IDTemp._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[3]._from_char(char)
#
elif type in (2, 3, 4, 5):
if not hasattr(self, '_IDDigit'):
self._IDDigit = RemUEIDDigit()
self._content = self._IDDigit._content
self._by_id = self._IDDigit._by_id
self._by_name = self._IDDigit._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[2]._val = type
self[3]._from_char(char)
if self.get_trans():
return
try:
spare = char.get_uint(5)
type = char.get_uint(3)
except CharpyErr as err:
raise(CharpyErr('{0} [_from_char]: {1}'.format(self._name, err)))
except Exception as err:
raise(EltErr('{0} [_from_char]: {1}'.format(self._name, err)))
#
if type == 1:
if not hasattr(self, '_IDEncIMSI'):
self._IDEncIMSI = RemUEIDEncIMSI()
self._content = self._IDTemp._content
self._by_id = self._IDTemp._by_id
self._by_name = self._IDTemp._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[3]._from_char(char)
#
elif type in (2, 3, 4, 5):
if not hasattr(self, '_IDDigit'):
self._IDDigit = RemUEIDDigit()
self._content = self._IDDigit._content
self._by_id = self._IDDigit._by_id
self._by_name = self._IDDigit._by_name
self[0]._val = spare >> 1
self[1]._val = spare & 1
self[2]._val = type
self[3]._from_char(char)
def repr(self):
if not self._content:
@ -1948,6 +2043,8 @@ class HdrCompConfig(Envelope):
Envelope.set_val(self, vals)
def _from_char(self, char):
if self.get_trans():
return
if char.get_len() >= 4:
self[9].set_trans(False)
self[10].set_trans(False)

View File

@ -41,10 +41,11 @@ from pycrate_core.base import *
from .TS24007 import *
from .TS24008_IE import (
AUTN, MSCm2, SuppCodecList, ExtDRXParam,
AUTN, MSCm2, SuppCodecList, ExtDRXParam, PLMNList, GPRSTimer2, GPRSTimer3,
EmergNumList,
)
from .TS24301_IE import (
NAS_KSI, EPSBearerCtxtStat,
NAS_KSI, EPSBearerCtxtStat, UENetCap as S1UENetCap, ExtEmergNumList
)
from .TS24501_IE import *
#from .TS24501_FGSM import FGSMTypeClasses
@ -204,13 +205,12 @@ class FGMMAuthenticationReject(Layer3):
# Registration request
# TS 24.501, section 8.2.6
#------------------------------------------------------------------------------#
# This is were things are getting serious...
class FGMMRegistrationRequest(Layer3):
_GEN = (
FGMMHeader(val={'Type':65}),
Type1V('NAS_KSI', IE=NAS_KSI()),
Type1V('5GSRegistrationType', IE=FGSRegType()),
Type1V('5GSRegType', IE=FGSRegType()),
Type6LVE('5GSID', val={'V':b'\0\0\0\0'}, IE=FGSID()),
Type1TV('NonCurrentNativeNAS_KSI', val={'T':0xC, 'V':0}, IE=NAS_KSI()),
Type4TLV('5GMMCap', val={'T':0x10, 'V':b'\0'}, IE=FGMMCap()),
@ -222,7 +222,7 @@ class FGMMRegistrationRequest(Layer3):
Type1TV('MICOInd', val={'T':0xB, 'V':0}, IE=MICOInd()),
Type4TLV('UEStatus', val={'T':0x2B, 'V':b'\0'}, IE=UEStatus()),
Type6TLVE('AddGUTI', val={'T':0x77, 'V':b'\xf2'+10*b'\0'}, IE=FGSID()),
Type4TLV('AllowedPDUSessStat', val={'T':0x25, 'V':b'\0\0'}, IE=AllowedPDUSessStat()),
Type4TLV('AllowedPDUSessStat', val={'T':0x25, 'V':b'\0\0'}, IE=PDUSessStat()),
Type4TLV('UEUsage', val={'T':0x18, 'V':b'\0'}, IE=UEUsage()),
Type4TLV('5GSDRXParam', val={'T':0x51, 'V':b'\0'}, IE=FGSDRXParam()),
Type6TLVE('EPSNASContainer', val={'T':0x70, 'V':b'\x07\0'}),
@ -240,3 +240,45 @@ class FGMMRegistrationRequest(Layer3):
Type4TLV('UERadioCapID', val={'T':0x67, 'V':b'\0'}, IE=UERadioCapID()),
)
#------------------------------------------------------------------------------#
# Registration accept
# TS 24.501, section 8.2.7
#------------------------------------------------------------------------------#
class FGMMRegistrationAccept(Layer3):
_GEN = (
FGMMHeader(val={'Type':66}),
Type4LV('5GSRegResult', val={'V':b'\0'}, IE=FGSRegType()),
Type6LVE('GUTI', val={'V':b'\0\0\0\0'}, IE=FGSID()),
Type4TLV('EquivPLMNList', val={'T':0x4A, 'V':3*b'\0'}, IE=PLMNList()),
Type4TLV('5GSTAIList', val={'T':0x54, 'V':7*b'\0'}, IE=FGSTAIList()),
Type4TLV('AllowedNSSAI', val={'T':0x15, 'V':b'\0\0'}, IE=NSSAI()),
Type4TLV('RejectedNSSAI', val={'T':0x11, 'V':b'\0\0'}, IE=RejectedNSSAI()),
Type4TLV('ConfiguredNSSAI', val={'T':0x31, 'V':b'\0\0'}, IE=NSSAI()),
Type4TLV('5GSNetFeat', val={'T':0x21, 'V':b'\0'}, IE=FGSNetFeat()),
Type4TLV('PDUSessStat', val={'T':0x50, 'V':b'\0\0'}, IE=PDUSessStat()),
Type4TLV('PDUSessStatReactResult', val={'T':0x26, 'V':b'\0\0'}, IE=PDUSessStat()),
Type6TLVE('PDUSessReactResultErr', val={'T':0x72, 'V':b'\0\0'}, IE=PDUSessReactResultErr()),
Type6TLVE('LADNInfo', val={'T':0x79, 'V':9*b'\0'}, IE=LADNInfo()),
Type1TV('MICOInd', val={'T':0xB, 'V':0}, IE=MICOInd()),
Type1TV('NetSlicingInd', val={'T':0x9, 'V':0}, IE=NetSlicingInd()),
Type6TLVE('SAList', val={'T':0x27, 'V':b'\0\0\0'}, IE=SAList()),
Type4TLV('T3512', val={'T':0x5E, 'V':b'\0'}, IE=GPRSTimer3()),
Type4TLV('Non3GPPDeregTimer', val={'T':0x5D, 'V':b'\0'}, IE=GPRSTimer()),
Type4TLV('T3502', val={'T':0x16, 'V':b'\0'}, IE=GPRSTimer()),
Type4TLV('EmergNumList', val={'T':0x34, 'V':b'\x02\x01\0'}, IE=EmergNumList()),
Type6TLVE('ExtEmergNumList', val={'T':0x7A, 'V':b'\0\0\0\0'}, IE=ExtEmergNumList()),
Type6TLVE('SORTransparentContainer', val={'T':0x73, 'V':17*b'\0'}, IE=SORTransparentContainer()),
Type6TLVE('EAPMsg', val={'T':0x78, 'V':b'\0\0\0\0'}),
Type1TV('NSSAIInclMode', val={'T':0xA, 'V':0}, IE=NSSAIInclMode()),
Type6TLVE('OperatorAccessCatDefs', val={'T':0x76, 'V':b''}, IE=OperatorAccessCatDefs()),
)

View File

@ -44,9 +44,8 @@ from pycrate_core.charpy import Charpy
from pycrate_mobile.TS24008_IE import (
BufBCD, PLMN, GPRSTimer3,
)
from pycrate_mobile.TS24301_IE import (
UENetCap as S1UENetCap, UESecCap as S1UESecCap,
)
#from pycrate_mobile.TS24301_IE import (
# )
_str_reserved = 'reserved'
_str_mnospec = 'operator-specific'
@ -68,7 +67,7 @@ SecHdrType_dict = {
#------------------------------------------------------------------------------#
# DNN
# TS 24.301, 9.11.2.1A
# TS 24.501, 9.11.2.1A
#------------------------------------------------------------------------------#
class DNN(Envelope):
@ -85,7 +84,7 @@ class DNN(Envelope):
#------------------------------------------------------------------------------#
# S-NSSAI
# TS 24.301, 9.11.2.8
# TS 24.501, 9.11.2.8
#------------------------------------------------------------------------------#
class _SNSSAI_SST_MappedHSST(Envelope):
@ -98,14 +97,14 @@ class _SNSSAI_SST_MappedHSST(Envelope):
class _SNSSAI_SST_SD(Envelope):
_GEN = (
Uint8('SST'),
Uint16('SD')
Uint24('SD')
)
class _SNSSAI_SST_SD_MappedHSST(Envelope):
_GEN = (
Uint8('SST'),
Uint16('SD'),
Uint24('SD'),
Uint8('MappedHPLMNSST')
)
@ -113,18 +112,18 @@ class _SNSSAI_SST_SD_MappedHSST(Envelope):
class _SNSSAI_SST_SD_MappedHSSTSD(Envelope):
_GEN = (
Uint8('SST'),
Uint16('SD'),
Uint24('SD'),
Uint8('MappedHPLMNSST'),
Uint16('MappedHPLMNSD')
Uint24('MappedHPLMNSD')
)
class _SNSSAI_SST_SD_MappedHSSTSD_spare(Envelope):
_GEN = (
Uint8('SST'),
Uint16('SD'),
Uint24('SD'),
Uint8('MappedHPLMNSST'),
Uint16('MappedHPLMNSD'),
Uint24('MappedHPLMNSD'),
Buf('spare', rep=REPR_HEX)
)
@ -133,11 +132,11 @@ class SNSSAI(Envelope):
_GEN = (
Uint8('Len'),
Alt('Value', GEN={
0 : Buf('none', bl=0),
1 : Uint8('SST'),
2 : _SNSSAI_SST_MappedHSST('SST_MappedHPLMNSST'),
3 : _SNSSAI_SST_SD('SST_SD'),
4 : _SNSSAI_SST_SD_MappedHSSTSD('SST_SD_MappedHPLMNSSTSD')},
1: Uint8('SST'),
2: _SNSSAI_SST_MappedHSST('SST_MappedHPLMNSST'),
4: _SNSSAI_SST_SD('SST_SD'),
5: _SNSSAI_SST_SD_MappedHSST('SST_SD_MappedHPLMNSST'),
8: _SNSSAI_SST_SD_MappedHSSTSD('SST_SD_MappedHPLMNSSTSD')},
DEFAULT=_SNSSAI_SST_SD_MappedHSSTSD_spare('SST_SD_MappedHPLMNSSTSD_spare'),
sel=lambda self: self.get_env()['Len'].get_val()
)
@ -150,7 +149,7 @@ class SNSSAI(Envelope):
#------------------------------------------------------------------------------#
# 5GMM capability
# TS 24.301, 9.11.3.1
# TS 24.501, 9.11.3.1
#------------------------------------------------------------------------------#
class FGMMCap(Envelope):
@ -178,6 +177,8 @@ class FGMMCap(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
l = char.len_bit()
if l <= 16:
# disable all elements after bit l
@ -206,7 +207,7 @@ class FGMMCap(Envelope):
#------------------------------------------------------------------------------#
# 5GMM cause
# TS 24.301, 9.11.3.2
# TS 24.501, 9.11.3.2
#------------------------------------------------------------------------------#
_FGMMCause_dict = {
@ -259,7 +260,7 @@ class FGMMCause(Uint8):
#------------------------------------------------------------------------------#
# 5GS DRX parameters
# TS 24.301, 9.11.3.2A
# TS 24.501, 9.11.3.2A
#------------------------------------------------------------------------------#
_FGSDRXParam_dict = {
@ -280,7 +281,7 @@ class FGSDRXParam(Envelope):
#------------------------------------------------------------------------------#
# 5GS mobile identity
# TS 24.301, 9.11.3.4
# TS 24.501, 9.11.3.4
#------------------------------------------------------------------------------#
FGSIDType_dict = {
@ -331,6 +332,8 @@ class SUCI_ECIESProfA(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
self[0]._from_char(char)
ct_bl = char.len_bit() - 64
if ct_bl > 0:
@ -349,6 +352,8 @@ class SUCI_ECIESProfB(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
self[0]._from_char(char)
ct_bl = char.len_bit() - 64
if ct_bl > 0:
@ -521,17 +526,92 @@ class FGSID(Envelope):
Envelope.set_val(self, kwargs)
def _from_char(self, char):
if not self.get_trans():
# get the type and set the appropriate content
type = char.to_uint(8) & 0x7
self._set_content(type)
Envelope._from_char(self, char)
if self.get_trans():
return
# get the type and set the appropriate content
type = char.to_uint(8) & 0x7
self._set_content(type)
Envelope._from_char(self, char)
#------------------------------------------------------------------------------#
# 5GS network feature support
# TS 24.501, 9.11.3.5
#------------------------------------------------------------------------------#
class FGSNetFeat(Envelope):
_name = '5GSNetFeat'
_GEN = (
Uint('MPSI', bl=1),
Uint('IWK_N26', bl=1),
Uint('EMF', bl=1),
Uint('EMC', bl=3),
Uint('IMS-VoPS-N3GPP', bl=1),
Uint('IMS-VoPS-3GPP', bl=1), # end of octet 1
Uint('5G-LCS', bl=1),
Uint('5G-UP-CIoT', bl=1),
Uint('5G-HC-CP-CIoT', bl=1),
Uint('N3Data', bl=1),
Uint('5G-CP-CIoT', bl=1),
Uint('RestrictEC', bl=1),
Uint('MCSI', bl=1),
Uint('EMCN3', bl=1), # end of octet 2
Buf('spare', val=b'', rep=REPR_HEX)
)
def _from_char(self, char):
if self.get_trans():
return
l = char.len_bit()
if l <= 8:
# disable all elements after bit l
self.disable_from('5G-LCS')
elif l > 16:
# enables some spare bits at the end
self[-1]._bl = l-16
Envelope._from_char(self, char)
def disable_from(self, ind):
"""disables all elements from index `ind' excluded (element offset or name)
"""
if isinstance(ind, str_types) and ind in self._by_name:
ind = self._by_name.index(ind)
[e.set_trans(True) for e in self._content[ind:]]
def enable_upto(self, ind):
"""enables all elements up to index `ind' included (element offset or name)
"""
if isinstance(ind, str_types) and ind in self._by_name:
ind = 1 + self._by_name.index(ind)
[e.set_trans(False) for e in self._content[:ind]]
#------------------------------------------------------------------------------#
# 5GS registration result
# TS 24.501, 9.11.3.6
#------------------------------------------------------------------------------#
_FGSRegResult_dict = {
1 : '3GPP access',
2 : 'Non-3GPP access',
3 : '3GPP access and non-3GPP access',
7 : _str_reserved
}
class FGSRegResult(Envelope):
_name = '5GSRegType'
_GEN = (
Uint('spare', bl=3),
Uint('NSSAAPerformed', bl=1),
Uint('SMSAllowed', bl=1),
Uint('Value', bl=3, dic=_FGSRegResult_dict)
)
#------------------------------------------------------------------------------#
# 5GS registration type
# TS 24.301, 9.11.3.7
# TS 24.501, 9.11.3.7
#------------------------------------------------------------------------------#
_FOR_dict = {
@ -557,7 +637,7 @@ class FGSRegType(Envelope):
#------------------------------------------------------------------------------#
# 5GS tracking area identity
# TS 24.301, 9.11.3.8
# TS 24.501, 9.11.3.8
#------------------------------------------------------------------------------#
class FGSTAI(Envelope):
@ -566,11 +646,110 @@ class FGSTAI(Envelope):
PLMN(),
Uint24('TAC', rep=REPR_HEX)
)
encode = Envelope.set_val
def decode(self):
return (self[0].decode(), self[1].get_val())
#------------------------------------------------------------------------------#
# 5GS tracking area identity list
# TS 24.501, 9.11.3.9
#------------------------------------------------------------------------------#
_PTAIListType_dict = {
0 : 'list of TACs belonging to one PLMN, with non-consecutive TAC values',
1 : 'list of TACs belonging to one PLMN, with consecutive TAC values',
2 : 'list of TAIs belonging to different PLMNs'
}
class _PTAIList0(Envelope):
"""List of non-consecutive TACs belonging to one PLMN
"""
_GEN = (
Uint('Num', bl=5),
PLMN(),
Array('TACs', GEN=Uint24('TAC'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: max(0, self[2].get_num()-1))
self[2].set_numauto(lambda: self[0].get_val()+1)
def get_tai(self):
plmn = self['PLMN'].decode()
return set([(plmn, tac) for tac in self['TACs'].get_val()])
class _PTAIList1(Envelope):
"""List of consecutive TACs belonging to one PLMN
"""
_GEN = (
Uint('Num', bl=5),
PLMN(),
Uint24('TAC1'),
)
def get_tai(self):
plmn, tac1 = self['PLMN'].decode(), self['TAC1'].get_val()
return set([(plmn, tac1 + i) for i in range(self['Num'].get_val() + 1)])
class _PTAIList2(Envelope):
"""List of TAI belonging to different PLMNs
"""
_GEN = (
Uint('Num', bl=5),
Sequence('TAIs', GEN=FGSTAI())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: max(0, self[1].get_num()-1))
self[1].set_numauto(lambda: self[0].get_val()+1)
def get_tai(self):
return set([tai.decode() for tai in self['TAIs']])
class FGSPTAIList(Envelope):
_name = '5GSPTAIList'
_GEN = (
Uint('spare', bl=1),
Uint('Type', bl=2, dic=_PTAIListType_dict),
Alt('PTAI', GEN={
0: _PTAIList0('PTAIList0'),
1: _PTAIList1('PTAIList1'),
2: _PTAIList2('PTAIList2')
},
DEFAULT=_PTAIList1('PTAIList1'),
sel=lambda self: self.get_env()['Type'].get_val())
)
def get_tai(self):
return self['PTAI'].get_alt().get_tai()
class FGSTAIList(Sequence):
_name = '5GSTAIList'
_GEN = FGSPTAIList()
def get_tai(self):
tai = set()
for tl in self:
tai.update(tl.get_tai())
return tai
#------------------------------------------------------------------------------#
# 5GS update type
# TS 24.301, 9.11.3.9A
# TS 24.501, 9.11.3.9A
#------------------------------------------------------------------------------#
class FGSUpdateType(Envelope):
@ -586,55 +765,9 @@ class FGSUpdateType(Envelope):
#------------------------------------------------------------------------------#
# Allowed PDU session status
# TS 24.301, 9.11.3.13
# TS 24.501, 9.11.3.13
#------------------------------------------------------------------------------#
class AllowedPDUSessStat(Envelope):
_GEN = (
Uint('PSI_7', bl=1),
Uint('PSI_6', bl=1),
Uint('PSI_5', bl=1),
Uint('PSI_4', bl=1),
Uint('PSI_3', bl=1),
Uint('PSI_2', bl=1),
Uint('PSI_1', bl=1),
Uint('PSI_0', bl=1),
Uint('PSI_15', bl=1),
Uint('PSI_14', bl=1),
Uint('PSI_13', bl=1),
Uint('PSI_12', bl=1),
Uint('PSI_11', bl=1),
Uint('PSI_10', bl=1),
Uint('PSI_9', bl=1),
Uint('PSI_8', bl=1),
Buf('spare', val=b'', rep=REPR_HEX)
)
def _from_char(self, char):
l = char.len_bit()
if l <= 16:
# disable all elements after bit l
self.disable_from(l)
elif l > 16:
# enables some spare bits at the end
self[-1]._bl = l-16
Envelope._from_char(self, char)
def disable_from(self, ind):
"""disables all elements from index `ind' excluded (integer -bit offset-
or element name)
"""
if isinstance(ind, str_types) and ind in self._by_name:
ind = self._by_name.index(ind)
[e.set_trans(True) for e in self._content[ind:]]
def enable_upto(self, ind):
"""enables all elements up to index `ind' included (integer -bit offset-
or element name)
"""
if isinstance(ind, str_types) and ind in self._by_name:
ind = 1 + self._by_name.index(ind)
[e.set_trans(False) for e in self._content[:ind]]
# actually identical to PDU session status in .44
#------------------------------------------------------------------------------#
@ -646,6 +779,22 @@ class LADNInd(Sequence):
_GEN = DNN()
#------------------------------------------------------------------------------#
# LADN information
# TS 24.501, 9.11.3.30
#------------------------------------------------------------------------------#
class LADN(Envelope):
_GEN = (
DNN(),
FGSTAIList()
)
class LADNInfo(Sequence):
_GEN = LADN()
#------------------------------------------------------------------------------#
# MICO indication
# TS 24.501, 9.11.3.31
@ -685,6 +834,135 @@ class NSSAI(Sequence):
_GEN = SNSSAI()
#------------------------------------------------------------------------------#
# NSSAI inclusion mode
# TS 24.501, 9.11.3.37A
#------------------------------------------------------------------------------#
class NSSAIInclMode(Envelope):
_GEN = (
Uint('spare', bl=2),
Uint('Value', bl=2, dic={0:'A', 1:'B', 2:'C', 3:'D'})
)
#------------------------------------------------------------------------------#
# Operator-defined access category definitions
# TS 24.501, 9.11.3.38
#------------------------------------------------------------------------------#
_CriteriaType_dict = {
0 : 'DNN',
1 : 'OS Id + OS App Id',
2 : 'S-NSSAI'
}
class _CritDNNs(Envelope):
_GEN = (
Uint8('Cnt'),
Array('DNNs', GEN=DNN())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_val())
class _CritOSAppId(Envelope):
_GEN = (
Buf('OS_UUID', bl=128, rep=REPR_HEX),
Uint8('LenAppId'),
Buf('AppId')
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[1].set_valauto(lambda: self[2].get_len())
self[2].set_blauto(lambda: self[1].get_val()<<3)
class _CritOSAppIds(Envelope):
_GEN = (
Uint8('Cnt'),
Array('OSAppIds', GEN=_CritOSAppId('OSAppId'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_val())
class _CritSNSSAI(Envelope):
_GEN = (
Uint8('Cnt'),
Sequence('SNSSAIs', GEN=SNSSAI())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_val())
class CriteriaComp(Envelope):
_GEN = (
Uint8('Type', dic=_CriteriaType_dict),
Alt('Crit', GEN={
0 : _CritDNNs('CompDNN'),
1 : _CritOSAppIds('CompOSAppId'),
2 : _CritSNSSAI('CompNSSAI')},
DEFAULT=Buf('CompUnk', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val()
)
)
class OperatorAccessCatDef(Envelope):
_GEN = (
Uint8('Len'),
Uint8('Precedence'),
Uint('PSAC', bl=1),
Uint('spare', bl=2),
Uint('AccessCatNum', bl=5),
Uint8('LenCriteria'),
Sequence('Criteria', GEN=CriteriaComp()),
Envelope('StdAccessCat', GEN=(
Uint('spare', bl=3),
Uint('Value', bl=5)),
) # optional, depends on PSAC (Presence of Std Access Cat...)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['Len'].set_valauto(lambda: 3 + self['LenCriteria'].get_val() if self['StdAccessCat'].get_trans() \
else 4 + self['LenCriteria'].get_val())
self['LenCriteria'].set_valauto(lambda: self['Criteria'].get_len())
self['StdAccessCat'].set_transauto(lambda: False if self['PSAC'].get_val() else True)
def _from_char(self, char):
if self.get_trans():
return
self[0]._from_char(char)
self[1]._from_char(char)
self[2]._from_char(char)
self[3]._from_char(char)
self[4]._from_char(char)
self[5]._from_char(char)
# truncate char according to LenCriteria
char_lb = char._len_bit
char._len_bit = char._cur + (self[5].get_val()<<3)
self[6]._from_char(char)
char._len_bit = char_lb
self[7]._from_char(char)
class OperatorAccessCatDefs(Sequence):
_GEN = OperatorAccessCatDef()
#------------------------------------------------------------------------------#
# Payload container type
# TS 24.501, 9.11.3.40
@ -774,6 +1052,8 @@ class _PayContOpt(Envelope):
self[1].set_valauto(lambda: self[2].get_len())
def _from_char(self, char):
if self.get_trans():
return
self[0]._from_char(char)
self[1]._from_char(char)
optlen = self[1].get_val()
@ -812,6 +1092,228 @@ class PayloadContainer(Envelope):
self[1].set_numauto(lambda: self[0].get_val())
#------------------------------------------------------------------------------#
# PDU session reactivation result error cause
# TS 24.501, 9.11.3.42
#------------------------------------------------------------------------------#
class PDUSessReactResultErr(Array):
_GEN = Envelope('PDUSessErr', GEN=(
Uint8('PSI'),
Uint8('Cause', dic=_FGMMCause_dict))
)
#------------------------------------------------------------------------------#
# PDU session status
# TS 24.501, 9.11.3.44
#------------------------------------------------------------------------------#
class PDUSessStat(Envelope):
_GEN = (
Uint('PSI_7', bl=1),
Uint('PSI_6', bl=1),
Uint('PSI_5', bl=1),
Uint('PSI_4', bl=1),
Uint('PSI_3', bl=1),
Uint('PSI_2', bl=1),
Uint('PSI_1', bl=1),
Uint('PSI_0', bl=1),
Uint('PSI_15', bl=1),
Uint('PSI_14', bl=1),
Uint('PSI_13', bl=1),
Uint('PSI_12', bl=1),
Uint('PSI_11', bl=1),
Uint('PSI_10', bl=1),
Uint('PSI_9', bl=1),
Uint('PSI_8', bl=1),
Buf('spare', val=b'', rep=REPR_HEX)
)
def _from_char(self, char):
if self.get_trans():
return
l = char.len_bit()
if l <= 16:
# disable all elements after bit l
self.disable_from(l)
elif l > 16:
# enables some spare bits at the end
self[-1]._bl = l-16
Envelope._from_char(self, char)
def disable_from(self, ind):
"""disables all elements from index `ind' excluded (integer -bit offset-
or element name)
"""
if isinstance(ind, str_types) and ind in self._by_name:
ind = self._by_name.index(ind)
[e.set_trans(True) for e in self._content[ind:]]
def enable_upto(self, ind):
"""enables all elements up to index `ind' included (integer -bit offset-
or element name)
"""
if isinstance(ind, str_types) and ind in self._by_name:
ind = 1 + self._by_name.index(ind)
[e.set_trans(False) for e in self._content[:ind]]
#------------------------------------------------------------------------------#
# Rejected NSSAI
# TS 24.501, 9.11.3.46
#------------------------------------------------------------------------------#
class RejectedSNSSAI(Envelope):
_GEN = (
Uint8('Len'),
Alt('Value', GEN={
1: Uint8('SST'),
4: Envelope('SST_SD', GEN=(Uint8('SST'), Uint24('SD')))},
sel=lambda self: self.get_env()['Len'].get_val()
)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_len())
class RejectedNSSAI(Sequence):
_GEN = RejectedSNSSAI()
#------------------------------------------------------------------------------#
# Service area list
# TS 24.501, 9.11.3.49
#------------------------------------------------------------------------------#
class _PTAIList3(Envelope):
"""All TAI belonging to a given PLMN
"""
_GEN = (
Uint('Num', val=0, bl=5),
PLMN(),
)
def get_tai(self):
return {(self['PLMN'].decode(), None), }
_AllowedPSAList_dict = {
0: 'TAIs in the list are in the allowed area',
1: 'TAIs in the list are in the non-allowed area'
}
class PSAList(Envelope):
_GEN = (
Uint('Allowed', bl=1, dic=_AllowedPSAList_dict),
Uint('Type', bl=2, dic=_PTAIListType_dict),
Alt('PTAI', GEN={
0: _PTAIList0('PTAIList0'),
1: _PTAIList1('PTAIList1'),
2: _PTAIList2('PTAIList2'),
3: _PTAIList3('PTAIList3')
},
DEFAULT=_PTAIList1('PTAIList3'),
sel=lambda self: self.get_env()['Type'].get_val())
)
def get_tai(self):
return self['PTAI'].get_alt().get_tai()
class SAList(Sequence):
_GEN = FGSPTAIList()
def get_tai(self):
tai = set()
for tl in self:
tai.update(tl.get_tai())
return tai
#------------------------------------------------------------------------------#
# SOR transparent container
# TS 24.501, 9.11.3.51
#------------------------------------------------------------------------------#
_SORDataType_dict = {
0: 'steering of roaming information',
1: 'acknowledgement of successful reception of the steering of roaming information'
}
_SORListInd_dict = {
0: 'no change in the list of operator controlled PLMN',
1: 'list of preferred PLMN/access technology combinations provided'
}
_SORListType_dict = {
0: 'secured packet',
1: 'list of PLMN ID and access technology'
}
_SORAck_dict = {
0: 'Ack not requested',
1: 'Ack requested'
}
class SORHeader(Envelope):
_GEN = (
Uint('spare', bl=4, rep=REPR_HEX),
Uint('ACK', bl=1, dic=_SORAck_dict),
Uint('ListType', bl=1, dic=_SORListType_dict),
Uint('ListInd', bl=1, dic=_SORListInd_dict),
Uint('DataType', bl=1, dic=_SORDataType_dict)
)
class _SORTransCont00(Envelope):
_GEN = (
Buf('SOR_MACI_AUSF', bl=128, rep=REPR_HEX),
Uint16('CntSOR'),
Buf('SecuredPkt', rep=REPR_HEX)
)
class _SORTransCont01(Envelope):
_GEN = (
Buf('SOR_MACI_AUSF', bl=128, rep=REPR_HEX),
Uint16('CntSOR'),
Sequence('PLMNATList', GEN=Envelope('PLMNAT', GEN=(
PLMN(),
Uint16('AccessTechno')))
)
)
class _SORTransCont1(Envelope):
_GEN = (
Buf('SOR_MACI_UE', bl=128, rep=REPR_HEX),
)
def get_sor_types(cont):
hdr = cont.get_env()['SORHeader']
return hdr['DataType'].get_val(), hdr['ListType'].get_val()
class SORTransparentContainer(Envelope):
_GEN = (
SORHeader(),
Alt('Cont', GEN={
(0, 0): _SORTransCont00('SORSecuredPkt'),
(0, 1): _SORTransCont01('SORPLMNList'),
(1, 0): _SORTransCont1('SORACK'),
(1, 1): _SORTransCont1('SORACK')},
sel=lambda self: get_sor_types(self)
)
)
#------------------------------------------------------------------------------#
# UE security capability
# TS 24.501, 9.11.3.54
@ -858,6 +1360,8 @@ class UESecCap(Envelope):
)
def _from_char(self, char):
if self.get_trans():
return
l = char.len_bit()
if l <= 32:
# disable all elements after bit l
@ -915,7 +1419,7 @@ class UEStatus(Envelope):
# TS 24.501, 9.11.3.57
#------------------------------------------------------------------------------#
class ULDataStat(AllowedPDUSessStat):
class ULDataStat(PDUSessStat):
pass
#------------------------------------------------------------------------------#