Skip to content

Commit dcd54d5

Browse files
GTP: update GTPPDUSessionContainer (#3130)
* gtp: fix GTPPDUSessionContainer layer implementation Signed-off-by: Raslan Darawsheh <rasland@nvidia.com> * Improve PR, add test Co-authored-by: gpotter2 <gabriel@potter.fr>
1 parent ecf2fac commit dcd54d5

2 files changed

Lines changed: 91 additions & 38 deletions

File tree

scapy/contrib/gtp.py

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,29 @@
1919
from __future__ import absolute_import
2020
import struct
2121

22-
2322
from scapy.compat import chb, orb, bytes_encode
2423
from scapy.config import conf
2524
from scapy.error import warning
26-
from scapy.fields import BitEnumField, BitField, ByteEnumField, ByteField, \
27-
ConditionalField, FieldLenField, FieldListField, FlagsField, IntField, \
28-
IPField, PacketListField, ShortField, StrFixedLenField, StrLenField, \
29-
XBitField, XByteField, XIntField
25+
from scapy.fields import (
26+
BitEnumField,
27+
BitField,
28+
ByteEnumField,
29+
ByteField,
30+
ConditionalField,
31+
FieldLenField,
32+
FieldListField,
33+
FlagsField,
34+
IPField,
35+
IntField,
36+
PacketListField,
37+
ShortField,
38+
StrFixedLenField,
39+
StrLenField,
40+
X3BytesField,
41+
XBitField,
42+
XByteField,
43+
XIntField,
44+
)
3045
from scapy.layers.inet import IP, UDP
3146
from scapy.layers.inet6 import IPv6, IP6Field
3247
from scapy.layers.ppp import PPP
@@ -313,56 +328,80 @@ def guess_payload_class(self, payload):
313328

314329

315330
class GTPPDUSessionContainer(Packet):
331+
# TS 38.415-g30 sect 5
316332
name = "GTP PDU Session Container"
333+
deprecated_fields = {
334+
"qmp": ("QMP", "2.4.5"),
335+
"P": ("PPP", "2.4.5"),
336+
"R": ("RQI", "2.4.5"),
337+
"extraPadding": ("padding", "2.4.5"),
338+
}
317339
fields_desc = [ByteField("ExtHdrLen", None),
318-
BitField("type", 0, 4),
319-
BitField("qmp", 0, 1),
340+
BitEnumField("type", 0, 4,
341+
{0: "DL PDU SESSION INFORMATION",
342+
1: "UL PDU SESSION INFORMATION"}),
343+
BitField("QMP", 0, 1),
344+
# UL (type 1)
320345
ConditionalField(BitField("dlDelayInd", 0, 1),
321346
lambda pkt: pkt.type == 1),
322347
ConditionalField(BitField("ulDelayInd", 0, 1),
323348
lambda pkt: pkt.type == 1),
324-
ConditionalField(BitField("spareUl1", 0, 1),
349+
# Common
350+
BitField("SNP", 0, 1),
351+
# UL (type 1)
352+
ConditionalField(BitField("N3N9DelayInd", 0, 1),
353+
lambda pkt: pkt.type == 1),
354+
ConditionalField(XBitField("spareUl1", 0, 1),
325355
lambda pkt: pkt.type == 1),
326-
ConditionalField(XBitField("spareDl1", 0, 3),
356+
# DL (type 0)
357+
ConditionalField(XBitField("spareDl1", 0, 2),
327358
lambda pkt: pkt.type == 0),
328-
ConditionalField(BitField("P", 0, 1),
359+
ConditionalField(BitField("PPP", 0, 1),
329360
lambda pkt: pkt.type == 0),
330-
ConditionalField(BitField("R", 0, 1),
361+
ConditionalField(BitField("RQI", 0, 1),
331362
lambda pkt: pkt.type == 0),
332-
ConditionalField(XBitField("spareUl2", 0, 2),
333-
lambda pkt: pkt.type == 1),
334-
BitField("QFI", 0, 6),
363+
# Common
364+
BitField("QFI", 0, 6), # QoS Flow Identifier
365+
# DL (type 0)
335366
ConditionalField(XBitField("PPI", 0, 3),
336367
lambda pkt: pkt.type == 0 and
337-
pkt.P == 1),
368+
pkt.PPP == 1),
338369
ConditionalField(XBitField("spareDl2", 0, 5),
339370
lambda pkt: pkt.type == 0 and
340-
pkt.P == 1),
341-
ConditionalField(XBitField("dlSendTime", 0, 32),
371+
pkt.PPP == 1),
372+
ConditionalField(XBitField("dlSendTime", 0, 64),
373+
lambda pkt: pkt.type == 0 and
374+
pkt.QMP == 1),
375+
ConditionalField(X3BytesField("dlQFISeqNum", 0),
342376
lambda pkt: pkt.type == 0 and
343-
pkt.qmp == 1),
344-
ConditionalField(XBitField("dlSendTimeRpt", 0, 32),
377+
pkt.SNP == 1),
378+
# UL (type 1)
379+
ConditionalField(XBitField("dlSendTimeRpt", 0, 64),
345380
lambda pkt: pkt.type == 1 and
346-
pkt.qmp == 1),
347-
ConditionalField(XBitField("dlRecvTime", 0, 32),
381+
pkt.QMP == 1),
382+
ConditionalField(XBitField("dlRecvTime", 0, 64),
348383
lambda pkt: pkt.type == 1 and
349-
pkt.qmp == 1),
350-
ConditionalField(XBitField("ulSendTime", 0, 32),
384+
pkt.QMP == 1),
385+
ConditionalField(XBitField("ulSendTime", 0, 64),
351386
lambda pkt: pkt.type == 1 and
352-
pkt.qmp == 1),
387+
pkt.QMP == 1),
353388
ConditionalField(XBitField("dlDelayRslt", 0, 32),
354389
lambda pkt: pkt.type == 1 and
355390
pkt.dlDelayInd == 1),
356391
ConditionalField(XBitField("ulDelayRslt", 0, 32),
357392
lambda pkt: pkt.type == 1 and
358393
pkt.ulDelayInd == 1),
394+
ConditionalField(XBitField("UlQFISeqNum", 0, 24),
395+
lambda pkt: pkt.type == 1 and
396+
pkt.SNP == 1),
397+
ConditionalField(XBitField("N3N9DelayRslt", 0, 32),
398+
lambda pkt: pkt.type == 1 and
399+
pkt.N3N9DelayInd == 1),
400+
# Common
359401
ByteEnumField("NextExtHdr", 0, ExtensionHeadersTypes),
360-
ConditionalField(StrLenField(
361-
"extraPadding",
362-
"",
363-
length_from=lambda pkt: 4 * (pkt.ExtHdrLen) - 5),
364-
lambda pkt:pkt.ExtHdrLen and pkt.ExtHdrLen > 1 and
365-
pkt.type == 0 and pkt.P == 1 and pkt.NextExtHdr == 0)]
402+
ConditionalField(
403+
StrLenField("padding", b"", length_from=lambda p: 0),
404+
lambda pkt: pkt.NextExtHdr == 0)]
366405

367406
def guess_payload_class(self, payload):
368407
if self.NextExtHdr == 0:
@@ -375,15 +414,24 @@ def guess_payload_class(self, payload):
375414
return PPP
376415
return GTPHeader.guess_payload_class(self, payload)
377416

417+
def post_dissect(self, s):
418+
if self.NextExtHdr == 0:
419+
# Padding is handled in this layer
420+
length = len(self.original) - len(s)
421+
pad_length = (- length) % 4
422+
self.padding = s[:pad_length]
423+
return s[pad_length:]
424+
return s
425+
378426
def post_build(self, p, pay):
379-
p += pay
427+
# Length
428+
if self.NextExtHdr == 0:
429+
p += b"\x00" * ((-len(p)) % 4)
430+
else:
431+
pay += b"\x00" * ((-len(p + pay)) % 4)
380432
if self.ExtHdrLen is None:
381-
if self.P == 1:
382-
hdr_len = 2
383-
else:
384-
hdr_len = 1
385-
p = struct.pack("!B", hdr_len) + p[1:]
386-
return p
433+
p = struct.pack("!B", len(p) // 4) + p[1:]
434+
return p + pay
387435

388436

389437
class GTPEchoRequest(Packet):

test/contrib/gtp.uts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,12 @@ assert isinstance(a[GTP_U_Header].payload, PPP)
5555
= GTPPDUSessionContainer(), dissect
5656
h = 'fa163ed6de7bfa163ed82b9408004500008400000000fe114b560a0a2e010a0a2efe086808680070000034ff006000000001fa163e850200ff800000000045000054074d00004001fb490a0a31fe0a0a32010000325600930001c444ca5f00000000759e0a0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'
5757
gtp = Ether(hex_bytes(h))
58-
gtp[GTP_U_Header].ExtHdrLen == 2 and gtp[GTP_U_Header].extraPadding == b'\x00\x00\x00' and gtp[GTP_U_Header][IP].src == '10.10.49.254' and gtp[GTP_U_Header][IP][ICMP].type == 0 and gtp[GTP_U_Header].type == 0 and gtp[GTP_U_Header].qmp == 0 and gtp[GTP_U_Header].P == 1 and gtp[GTP_U_Header].R == 1 and gtp[GTP_U_Header].QFI == 63 and gtp[GTP_U_Header].PPI == 4
58+
gtp[GTP_U_Header].ExtHdrLen == 2 and gtp[GTP_U_Header].padding == b'\x00\x00\x00' and gtp[GTP_U_Header][IP].src == '10.10.49.254' and gtp[GTP_U_Header][IP][ICMP].type == 0 and gtp[GTP_U_Header].type == 0 and gtp[GTP_U_Header].qmp == 0 and gtp[GTP_U_Header].P == 1 and gtp[GTP_U_Header].R == 1 and gtp[GTP_U_Header].QFI == 63 and gtp[GTP_U_Header].PPI == 4
59+
60+
= GTPPDUSessionContainer with padding
61+
data = b'\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x08\x00E\x00\x00^\x00\x01\x00\x00@\x11|\x8c\x7f\x00\x00\x01\x7f\x00\x00\x01\x08h\x08h\x00J\xed^4\xff\x00:\x00\x00\x00\x00\x00\x00\x00\x85\x04\x08\xbf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00&\x00\x01\x00\x00@\x11|\xc4\x7f\x00\x00\x01\x7f\x00\x00\x01\x005\x005\x00\x12\x01^ffffffffff000'
62+
gtp = Ether(data)
63+
assert IP in gtp
5964

6065
= GTPEchoResponse matches GTPEchoRequest by seq
6166
req = GTPHeader(seq=12345)/GTPEchoRequest()

0 commit comments

Comments
 (0)