From 822bdda33259a8bef5a6e62a55d9bad826807cde Mon Sep 17 00:00:00 2001 From: mich Date: Fri, 21 Aug 2020 12:50:32 +0200 Subject: [PATCH] mobile: finalize 5G NAS update --- pycrate_mobile/NAS5G.py | 161 ++++++++++++++++++++++---------- pycrate_mobile/TS24007.py | 19 +++- pycrate_mobile/TS24501_IE.py | 12 ++- pycrate_mobile/TS24519_TSNAF.py | 8 +- 4 files changed, 144 insertions(+), 56 deletions(-) diff --git a/pycrate_mobile/NAS5G.py b/pycrate_mobile/NAS5G.py index 347179b..33d03f3 100644 --- a/pycrate_mobile/NAS5G.py +++ b/pycrate_mobile/NAS5G.py @@ -32,6 +32,7 @@ from pycrate_core.utils import * from .TS24501_FGMM import FGMMTypeClasses, FGMMSecProtNASMessage from .TS24501_FGSM import FGSMTypeClasses from .TS24501_UEPOL import FGUEPOLTypeClasses +from .TS24519_TSNAF import FGTSNAFEthPortTypeClasses, FGTSNAFBridgeTypeClasses from .TS24011_PPSMS import PPSMSCPTypeClasses @@ -111,90 +112,154 @@ def parse_NAS5G(buf, inner=True, sec_hdr=True): # error 96, invalid mandatory info return None, 96 # - if inner and pd == 126: - if typ in (65, 76, 79, 94): - nasc = Msg['NASContainer'] - if not nasc.get_trans(): - # NAS Container present in Msg - cont, err = parse_NAS5G(nasc[-1].get_val(), inner=inner) - if err == 0: - nasc.replace(nasc[-1], cont) + if inner: + if pd == 126: + if typ in (65, 76, 79, 94): + nasc = Msg['NASContainer'] + if not nasc.get_trans(): + # NAS Container present in Msg + Cont, err = parse_NAS5G(nasc[-1].get_val(), inner=inner) + if err == 0: + nasc.replace(nasc['V'], Cont) + # + if typ in (65, 79, 103, 104): + payct, payc = Msg['PayloadContainerType'], Msg['PayloadContainer'] + if not payct.get_trans() and not payc.get_trans(): + # Payload container present in Msg + conttype, contbuf = payct['V'].get_val(), payc['V'].get_val() + Cont, err = parse_PayCont(conttype, contbuf) + if err == 0: + payc.replace(payc['V'], Cont) # - if typ in (65, 79, 103, 104): - payct, payc = Msg['PayloadContainerType'], Msg['PayloadContainer'] - if not payct.get_trans() and not payc.get_trans(): - # Payload container present in Msg - conttype, contbuf = payct['V'].get_val(), payc['V'].get_val() - cont = parse_NAS5GPayCont(conttype, contbuf) - if cont: - payc.replace(payc['V'], cont) + elif pd == 46: + if typ in (193, 201, 203, 204): + ethc = Msg['PortMgmtInfoContainer'] + if not ethc.get_trans(): + # PortMgmtInfoContainer present in Msg + Cont, err = parse_PortMgmtInfoCont(ethc['V'].get_val()) + if err == 0: + ethc.replace(ethc['V'], Cont) # return Msg, 0 -def parse_NAS5GPayCont(conttype, buf): +def parse_PayCont(conttype, buf): + if conttype == 1 and len(buf) >= 2: # 5GSM - cont, err = parse_NAS5G(buf, inner=True) - if err == 0: - return cont + return parse_NAS5G(buf, inner=True) + elif conttype == 2 and len(buf) >= 2: # SMS PP pd, typ = unpack('>BB', buf[:2]) pd &= 0xF if pd == 9 and typ in (1, 4, 16): - cont = PPSMSCPTypeClasses[typ]() + Cont = PPSMSCPTypeClasses[typ]() try: - cont.from_bytes(buf) + Cont.from_bytes(buf) except Exception: - pass + # error 96, invalid mandatory info + return None, 96 else: - return cont + return Cont, 0 + else: + # error 97, Message type non-existent or not implemented + return None, 97 + elif conttype == 3: # LPP, TODO pass + elif conttype == 4 and len(buf) >= 17: # SOR - cont = SORTransparentContainer() + Cont = SORTransContainer() try: - cont.from_bytes(buf) + Cont.from_bytes(buf) except Exception: - pass + # error 96, invalid mandatory info + return None, 96 else: - return cont + return Cont, 0 + elif conttype == 5 and len(buf) >= 2: # UE policy _, typ = unpack('>BB', buf[:2]) if 1 <= typ <= 4: - cont = FGUEPOLTypeClasses[typ]() + Cont = FGUEPOLTypeClasses[typ]() try: - cont.from_bytes(buf) + Cont.from_bytes(buf) except Exception: - pass + # error 96, invalid mandatory info + return None, 96 else: - return cont - elif conttype == 6: - # UE params update, TODO - pass + return Cont, 0 + else: + # error 97, Message type non-existent or not implemented + return None, 97 + + elif conttype == 6 and len(buf) >= 17: + # UPU + Cont = UPUTransContainer() + try: + Cont.from_bytes(buf) + except Exception: + # error 96, invalid mandatory info + return None, 96 + else: + return Cont, 0 + elif conttype == 7: - # Loc services, TODO - pass - elif conttype == 8: - # CIoT, TODO + # LCS, TODO pass + + elif conttype == 8 and len(buf) >= 1: + # CIoT + Cont = CIoTSmallDataContainer() + try: + Cont.from_bytes(buf) + except Exception: + # error 96, invalid mandatory info + return None, 96 + else: + return Cont, 0 + elif conttype == 15 and len(buf) >= 1: # multi - cont = PayloadContainerMult() + Cont = PayloadContainerMult() try: - cont.from_bytes(buf) + Cont.from_bytes(buf) except Exception: - pass + # error 96, invalid mandatory info + return None, 96 else: # parse each entry for entry in cont['Entries']: - econttype, ebuf = cont['Type'].get_val(), cont['Cont'].get_val() - econt = parse_NAS5GPayCont(econttype, ebuf) - if econt: - entry.replace(entr['Cont'], econt) - return None - + e_conttype, e_buf = Cont['Type'].get_val(), Cont['Cont'].get_val() + e_cont, e_err = parse_NAS5GPayCont(e_conttype, e_buf) + if e_err == 0: + entry.replace(entry['Cont'], e_cont) + + # error 96, invalid mandatory info + return None, 96 + + +def parse_PortMgmtInfoCont(buf): + try: + # this corresponds actually only to the layout of the 5GMM header + typ = unpack('>B', buf[:1]) + except Exception: + # error 96, invalid mandatory info + return None, 96 + if 1 <= typ <= 6: + Cont = FGTSNAFEthPortTypeClasses[typ]() + try: + Cont.from_bytes(buf) + except Exception: + # error 96, invalid mandatory info + return None, 96 + else: + return Cont, 0 + else: + # error 97, Message type non-existent or not implemented + return None, 97 + diff --git a/pycrate_mobile/TS24007.py b/pycrate_mobile/TS24007.py index 9290662..66fff93 100644 --- a/pycrate_mobile/TS24007.py +++ b/pycrate_mobile/TS24007.py @@ -70,9 +70,11 @@ class Layer3(Envelope): ENV_SEL_TRANS = False # this is to break the decoding routine when an unknown IE is encountered + # this needs to be set to True for 2G RR signaling message (due to rest octets) DEC_BREAK_ON_UNK_IE = False + def __init__(self, *args, **kw): if 'val' in kw: val = kw['val'] @@ -102,30 +104,38 @@ class Layer3(Envelope): self._rest = ie else: for ie in self._content: + ''' if isinstance(ie, (Type1V, Type1TV)): rawtype = integer_types else: rawtype = bytes_types + ''' if isinstance(ie, (Type1V, Type3V, Type4LV, Type6LVE)) and ie._name in val: # setting value for non-optional IE + ie.set_val({'V': val[ie._name]}) + ''' if isinstance(val[ie._name], rawtype): # setting raw value ie['V'].set_val(val[ie._name]) else: # setting embedded IE structure ie.set_IE(val=val[ie._name]) + ''' elif isinstance(ie, (Type1TV, Type3TV, Type4TLV, Type6TLVE)): # optional IE T = ie[0] self._opts.append( (T.get_bl(), T(), ie) ) if ie._name in val: ie._trans = False + ie.set_val({'V': val[ie._name]}) + ''' if isinstance(val[ie._name], rawtype): # setting raw value ie['V'].set_val(val[ie._name]) else: # setting embedded IE structure ie.set_IE(val=val[ie._name]) + ''' elif isinstance(ie, Type2): # optional Tag-only IE self._opts.append( (8, ie[0](), ie) ) @@ -269,20 +279,25 @@ class IE(Envelope): elif isinstance(vals, (tuple, list)): for ind, elt in enumerate(self.__iter__()): val = vals[ind] - if elt._name == 'V' and not isinstance(val, bytes_types): + if elt._name == 'V' and not isinstance(val, elt.TYPES): + # keep value for setting the inner IE ie_val = val else: + # set raw V value elt.set_val(val) elif isinstance(vals, dict): for key, val in vals.items(): - if key == 'V' and not isinstance(val, bytes_types): + if key == 'V' and not isinstance(val, self['V'].TYPES): + # keep value for setting the inner IE ie_val = val else: + # set raw V value self.__setitem__(key, val) elif self._SAFE_STAT: raise(EltErr('{0} [set_val]: vals type is {1}, expecting None, tuple, list or dict'\ .format(self._name, type(vals).__name__))) if ie_val is not None: + # set the value to the inner IE self.set_IE(val=ie_val) def _from_char(self, char): diff --git a/pycrate_mobile/TS24501_IE.py b/pycrate_mobile/TS24501_IE.py index 4a53707..e5310a2 100644 --- a/pycrate_mobile/TS24501_IE.py +++ b/pycrate_mobile/TS24501_IE.py @@ -186,6 +186,8 @@ class SNSSAI(Envelope): def _from_char(self, char): + if self.get_trans(): + return l = char.len_bit() if l == 8: self[1].set_trans(True) @@ -683,6 +685,9 @@ _EMF_dict = { class FGSNetFeat(Envelope): + + ENV_SEL_TRANS = False + _name = '5GSNetFeat' _GEN = ( Uint('MPSI', bl=1), @@ -710,9 +715,9 @@ class FGSNetFeat(Envelope): return l = char.len_bit() if l <= 8: - self.disable_from(8) + self.disable_from('5G-UP-CIoT') elif l <= 16: - self.disable_from(13) + self.disable_from('spare') elif l > 24: # enables some spare bits at the end self[-1]._bl = l-24 @@ -1883,6 +1888,9 @@ class AddConfigInd(Envelope): #------------------------------------------------------------------------------# class FGSMCap(Envelope): + + ENV_SEL_TRANS = False + _name = '5GSMCap' _GEN = ( Uint('TPMIC', bl=1), diff --git a/pycrate_mobile/TS24519_TSNAF.py b/pycrate_mobile/TS24519_TSNAF.py index 1b84724..9b7c6ba 100644 --- a/pycrate_mobile/TS24519_TSNAF.py +++ b/pycrate_mobile/TS24519_TSNAF.py @@ -105,7 +105,7 @@ class EthPortParam(Envelope): _GEN = ( Uint16('Name', val=1, dic=EthPortParamName_dict), Uint16('Len'), - Buf('Value', val='', rep=REPR_HEX) + Buf('Value', val=b'', rep=REPR_HEX) ) def __init__(self, *args, **kwargs): @@ -253,7 +253,7 @@ class BridgeParam(Envelope): _GEN = ( Uint16('Name', val=1, dic=BridgeParamName_dict), Uint16('Len'), - Buf('Value', val='', rep=REPR_HEX) + Buf('Value', val=b'', rep=REPR_HEX) ) def __init__(self, *args, **kwargs): @@ -291,7 +291,7 @@ class BridgeMgmtList(Sequence): #------------------------------------------------------------------------------# class BridgeMgmtCap(Array): - _GEN = Uint16('ParamName', val=1, dic=BridgeParamName_dict), + _GEN = Uint16('ParamName', val=1, dic=BridgeParamName_dict) #------------------------------------------------------------------------------# @@ -359,7 +359,7 @@ class BridgeUpdRes(Envelope): class ManageEthPortCommand(Layer3E): _GEN = ( Uint8('Type', val=1, dic=TSNAFEthPortMsgType_dict), - Type6LVE('EthPortMgmtList', val={'V':b''}, IE=EthPortMgmtList() + Type6LVE('EthPortMgmtList', val={'V':b''}, IE=EthPortMgmtList()) )