Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gtp: identify tunnel via GTP device + GTP version + TEID + family

This allows to define a GTP tunnel for dual stack MS/UE with both IPv4
and IPv6 addresses while using the same TEID via two PDP context
objects.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+63 -22
+63 -22
drivers/net/gtp.c
··· 141 141 } 142 142 143 143 /* Resolve a PDP context structure based on the 64bit TID. */ 144 - static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid) 144 + static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid, u16 family) 145 145 { 146 146 struct hlist_head *head; 147 147 struct pdp_ctx *pdp; ··· 149 149 head = &gtp->tid_hash[gtp0_hashfn(tid) % gtp->hash_size]; 150 150 151 151 hlist_for_each_entry_rcu(pdp, head, hlist_tid) { 152 - if (pdp->gtp_version == GTP_V0 && 152 + if (pdp->af == family && 153 + pdp->gtp_version == GTP_V0 && 153 154 pdp->u.v0.tid == tid) 154 155 return pdp; 155 156 } ··· 158 157 } 159 158 160 159 /* Resolve a PDP context structure based on the 32bit TEI. */ 161 - static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid) 160 + static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid, u16 family) 162 161 { 163 162 struct hlist_head *head; 164 163 struct pdp_ctx *pdp; ··· 166 165 head = &gtp->tid_hash[gtp1u_hashfn(tid) % gtp->hash_size]; 167 166 168 167 hlist_for_each_entry_rcu(pdp, head, hlist_tid) { 169 - if (pdp->gtp_version == GTP_V1 && 168 + if (pdp->af == family && 169 + pdp->gtp_version == GTP_V1 && 170 170 pdp->u.v1.i_tei == tid) 171 171 return pdp; 172 172 } ··· 307 305 } 308 306 309 307 static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, 310 - unsigned int hdrlen, unsigned int role) 308 + unsigned int hdrlen, unsigned int role, __u16 inner_proto) 311 309 { 312 - __u16 inner_proto; 313 - 314 - if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) { 315 - netdev_dbg(pctx->dev, "GTP packet does not encapsulate an IP packet\n"); 316 - return -1; 317 - } 318 - 319 310 if (!gtp_check_ms(skb, pctx, hdrlen, role, inner_proto)) { 320 311 netdev_dbg(pctx->dev, "No PDP ctx for this MS\n"); 321 312 return 1; ··· 557 562 msg, 0, GTP_GENL_MCGRP, GFP_ATOMIC); 558 563 } 559 564 565 + static int gtp_proto_to_family(__u16 proto) 566 + { 567 + switch (proto) { 568 + case ETH_P_IP: 569 + return AF_INET; 570 + case ETH_P_IPV6: 571 + return AF_INET6; 572 + default: 573 + WARN_ON_ONCE(1); 574 + break; 575 + } 576 + 577 + return AF_UNSPEC; 578 + } 579 + 560 580 /* 1 means pass up to the stack, -1 means drop and 0 means decapsulated. */ 561 581 static int gtp0_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) 562 582 { ··· 579 569 sizeof(struct gtp0_header); 580 570 struct gtp0_header *gtp0; 581 571 struct pdp_ctx *pctx; 572 + __u16 inner_proto; 582 573 583 574 if (!pskb_may_pull(skb, hdrlen)) 584 575 return -1; ··· 602 591 if (gtp0->type != GTP_TPDU) 603 592 return 1; 604 593 605 - pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid)); 594 + if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) { 595 + netdev_dbg(gtp->dev, "GTP packet does not encapsulate an IP packet\n"); 596 + return -1; 597 + } 598 + 599 + pctx = gtp0_pdp_find(gtp, be64_to_cpu(gtp0->tid), 600 + gtp_proto_to_family(inner_proto)); 606 601 if (!pctx) { 607 602 netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb); 608 603 return 1; 609 604 } 610 605 611 - return gtp_rx(pctx, skb, hdrlen, gtp->role); 606 + return gtp_rx(pctx, skb, hdrlen, gtp->role, inner_proto); 612 607 } 613 608 614 609 /* msg_type has to be GTP_ECHO_REQ or GTP_ECHO_RSP */ ··· 785 768 sizeof(struct gtp1_header); 786 769 struct gtp1_header *gtp1; 787 770 struct pdp_ctx *pctx; 771 + __u16 inner_proto; 788 772 789 773 if (!pskb_may_pull(skb, hdrlen)) 790 774 return -1; ··· 821 803 if (!pskb_may_pull(skb, hdrlen)) 822 804 return -1; 823 805 806 + if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) { 807 + netdev_dbg(gtp->dev, "GTP packet does not encapsulate an IP packet\n"); 808 + return -1; 809 + } 810 + 824 811 gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr)); 825 812 826 - pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid)); 813 + pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid), 814 + gtp_proto_to_family(inner_proto)); 827 815 if (!pctx) { 828 816 netdev_dbg(gtp->dev, "No PDP ctx to decap skb=%p\n", skb); 829 817 return 1; ··· 839 815 gtp_parse_exthdrs(skb, &hdrlen) < 0) 840 816 return -1; 841 817 842 - return gtp_rx(pctx, skb, hdrlen, gtp->role); 818 + return gtp_rx(pctx, skb, hdrlen, gtp->role, inner_proto); 843 819 } 844 820 845 821 static void __gtp_encap_destroy(struct sock *sk) ··· 1867 1843 found = true; 1868 1844 if (version == GTP_V0) 1869 1845 pctx_tid = gtp0_pdp_find(gtp, 1870 - nla_get_u64(info->attrs[GTPA_TID])); 1846 + nla_get_u64(info->attrs[GTPA_TID]), 1847 + family); 1871 1848 else if (version == GTP_V1) 1872 1849 pctx_tid = gtp1_pdp_find(gtp, 1873 - nla_get_u32(info->attrs[GTPA_I_TEI])); 1850 + nla_get_u32(info->attrs[GTPA_I_TEI]), 1851 + family); 1874 1852 if (pctx_tid) 1875 1853 found = true; 1876 1854 ··· 2060 2034 struct nlattr *nla[]) 2061 2035 { 2062 2036 struct gtp_dev *gtp; 2037 + int family; 2038 + 2039 + if (nla[GTPA_FAMILY]) 2040 + family = nla_get_u8(nla[GTPA_FAMILY]); 2041 + else 2042 + family = AF_INET; 2063 2043 2064 2044 gtp = gtp_find_dev(net, nla); 2065 2045 if (!gtp) ··· 2074 2042 if (nla[GTPA_MS_ADDRESS]) { 2075 2043 __be32 ip = nla_get_be32(nla[GTPA_MS_ADDRESS]); 2076 2044 2045 + if (family != AF_INET) 2046 + return ERR_PTR(-EINVAL); 2047 + 2077 2048 return ipv4_pdp_find(gtp, ip); 2078 2049 } else if (nla[GTPA_MS_ADDR6]) { 2079 2050 struct in6_addr addr = nla_get_in6_addr(nla[GTPA_MS_ADDR6]); 2051 + 2052 + if (family != AF_INET6) 2053 + return ERR_PTR(-EINVAL); 2080 2054 2081 2055 if (addr.s6_addr32[2] || 2082 2056 addr.s6_addr32[3]) ··· 2092 2054 } else if (nla[GTPA_VERSION]) { 2093 2055 u32 gtp_version = nla_get_u32(nla[GTPA_VERSION]); 2094 2056 2095 - if (gtp_version == GTP_V0 && nla[GTPA_TID]) 2096 - return gtp0_pdp_find(gtp, nla_get_u64(nla[GTPA_TID])); 2097 - else if (gtp_version == GTP_V1 && nla[GTPA_I_TEI]) 2098 - return gtp1_pdp_find(gtp, nla_get_u32(nla[GTPA_I_TEI])); 2057 + if (gtp_version == GTP_V0 && nla[GTPA_TID]) { 2058 + return gtp0_pdp_find(gtp, nla_get_u64(nla[GTPA_TID]), 2059 + family); 2060 + } else if (gtp_version == GTP_V1 && nla[GTPA_I_TEI]) { 2061 + return gtp1_pdp_find(gtp, nla_get_u32(nla[GTPA_I_TEI]), 2062 + family); 2063 + } 2099 2064 } 2100 2065 2101 2066 return ERR_PTR(-EINVAL);