Skip to content
This repository was archived by the owner on Mar 8, 2024. It is now read-only.

Working with GTPC

p1-bmu edited this page Feb 1, 2022 · 5 revisions

How to encode and decode GTP-C signalling

module handling GTP-C

Only version 2 of the GTP-C protocol is supported currently (2022/02), as defined in the 3GPP specification TS 29.274. This is the protocol mostly used within 4G core networks to manage subscribers' sessions, between the MME, the S-GW and P-GW. More interfaces are also relying on GTPv2-C, this can be seen from the GTP-C Type dictionnary in the pycrate's source.

GTPv2-C and PFCP, a newer protocol defined in the 3GPP TS 29.244, are very similar in terms of message structure. Therefore, some constructs are shared between the GTPv2-C module and the PFCP one.

Basically, a GTPv2-C message is made of a header and a sequence of information elements; some are mandatory, others are optional. Each information element is structured in a Type-Length-Value fashion, with some subtleties: There is an additional Instance field after the length prefix, coded on 8 bits (with 4 spare ones), and the type can eventually be extended to 16 bits.

Decoding GTPv2-C messages

In order to decode GTPv2-C messages, the easiest is to use the main parsing function parse_GTPC(), which takes a buffer and returns a 2 tuple: the parsed message structure (or None if the parsing failed completely) and an error code (0 if everything went fine, or a code we would return as an error cause to a GTP-C endpoint).

In [1]: from pycrate_mobile.TS29274_GTPC import *                                                                                                        

In [2]: from binascii import * 

In [3]: buf  = unhexlify('482000ec0012345601e240000100080000010189674523f14c00050011223344554b000800112233445566778856000d001800f110123400f11009988770530
    ...: 0030000f1105200010006570009008612345678ac141e2847002300066d792d61706e08746573742d6d6e6f066d6e63303031066d6363303031046770727380000100016300010001
    ...: 4f00050001000000007f000100004800080000100000001000004e001a008080211001000010810600000000830600000000000d00000a005d002c004900010005570009028444554
    ...: 455ac5a5046500016007c090000000000000000000000000000000000000000')                                                                                

In [4]: Msg, Err = parse_GTPC(buf)                                                                                                                       

In [5]: Err # no error while decoding the buffer
Out[5]: 0

In [6]: print(Msg.show())                                                                                                                                
### CreateSessionRequest ###
 ### GTPCHdr ###
  <Version : 2>
  <P : 0>
  <T : 1>
  <MP : 0>
  <spare : 0>
  <Type : 32 (Create Session Request)>
  <Len : 236>
  <TEID : 0x00123456>
  <SeqNum : 123456>
  <spare : 0>
     ### CreateSessionRequestIEs ###
      ### IMSI ###
       ### GTPCIEHdr ###
        <Type : 1 (International Mobile Subscriber Identity (IMSI))>
        <Len : 8>
        <spare : 0>
        <Inst : 0>
           <IMSI : 001010987654321>
      ### MSISDN ###
       ### GTPCIEHdr ###
        <Type : 76 (MSISDN)>
        <Len : 5>
        <spare : 0>
        <Inst : 0>
           <MSISDN : 1122334455>
      ### MEI ###
       ### GTPCIEHdr ###
        <Type : 75 (Mobile Equipment Identity (MEI))>
        <Len : 8>
        <spare : 0>
        <Inst : 0>
           <MEI : 1122334455667788>
      ### ULI ###
       ### GTPCIEHdr ###
        <Type : 86 (User Location Information (ULI))>
        <Len : 13>
        <spare : 0>
        <Inst : 0>
           ### ULI ###
            ### Flags ###
             <ExtMacroENBID : 0>
             <MacroENBID : 0>
             <LAI : 0>
             <ECGI : 1>
             <TAI : 1>
             <RAI : 0>
             <SAI : 0>
             <CGI : 0>
            ### TAI ###
             <PLMN : 00101>
             <TAC : 0x1234>
            ### ECGI ###
             <PLMN : 00101>
             <spare : 0x0>
             <ECI : 0x9988770>
            <ext : 0x>
      ### ServingNetwork ###
       ### GTPCIEHdr ###
        <Type : 83 (Serving Network)>
        <Len : 3>
        <spare : 0>
        <Inst : 0>
           ### ServingNetwork ###
            <PLMN : 00101>
            <ext : 0x>
      ### RATType ###
       ### GTPCIEHdr ###
        <Type : 82 (RAT Type)>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### RATType ###
            <Val : 6 (EUTRAN (WB-E-UTRAN))>
            <ext : 0x>
      ### SenderFTEIDforControlPlane ###
       ### GTPCIEHdr ###
        <Type : 87 (Fully Qualified Tunnel Endpoint Identifier (F-TEID))>
        <Len : 9>
        <spare : 0>
        <Inst : 0>
           ### FTEID ###
            <V4 : 1>
            <V6 : 0>
            <IF : 6 (S5/S8 SGW GTP-C interface)>
            <TEID_GREKey : 0x12345678>
            <IPv4Addr : 0xac141e28>
            <ext : 0x>
      ### APN ###
       ### GTPCIEHdr ###
        <Type : 71 (Access Point Name (APN))>
        <Len : 35>
        <spare : 0>
        <Inst : 0>
           ### APN ###
            ### APNItem ###
             <Len : 6>
             <Value : b'my-apn'>
            ### APNItem ###
             <Len : 8>
             <Value : b'test-mno'>
            ### APNItem ###
             <Len : 6>
             <Value : b'mnc001'>
            ### APNItem ###
             <Len : 6>
             <Value : b'mcc001'>
            ### APNItem ###
             <Len : 4>
             <Value : b'gprs'>
      ### SelectionMode ###
       ### GTPCIEHdr ###
        <Type : 128 (Selection Mode)>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### SelectionMode ###
            <spare : 0>
            <Val : 1 (MS provided APN, subscription not verified)>
            <ext : 0x>
      ### PDNType ###
       ### GTPCIEHdr ###
        <Type : 99 (PDN Type)>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### PDNType ###
            <spare : 0>
            <Val : 1 (IPv4)>
      ### PAA ###
       ### GTPCIEHdr ###
        <Type : 79 (PDN Address Allocation (PAA))>
        <Len : 5>
        <spare : 0>
        <Inst : 0>
           ### PAA ###
            <spare : 0>
            <PDNType : 1 (IPv4)>
            <PDNAddress : 0x00000000>
      ### MaximumAPNRestriction ###
       ### GTPCIEHdr ###
        <Type : 127 (APN Restriction)>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### APNRestriction ###
            <Val : 0>
            <ext : 0x>
      ### AggregateMaximumBitRate ###
       ### GTPCIEHdr ###
        <Type : 72 (Aggregate Maximum Bit Rate (AMBR))>
        <Len : 8>
        <spare : 0>
        <Inst : 0>
           ### AMBR ###
            <APN-AMBR-UL : 1048576>
            <APN-AMBR-DL : 1048576>
      ### PCO ###
       ### GTPCIEHdr ###
        <Type : 78 (Protocol Configuration Options (PCO))>
        <Len : 26>
        <spare : 0>
        <Inst : 0>
           ### PCO ###
            <Ext : 1>
            <spare : 0>
            <Prot : 0 (PPP with IP PDP)>
            ### Config ###
             ### ProtConfigElt ###
              <ID : 32801 (IPCP)>
              <Len : 16>
              ### Cont ###
               <Code : 1 (Configure-Request)>
               <Id : 0>
               <Len : 16>
               ### Data ###
                ### NCPOpt ###
                 <Type : 129 (Primary DNS Server Address)>
                 <Len : 6>
                 <Data : 0x00000000>
                ### NCPOpt ###
                 <Type : 131 (Secondary DNS Server Address)>
                 <Len : 6>
                 <Data : 0x00000000>
             ### ProtConfigElt ###
              <ID : 13 (DNS server IPv4 address request)>
              <Len : 0>
              <Cont : 0x>
             ### ProtConfigElt ###
              <ID : 10 (IP address allocation via NAS signalling)>
              <Len : 0>
              <Cont : 0x>
      ### BearerContexttobecreated ###
       ### GTPCIEHdr ###
        <Type : 93>
        <Len : 44>
        <spare : 0>
        <Inst : 0>
       ### CreateSessionRequest_BearerContexttobecreated ###
        ### EPSBearerID ###
         ### GTPCIEHdr ###
          <Type : 73 (EPS Bearer ID (EBI))>
          <Len : 1>
          <spare : 0>
          <Inst : 0>
             ### EBI ###
              <spare : 0>
              <Val : 5>
              <ext : 0x>
        ### S5S8USGWFTEID ###
         ### GTPCIEHdr ###
          <Type : 87 (Fully Qualified Tunnel Endpoint Identifier (F-TEID))>
          <Len : 9>
          <spare : 0>
          <Inst : 2>
             ### FTEID ###
              <V4 : 1>
              <V6 : 0>
              <IF : 4 (S5/S8 SGW GTP-U interface)>
              <TEID_GREKey : 0x44554455>
              <IPv4Addr : 0xac5a5046>
              <ext : 0x>
        ### BearerLevelQoS ###
         ### GTPCIEHdr ###
          <Type : 80 (Bearer Level Quality of Service (Bearer QoS))>
          <Len : 22>
          <spare : 0>
          <Inst : 0>
             ### BearerQoS ###
              <spare : 0>
              <PCI : 1>
              <PL : 15>
              <spare : 0>
              <PVI : 0>
              <QCI : 9>
              <MaxBitRateUL : 0>
              <MaxBitRateDL : 0>
              <GuaranteedBitRateUL : 0>
              <GuaranteedBitRateDL : 0>
              <ext : 0x>

In [6]: print(Msg[0].show()) # show only the header                                                                                                           
### GTPCHdr ###
 <Version : 2>
 <P : 0>
 <T : 1>
 <MP : 0>
 <spare : 0>
 <Type : 32 (Create Session Request)>
 <Len : 236>
 <TEID : 0x00123456>
 <SeqNum : 123456>
 <spare : 0>

In [7]: for ie in Msg[1]: 
    ...:     print(ie.show()) # iterating over each IE 
    ...:                                                                                                                                                  
    ### IMSI ###
     ### GTPCIEHdr ###
      <Type : 1 (International Mobile Subscriber Identity (IMSI))>
      <Len : 8>
      <spare : 0>
      <Inst : 0>
         <IMSI : 001010987654321>
    ### MSISDN ###
     ### GTPCIEHdr ###
      <Type : 76 (MSISDN)>
      <Len : 5>
      <spare : 0>
      <Inst : 0>
         <MSISDN : 1122334455>
    [...]

In the GTPv2-C specification, some IEs are given as mandatory within a given message. This is however not always honored by some implementation. When trying to decode such a message, one will get an exception from pycrate e.g., PycrateErr: CreateSessionResponseIEs: missing mandatory IE(s), BearerContextcreated (or whatever IE is found missing). There is a simple mean to manage the check for mandatory IE, one only needs to configure the GTPCIEs class attribute as such:

In[29]: GTPCIEs.VERIF_MAND = False # to disable the check for mandatory IEs

In[30]: GTPCIEs.VERIF_MAND = True # to re-enable it

By doing so, one can eventually decode a GTPv2-C message that is not perfectly compliant to the 3GPP standard. Following is an example:

In [31]: buf = unhexlify('48210033098765430004c800020002005c0003000100074e001c0080c02305030000050080211004000010810600000000830600000000')                

In [32]: Msg, Err = parse_GTPC(buf)                                                                                                                       

In [33]: Err # we were unable to decode the buffer
Out[33]: 2

In [34]: Msg                                                                                                                                              

In [35]: GTPCIEs.VERIF_MAND = False # disabling the check for mandatory IEs

In [36]: Msg, Err = parse_GTPC(buf)                                                                                                                       

In [37]: Err # the decoding is OK this time
Out[37]: 0

In [38]: print(Msg.show())                                                                                                                                
### CreateSessionResponse ###
 ### GTPCHdr ###
  <Version : 2>
  <P : 0>
  <T : 1>
  <MP : 0>
  <spare : 0>
  <Type : 33 (Create Session Response)>
  <Len : 51>
  <TEID : 0x09876543>
  <SeqNum : 1224>
  <spare : 0>
     ### CreateSessionResponseIEs ###
      ### Cause ###
       ### GTPCIEHdr ###
        <Type : 2 (Cause)>
        <Len : 2>
        <spare : 0>
        <Inst : 0>
           ### Cause ###
            <Val : 92 (User authentication failed)>
            <spare : 0>
            <PCE : 0>
            <BCE : 0>
            <CS : 0>
            ### OffendingIE [transparent] ###
             <Type : 0>
             <Len : 0>
             <spare : 0>
             <Inst : 0>
      ### Recovery ###
       ### GTPCIEHdr ###
        <Type : 3 (Recovery (Restart Counter))>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           <Recovery : 7>
      ### PCO ###
       ### GTPCIEHdr ###
        <Type : 78 (Protocol Configuration Options (PCO))>
        <Len : 28>
        <spare : 0>
        <Inst : 0>
           ### PCO ###
            <Ext : 1>
            <spare : 0>
            <Prot : 0 (PPP with IP PDP)>
            ### Config ###
             ### ProtConfigElt ###
              <ID : 49187 (PAP)>
              <Len : 5>
              ### Cont ###
               <Code : 3 (Authenticate-Nak)>
               <Id : 0>
               <Len : 5>
               ### Data ###
                <MsgLen : 0>
                <Msg : b''>
             ### ProtConfigElt ###
              <ID : 32801 (IPCP)>
              <Len : 16>
              ### Cont ###
               <Code : 4 (Configure-Reject)>
               <Id : 0>
               <Len : 16>
               ### Data ###
                ### NCPOpt ###
                 <Type : 129 (Primary DNS Server Address)>
                 <Len : 6>
                 <Data : 0x00000000>
                ### NCPOpt ###
                 <Type : 131 (Secondary DNS Server Address)>
                 <Len : 6>
                 <Data : 0x00000000>

In [39]: GTPCIEs.VERIF_MAND = True # we restore the check for mandatory IEs

In [40]: Msg = CreateSessionResponse()                                                                                                                    

In [41]: Msg.from_bytes(buf) # Here we can see the exception raised by the decoding routine
---------------------------------------------------------------------------
PycrateErr                                Traceback (most recent call last)
<ipython-input-41-6d0e00014898> in <module>
----> 1 Msg.from_bytes(buf)

~/python/pycrate_core/elt.py in from_bytes(self, char)
    634                          .format(self._name, type(char).__name__)))
    635         #
--> 636         self._from_char(char)
    637 
    638     def to_bytes(self):

~/python/pycrate_mobile/TS29274_GTPC.py in _from_char(self, char)
   4028         char._lb = char._cur + 8 * len_ies
   4029         # decode all IEs
-> 4030         self[1]._from_char(char)
   4031         # restore original char length
   4032         char._len_bit = char_lb

~/python/pycrate_mobile/TS29274_GTPC.py in _from_char(self, char)
   3956                     self._ie_mand.remove(ie._name)
   3957             if self._ie_mand:
-> 3958                 raise(PycrateErr('{0}: missing mandatory IE(s), {1}'\
   3959                       .format(self._name, ', '.join(sorted(self._ie_mand)))))
   3960 

PycrateErr: CreateSessionResponseIEs: missing mandatory IE(s), BearerContextcreated

It is also possible to only decode the header by instantiating the GTPCHdr class, or a list of information elements with the GTPCIEs class. Beware however, that depending of the message type, some specific internal nested IE structures are locally defined for this specific message type, and will not be handled correctly by this generic GTPCIEs class. Finally, in case we want to manipulate a given GTPv2-C message, we can use one of the class from the GTPCDispatcher

Encoding GTPv2-C messages

GTPv2-C messages can be quite complex, and like with any of this type of protocols, we need to know exactly what to put in your message when crafting it. Some automation is carried by pycrate for length prefixes and few other parameters, but this is still required for the developper to know what values to put in almost many of the fields and information elements in the message.

When instantiating a GTPv2-C class, by default we only get the header set in the structure. We then need to set each IE one by one. Here is an example:

In [2]: from pycrate_mobile.TS29274_GTPC import *                                                                                                         

In [3]: Msg = CreateBearerRequest(val={'GTPCHdr': {'TEID': 0x12345, 'SeqNum': 12345}})

In [4]: print(Msg.show())                                                                                                                                 
### CreateBearerRequest ###
 ### GTPCHdr ###
  <Version : 2>
  <P : 0>
  <T : 1>
  <MP : 0>
  <spare : 0>
  <Type : 95 (Create Bearer Request)>
  <Len : 8>
  <TEID : 0x00012345>
  <SeqNum : 12345>
  <spare : 0>
     ### CreateBearerRequestIEs ###

From there, we can initialize all (and only) mandatory IEs with the init_ies() method. This is just a matter of filling them with appropriate value to get a compliant message.

In [5]: Msg[1].init_ies() # setting all mandatory IEs with dummy / default values                                                                                     

In [6]: print(Msg.show())                                                                                                                                   
### CreateBearerRequest ###
 ### GTPCHdr ###
  <Version : 2>
  <P : 0>
  <T : 1>
  <MP : 0>
  <spare : 0>
  <Type : 95 (Create Bearer Request)>
  <Len : 53>
  <TEID : 0x00012345>
  <SeqNum : 12345>
  <spare : 0>
     ### CreateBearerRequestIEs ###
      ### LinkedEPSBearerID ###
       ### GTPCIEHdr ###
        <Type : 73 (EPS Bearer ID (EBI))>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### EBI ###
            <spare : 0>
            <Val : 5>
            <ext : 0x>
      ### BearerContext ###
       ### GTPCIEHdr ###
        <Type : 93>
        <Len : 36>
        <spare : 0>
        <Inst : 0>
           ### CreateBearerRequest_BearerContext ###
            ### EPSBearerID ###
             ### GTPCIEHdr ###
              <Type : 73 (EPS Bearer ID (EBI))>
              <Len : 1>
              <spare : 0>
              <Inst : 0>
                 ### EBI ###
                  <spare : 0>
                  <Val : 5>
                  <ext : 0x>
            ### BearerLevelQoS ###
             ### GTPCIEHdr ###
              <Type : 80 (Bearer Level Quality of Service (Bearer QoS))>
              <Len : 22>
              <spare : 0>
              <Inst : 0>
                 ### BearerQoS ###
                  <spare : 0>
                  <PCI : 0>
                  <PL : 0>
                  <spare : 0>
                  <PVI : 0>
                  <QCI : 9>
                  <MaxBitRateUL : 10000>
                  <MaxBitRateDL : 10000>
                  <GuaranteedBitRateUL : 0>
                  <GuaranteedBitRateDL : 0>
                  <ext : 0x>
            ### TFT ###
             ### GTPCIEHdr ###
              <Type : 84 (EPS Bearer Level Traffic Flow Template (Bearer TFT))>
              <Len : 1>
              <spare : 0>
              <Inst : 0>
                 ### BearerTFT ###
                  <Opcode : 0 (Ignore this IE)>
                  <E : 0 (no parameters list)>
                  <NumPktFilters : 0>
                  ### PktFilters ###

In this example, there are 2 IEs that we can access by their index:

In [9]: Msg[1][0][1]                                                                                                                                        
Out[9]: <EBI : <spare : 0><Val : 5><ext : 0x>>

In [10]: Msg[1][1][1]                                                                                                                                       
Out[10]: <CreateBearerRequest_BearerContext : <EPSBearerID : <GTPCIEHdr : <Type : 73 (EPS Bearer ID (EBI))><Len : 1><spare : 0><Inst : 0><TypeExt [transparent] : 0>><EBI : <spare : 0><Val : 5><ext : 0x>>><BearerLevelQoS : <GTPCIEHdr : <Type : 80 (Bearer Level Quality of Service (Bearer QoS))><Len : 22><spare : 0><Inst : 0><TypeExt [transparent] : 0>><BearerQoS : <spare : 0><PCI : 0><PL : 0><spare : 0><PVI : 0><QCI : 9><MaxBitRateUL : 10000><MaxBitRateDL : 10000><GuaranteedBitRateUL : 0><GuaranteedBitRateDL : 0><ext : 0x>>><TFT : <GTPCIEHdr : <Type : 84 (EPS Bearer Level Traffic Flow Template (Bearer TFT))><Len : 1><spare : 0><Inst : 0><TypeExt [transparent] : 0>><BearerTFT : <Opcode : 0 (Ignore this IE)><E : 0 (no parameters list)><NumPktFilters : 0><PktFilterIds [transparent] : ><PktFilters : ><Parameters [transparent] : >>>>

As we have here GTPCIEs into GTPCIEs (also called Grouped IEs in the specification, or nested IEs), we can do the same enumeration for the content of the BearerContext IE:

In [15]: Msg[1][1][1][0][1]                                                                                                                                 
Out[15]: <EBI : <spare : 0><Val : 5><ext : 0x>>

In [16]: Msg[1][1][1][1][1]                                                                                                                                 
Out[16]: <BearerQoS : <spare : 0><PCI : 0><PL : 0><spare : 0><PVI : 0><QCI : 9><MaxBitRateUL : 10000><MaxBitRateDL : 10000><GuaranteedBitRateUL : 0><GuaranteedBitRateDL : 0><ext : 0x>>

In [17]: Msg[1][1][1][2][1]                                                                                                                                 
Out[17]: <BearerTFT : <Opcode : 0 (Ignore this IE)><E : 0 (no parameters list)><NumPktFilters : 0><PktFilterIds [transparent] : ><PktFilters : ><Parameters [transparent] : >>

And we can set each IE content by providing values according to each IE structure, e.g.:

In [23]: Msg[1][1][1][1][1].set_val({'PCI': 1, 'PL': 1, 'PVI': 1, 'QCI': 7, 'MaxBitRateUL': 100000, 'MaxBitRateDL': 100000})                                

In [24]: Msg[1][1][1][1][1]                                                                                                                                 
Out[24]: <BearerQoS : <spare : 0><PCI : 1><PL : 1><spare : 0><PVI : 1><QCI : 7><MaxBitRateUL : 100000><MaxBitRateDL : 100000><GuaranteedBitRateUL : 0><GuaranteedBitRateDL : 0><ext : 0x>>

If we want to set the infamous BearerTFT sub-IE, we need however to go through the related quite complex structure from the TS 24.008 specification.

One can also initialize all defined IEs for a given message type, including all optional ones, with wopt=True passed as argument. In this case, all optional IEs, including nested IEs are all set to default (or dummy) values. This way, we obtain something like the largest (or richest) possible GTPv2-C message, while still staying fully compliant to the specification.

In [27]: Msg[1].init_ies(wopt=True)                                                                                                                         

In [28]: print(Msg.show())                                                                                                                                  
### CreateBearerRequest ###
 ### GTPCHdr ###
  <Version : 2>
  <P : 0>
  <T : 1>
  <MP : 0>
  <spare : 0>
  <Type : 95 (Create Bearer Request)>
  <Len : 328>
  <TEID : 0x00000000>
  <SeqNum : 0>
  <spare : 0>
     ### CreateBearerRequestIEs ###
      ### LinkedEPSBearerID ###
       ### GTPCIEHdr ###
        <Type : 73 (EPS Bearer ID (EBI))>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### EBI ###
            <spare : 0>
            <Val : 5>
            <ext : 0x>
      ### BearerContext ###
       ### GTPCIEHdr ###
        <Type : 93>
        <Len : 142>
        <spare : 0>
        <Inst : 0>
           ### CreateBearerRequest_BearerContext ###
            ### EPSBearerID ###
             ### GTPCIEHdr ###
              <Type : 73 (EPS Bearer ID (EBI))>
              <Len : 1>
              <spare : 0>
              <Inst : 0>
                 ### EBI ###
                  <spare : 0>
                  <Val : 5>
                  <ext : 0x>
            [...]
            ### PGWSetFQDN ###
             ### GTPCIEHdr ###
              <Type : 215 (PGW Set FQDN)>
              <Len : 0>
              <spare : 0>
              <Inst : 0>
                 ### PGWSetFQDN ###
                  ### FQDN ###
                  <ext : 0x>

We can also add or remove individual IE one by one within a message, by using the add_ie() and rem_ie() methods, providing the IE type and optionally instance and value:

In [29]: print(Msg[1][-1][1].show())                                                                                                                      
        ### CreateBearerRequest_PGWChangeInfo ###
         ### AlternativePGWCSMFIPAddress ###
          ### GTPCIEHdr ###
           <Type : 74 (IP Address)>
           <Len : 0>
           <spare : 0>
           <Inst : 0>
              <IPAddress : 0x>
         ### NewPGWCSMFIPAddress ###
          ### GTPCIEHdr ###
           <Type : 74 (IP Address)>
           <Len : 0>
           <spare : 0>
           <Inst : 1>
              <IPAddress : 0x>
         ### PGWSetFQDN ###
          ### GTPCIEHdr ###
           <Type : 215 (PGW Set FQDN)>
           <Len : 0>
           <spare : 0>
           <Inst : 0>
              ### PGWSetFQDN ###
               ### FQDN ###
               <ext : 0x>

In [30]: Msg[1].rem_ie(214)                                                                                                                               

In [31]: print(Msg[1][-1][1].show())                                                                                                                      
        ### CreateBearerRequest_LoadControlInformation ###
         ### LoadMetric ###
          ### GTPCIEHdr ###
           <Type : 182 (Metric)>
           <Len : 1>
           <spare : 0>
           <Inst : 0>
              <Metric : 0>
         ### LoadControlSequenceNumber ###
          ### GTPCIEHdr ###
           <Type : 183 (Sequence Number)>
           <Len : 4>
           <spare : 0>
           <Inst : 0>
              <SequenceNumber : 0>
         ### ListofAPNAndRelativeCapacity ###
          ### GTPCIEHdr ###
           <Type : 184 (APN and Relative Capacity)>
           <Len : 2>
           <spare : 0>
           <Inst : 0>
              ### APNAndRelativeCapacity ###
               <RelativeCapacity : 0>
               <APNLen : 0>
               ### APN ###
               <ext : 0x>

In [32]: Msg[1][1][1].rem_ie(94) # removing the ChargingID IE nested in the BearerContext IE

Finally, this would not be complete if we always add to go through calling the presented methods for each IE. There is also the alternative way to set the complete message by passing all required values at instantiation. This requires however that the developper knows exactly the structure of each IE to set it properly.

In [34]: from socket import inet_aton 

In [35]: Msg = CreateBearerRequest(val={
    ...:     'GTPCHdr': {'TEID': 0x12345, 'SeqNum': 12345},
    ...:     'CreateBearerRequestIEs': [ 
    ...:       {'GTPCIEHdr': {'Type': 73}, 'EBI': {'Val': 12}}, 
    ...:       {'GTPCIEHdr': {'Type': 93}, 'CreateBearerRequest_BearerContext': [ 
    ...:           {'GTPCIEHdr': {'Type': 73}, 'EBI': {'Val': 12}}, 
    ...:           {'GTPCIEHdr': {'Type': 80}, 'BearerQoS': {'PCI': 1, 'PL': 1, 'PVI': 1, 'QCI': 7, 'MaxBitRateUL': 100000, 'MaxBitRateDL': 100000}}, 
    ...:           {'GTPCIEHdr': {'Type': 84}, 'BearerTFT': {'Opcode': 1}}]}, 
    ...:       {'GTPCIEHdr': {'Type': 87}, 'FTEID': {'V4': 1, 'IPv4Addr': inet_aton('10.11.12.13'), 'TEID_GREKey': 0x99887766}} 
    ...:       ]}) 
    ...:                                                                                                                                                  

In [36]: print(Msg.show())                                                                                                                                
### CreateBearerRequest ###
 ### GTPCHdr ###
  <Version : 2>
  <P : 0>
  <T : 1>
  <MP : 0>
  <spare : 0>
  <Type : 95 (Create Bearer Request)>
  <Len : 66>
  <TEID : 0x00012345>
  <SeqNum : 12345>
  <spare : 0>
     ### CreateBearerRequestIEs ###
      ### LinkedEPSBearerID ###
       ### GTPCIEHdr ###
        <Type : 73 (EPS Bearer ID (EBI))>
        <Len : 1>
        <spare : 0>
        <Inst : 0>
           ### EBI ###
            <spare : 0>
            <Val : 12>
            <ext : 0x>
      ### BearerContext ###
       ### GTPCIEHdr ###
        <Type : 93>
        <Len : 36>
        <spare : 0>
        <Inst : 0>
           ### CreateBearerRequest_BearerContext ###
            ### EPSBearerID ###
             ### GTPCIEHdr ###
              <Type : 73 (EPS Bearer ID (EBI))>
              <Len : 1>
              <spare : 0>
              <Inst : 0>
                 ### EBI ###
                  <spare : 0>
                  <Val : 12>
                  <ext : 0x>
            ### BearerLevelQoS ###
             ### GTPCIEHdr ###
              <Type : 80 (Bearer Level Quality of Service (Bearer QoS))>
              <Len : 22>
              <spare : 0>
              <Inst : 0>
                 ### BearerQoS ###
                  <spare : 0>
                  <PCI : 1>
                  <PL : 1>
                  <spare : 0>
                  <PVI : 1>
                  <QCI : 7>
                  <MaxBitRateUL : 100000>
                  <MaxBitRateDL : 100000>
                  <GuaranteedBitRateUL : 0>
                  <GuaranteedBitRateDL : 0>
                  <ext : 0x>
            ### TFT ###
             ### GTPCIEHdr ###
              <Type : 84 (EPS Bearer Level Traffic Flow Template (Bearer TFT))>
              <Len : 1>
              <spare : 0>
              <Inst : 0>
                 ### BearerTFT ###
                  <Opcode : 1 (Create new TFT)>
                  <E : 0 (no parameters list)>
                  <NumPktFilters : 0>
                  ### PktFilters ###
      ### GTPCIE ###
       ### GTPCIEHdr ###
        <Type : 87 (Fully Qualified Tunnel Endpoint Identifier (F-TEID))>
        <Len : 9>
        <spare : 0>
        <Inst : 0>
           ### FTEID ###
            <V4 : 1>
            <V6 : 0>
            <IF : 0 (S1-U eNodeB GTP-U interface)>
            <TEID_GREKey : 0x99887766>
            <IPv4Addr : 0x0a0b0c0d>
            <ext : 0x>

In [37]: Msg.hex()                                                                                                                                        
Out[37]: '485f00420001234500303900490001000c5d002400490001000c50001600450700000186a000000186a00000000000000000000054000100205700090080998877660a0b0c0d'

In [38]: Msg.to_bytes()                                                                                                                                   
Out[38]: b'H_\x00B\x00\x01#E\x0009\x00I\x00\x01\x00\x0c]\x00$\x00I\x00\x01\x00\x0cP\x00\x16\x00E\x07\x00\x00\x01\x86\xa0\x00\x00\x01\x86\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x01\x00 W\x00\t\x00\x80\x99\x88wf\n\x0b\x0c\r'

Now it is up to each developper to use this into an application, such as a S-GW or MME emulator, with all the appropriate subscriber's context management !

Clone this wiki locally