Skip to content

Commit e30ea48

Browse files
committed
gtp: support for IPv4-in-IPv6-GTP and IPv6-in-IPv4-GTP
Add new protocol field to PDP context that determines the transmit path IP protocol to encapsulate the original packets, either IPv4 or IPv6. Relax existing netlink attribute checks to allow to specify different family in MS and peer attributes from the control plane. Use build helpers to tx path to encapsulate IPv4-in-IPv6-GTP and IPv6-in-IPv4-GTP according to the user-specified configuration. From rx path, snoop for the inner protocol header since outer skb->protocol might differ and use this to validate for valid PDP context and to restore skb->protocol after decapsulation. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 045a7c1 commit e30ea48

File tree

1 file changed

+101
-28
lines changed

1 file changed

+101
-28
lines changed

drivers/net/gtp.c

Lines changed: 101 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,10 @@ static bool gtp_check_ms_ipv6(struct sk_buff *skb, struct pdp_ctx *pctx,
268268
* existing mobile subscriber.
269269
*/
270270
static bool gtp_check_ms(struct sk_buff *skb, struct pdp_ctx *pctx,
271-
unsigned int hdrlen, unsigned int role)
271+
unsigned int hdrlen, unsigned int role,
272+
__u16 inner_proto)
272273
{
273-
switch (ntohs(skb->protocol)) {
274+
switch (inner_proto) {
274275
case ETH_P_IP:
275276
return gtp_check_ms_ipv4(skb, pctx, hdrlen, role);
276277
case ETH_P_IPV6:
@@ -279,16 +280,47 @@ static bool gtp_check_ms(struct sk_buff *skb, struct pdp_ctx *pctx,
279280
return false;
280281
}
281282

283+
static int gtp_inner_proto(struct sk_buff *skb, unsigned int hdrlen,
284+
__u16 *inner_proto)
285+
{
286+
__u8 *ip_version, _ip_version;
287+
288+
ip_version = skb_header_pointer(skb, hdrlen, sizeof(*ip_version),
289+
&_ip_version);
290+
if (!ip_version)
291+
return -1;
292+
293+
switch (*ip_version & 0xf0) {
294+
case 0x40:
295+
*inner_proto = ETH_P_IP;
296+
break;
297+
case 0x60:
298+
*inner_proto = ETH_P_IPV6;
299+
break;
300+
default:
301+
return -1;
302+
}
303+
304+
return 0;
305+
}
306+
282307
static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb,
283-
unsigned int hdrlen, unsigned int role)
308+
unsigned int hdrlen, unsigned int role)
284309
{
285-
if (!gtp_check_ms(skb, pctx, hdrlen, role)) {
310+
__u16 inner_proto;
311+
312+
if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) {
313+
netdev_dbg(pctx->dev, "GTP packet does not encapsulate an IP packet\n");
314+
return -1;
315+
}
316+
317+
if (!gtp_check_ms(skb, pctx, hdrlen, role, inner_proto)) {
286318
netdev_dbg(pctx->dev, "No PDP ctx for this MS\n");
287319
return 1;
288320
}
289321

290322
/* Get rid of the GTP + UDP headers. */
291-
if (iptunnel_pull_header(skb, hdrlen, skb->protocol,
323+
if (iptunnel_pull_header(skb, hdrlen, htons(inner_proto),
292324
!net_eq(sock_net(pctx->sk), dev_net(pctx->dev)))) {
293325
pctx->dev->stats.rx_length_errors++;
294326
goto err;
@@ -1108,6 +1140,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
11081140
struct gtp_pktinfo *pktinfo)
11091141
{
11101142
struct gtp_dev *gtp = netdev_priv(dev);
1143+
struct net *net = gtp->net;
11111144
struct pdp_ctx *pctx;
11121145
struct iphdr *iph;
11131146
int ret;
@@ -1128,8 +1161,21 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev,
11281161
}
11291162
netdev_dbg(dev, "found PDP context %p\n", pctx);
11301163

1131-
ret = gtp_build_skb_outer_ip4(skb, dev, pktinfo, pctx,
1132-
iph->tos, iph->frag_off);
1164+
switch (pctx->sk->sk_family) {
1165+
case AF_INET:
1166+
ret = gtp_build_skb_outer_ip4(skb, dev, pktinfo, pctx,
1167+
iph->tos, iph->frag_off);
1168+
break;
1169+
case AF_INET6:
1170+
ret = gtp_build_skb_outer_ip6(net, skb, dev, pktinfo, pctx,
1171+
iph->tos);
1172+
break;
1173+
default:
1174+
ret = -1;
1175+
WARN_ON_ONCE(1);
1176+
break;
1177+
}
1178+
11331179
if (ret < 0)
11341180
return ret;
11351181

@@ -1167,7 +1213,19 @@ static int gtp_build_skb_ip6(struct sk_buff *skb, struct net_device *dev,
11671213

11681214
tos = ipv6_get_dsfield(ip6h);
11691215

1170-
ret = gtp_build_skb_outer_ip6(net, skb, dev, pktinfo, pctx, tos);
1216+
switch (pctx->sk->sk_family) {
1217+
case AF_INET:
1218+
ret = gtp_build_skb_outer_ip4(skb, dev, pktinfo, pctx, tos, 0);
1219+
break;
1220+
case AF_INET6:
1221+
ret = gtp_build_skb_outer_ip6(net, skb, dev, pktinfo, pctx, tos);
1222+
break;
1223+
default:
1224+
ret = -1;
1225+
WARN_ON_ONCE(1);
1226+
break;
1227+
}
1228+
11711229
if (ret < 0)
11721230
return ret;
11731231

@@ -1207,8 +1265,8 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
12071265
if (err < 0)
12081266
goto tx_err;
12091267

1210-
switch (proto) {
1211-
case ETH_P_IP:
1268+
switch (pktinfo.pctx->sk->sk_family) {
1269+
case AF_INET:
12121270
udp_tunnel_xmit_skb(pktinfo.rt, pktinfo.sk, skb,
12131271
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
12141272
pktinfo.tos,
@@ -1219,7 +1277,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
12191277
dev_net(dev)),
12201278
false);
12211279
break;
1222-
case ETH_P_IPV6:
1280+
case AF_INET6:
12231281
#if IS_ENABLED(CONFIG_IPV6)
12241282
udp_tunnel6_xmit_skb(&pktinfo.rt6->dst, pktinfo.sk, skb, dev,
12251283
&pktinfo.fl6.saddr, &pktinfo.fl6.daddr,
@@ -1695,18 +1753,27 @@ static void gtp_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
16951753
}
16961754
}
16971755

1756+
static void ip_pdp_peer_fill(struct pdp_ctx *pctx, struct genl_info *info)
1757+
{
1758+
if (info->attrs[GTPA_PEER_ADDRESS]) {
1759+
pctx->peer.addr.s_addr =
1760+
nla_get_be32(info->attrs[GTPA_PEER_ADDRESS]);
1761+
} else if (info->attrs[GTPA_PEER_ADDR6]) {
1762+
pctx->peer.addr6 = nla_get_in6_addr(info->attrs[GTPA_PEER_ADDR6]);
1763+
}
1764+
}
1765+
16981766
static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
16991767
{
1700-
pctx->peer.addr.s_addr =
1701-
nla_get_be32(info->attrs[GTPA_PEER_ADDRESS]);
1768+
ip_pdp_peer_fill(pctx, info);
17021769
pctx->ms.addr.s_addr =
17031770
nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
17041771
gtp_pdp_fill(pctx, info);
17051772
}
17061773

17071774
static bool ipv6_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info)
17081775
{
1709-
pctx->peer.addr6 = nla_get_in6_addr(info->attrs[GTPA_PEER_ADDR6]);
1776+
ip_pdp_peer_fill(pctx, info);
17101777
pctx->ms.addr6 = nla_get_in6_addr(info->attrs[GTPA_MS_ADDR6]);
17111778
if (pctx->ms.addr6.s6_addr32[2] ||
17121779
pctx->ms.addr6.s6_addr32[3])
@@ -1740,6 +1807,9 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
17401807
if (family == AF_INET6)
17411808
return ERR_PTR(-EAFNOSUPPORT);
17421809
#endif
1810+
if (!info->attrs[GTPA_PEER_ADDRESS] &&
1811+
!info->attrs[GTPA_PEER_ADDR6])
1812+
return ERR_PTR(-EINVAL);
17431813

17441814
if ((info->attrs[GTPA_PEER_ADDRESS] &&
17451815
sk->sk_family == AF_INET6) ||
@@ -1750,9 +1820,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
17501820
switch (family) {
17511821
case AF_INET:
17521822
if (!info->attrs[GTPA_MS_ADDRESS] ||
1753-
!info->attrs[GTPA_PEER_ADDRESS] ||
1754-
info->attrs[GTPA_MS_ADDR6] ||
1755-
info->attrs[GTPA_PEER_ADDR6])
1823+
info->attrs[GTPA_MS_ADDR6])
17561824
return ERR_PTR(-EINVAL);
17571825

17581826
ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]);
@@ -1761,9 +1829,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
17611829
break;
17621830
case AF_INET6:
17631831
if (!info->attrs[GTPA_MS_ADDR6] ||
1764-
!info->attrs[GTPA_PEER_ADDR6] ||
1765-
info->attrs[GTPA_MS_ADDRESS] ||
1766-
info->attrs[GTPA_PEER_ADDRESS])
1832+
info->attrs[GTPA_MS_ADDRESS])
17671833
return ERR_PTR(-EINVAL);
17681834

17691835
ms_addr6 = nla_get_in6_addr(info->attrs[GTPA_MS_ADDR6]);
@@ -1827,8 +1893,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
18271893

18281894
switch (pctx->af) {
18291895
case AF_INET:
1830-
if (!info->attrs[GTPA_MS_ADDRESS] ||
1831-
!info->attrs[GTPA_PEER_ADDRESS]) {
1896+
if (!info->attrs[GTPA_MS_ADDRESS]) {
18321897
sock_put(sk);
18331898
kfree(pctx);
18341899
return ERR_PTR(-EINVAL);
@@ -1837,8 +1902,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
18371902
ipv4_pdp_fill(pctx, info);
18381903
break;
18391904
case AF_INET6:
1840-
if (!info->attrs[GTPA_MS_ADDR6] ||
1841-
!info->attrs[GTPA_PEER_ADDR6]) {
1905+
if (!info->attrs[GTPA_MS_ADDR6]) {
18421906
sock_put(sk);
18431907
kfree(pctx);
18441908
return ERR_PTR(-EINVAL);
@@ -2062,13 +2126,22 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
20622126

20632127
switch (pctx->af) {
20642128
case AF_INET:
2065-
if (nla_put_be32(skb, GTPA_PEER_ADDRESS, pctx->peer.addr.s_addr) ||
2066-
nla_put_be32(skb, GTPA_MS_ADDRESS, pctx->ms.addr.s_addr))
2129+
if (nla_put_be32(skb, GTPA_MS_ADDRESS, pctx->ms.addr.s_addr))
2130+
goto nla_put_failure;
2131+
break;
2132+
case AF_INET6:
2133+
if (nla_put_in6_addr(skb, GTPA_MS_ADDR6, &pctx->ms.addr6))
2134+
goto nla_put_failure;
2135+
break;
2136+
}
2137+
2138+
switch (pctx->sk->sk_family) {
2139+
case AF_INET:
2140+
if (nla_put_be32(skb, GTPA_PEER_ADDRESS, pctx->peer.addr.s_addr))
20672141
goto nla_put_failure;
20682142
break;
20692143
case AF_INET6:
2070-
if (nla_put_in6_addr(skb, GTPA_PEER_ADDR6, &pctx->peer.addr6) ||
2071-
nla_put_in6_addr(skb, GTPA_MS_ADDR6, &pctx->ms.addr6))
2144+
if (nla_put_in6_addr(skb, GTPA_PEER_ADDR6, &pctx->peer.addr6))
20722145
goto nla_put_failure;
20732146
break;
20742147
}

0 commit comments

Comments
 (0)