]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gtp: parse extension headers before reading inner protocol
authorZhixing Chen <running910@gmail.com>
Wed, 8 Jul 2026 04:22:44 +0000 (12:22 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 21 Jul 2026 09:23:30 +0000 (11:23 +0200)
GTPv1-U packets may carry a chain of extension headers before the inner
IP packet. The receive path already parses and skips these extension
headers, but it currently reads the inner protocol before doing so.

As a result, the first extension header byte is interpreted as the inner
IP version. Packets with extension headers are then dropped before PDP
lookup.

Parse the extension header chain before calling gtp_inner_proto(), so the
inner protocol is read from the actual inner IP header.

Fixes: c75fc0b9e5be ("gtp: identify tunnel via GTP device + GTP version + TEID + family")
Signed-off-by: Zhixing Chen <running910@gmail.com>
Link: https://patch.msgid.link/20260708042244.120898-1-running910@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/gtp.c

index a60ef32b35b8255a17bed3fbc6ce19f26b3ba3a8..c0e38878af51b300aa4da9a41230d50731df8e24 100644 (file)
@@ -826,13 +826,17 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
        if (!pskb_may_pull(skb, hdrlen))
                return -1;
 
+       gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
+
+       if (gtp1->flags & GTP1_F_EXTHDR &&
+           gtp_parse_exthdrs(skb, &hdrlen) < 0)
+               return -1;
+
        if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) {
                netdev_dbg(gtp->dev, "GTP packet does not encapsulate an IP packet\n");
                return -1;
        }
 
-       gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr));
-
        pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid),
                             gtp_proto_to_family(inner_proto));
        if (!pctx) {
@@ -840,10 +844,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
                return 1;
        }
 
-       if (gtp1->flags & GTP1_F_EXTHDR &&
-           gtp_parse_exthdrs(skb, &hdrlen) < 0)
-               return -1;
-
        return gtp_rx(pctx, skb, hdrlen, gtp->role, inner_proto);
 }