This patch adds the netlink changes required to support IPv6. Signed-off-by: Jonas Bonn <jo...@norrbonn.se> --- drivers/net/gtp.c | 84 ++++++++++++++++++++++++++++++---------- include/uapi/linux/gtp.h | 2 + 2 files changed, 65 insertions(+), 21 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 4c902bffefa3..40bbbe8cfad6 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1231,11 +1231,26 @@ static struct gtp_dev *gtp_find_dev(struct net *src_net, struct nlattr *nla[]) return gtp; } -static void ipv4_pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) +static void pdp_fill(struct pdp_ctx *pctx, struct genl_info *info) { pctx->gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]); - ipv4(&pctx->peer_addr) = nla_get_be32(info->attrs[GTPA_PEER_ADDRESS]); - ipv4(&pctx->ms_addr) = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]); + pctx->flags = 0; + + if (info->attrs[GTPA_PEER_IPV6]) { + pctx->flags |= PDP_F_PEER_V6; + pctx->peer_addr = nla_get_in6_addr(info->attrs[GTPA_PEER_IPV6]); + } else + ipv6_addr_set_v4mapped( + nla_get_be32(info->attrs[GTPA_PEER_ADDRESS]), + &pctx->peer_addr); + + if (info->attrs[GTPA_MS_IPV6]) { + pctx->flags |= PDP_F_MS_V6; + pctx->ms_addr = nla_get_in6_addr(info->attrs[GTPA_MS_IPV6]); + } else + ipv6_addr_set_v4mapped( + nla_get_be32(info->attrs[GTPA_MS_ADDRESS]), + &pctx->ms_addr); switch (pctx->gtp_version) { case GTP_V0: @@ -1263,13 +1278,20 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, u32 hash_ms, hash_tid = 0; unsigned int version; bool found = false; - __be32 ms_addr; - ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]); - hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size; + if (info->attrs[GTPA_MS_IPV6]) { + struct in6_addr ms_addr_v6; + ms_addr_v6 = nla_get_in6_addr(info->attrs[GTPA_MS_IPV6]); + hash_ms = ipv6_hashfn(&ms_addr_v6) % gtp->hash_size; + pctx = ipv6_pdp_find(gtp, &ms_addr_v6); + } else { + __be32 ms_addr; + ms_addr = nla_get_be32(info->attrs[GTPA_MS_ADDRESS]); + hash_ms = ipv4_hashfn(ms_addr) % gtp->hash_size; + pctx = ipv4_pdp_find(gtp, ms_addr); + } version = nla_get_u32(info->attrs[GTPA_VERSION]); - pctx = ipv4_pdp_find(gtp, ms_addr); if (pctx) found = true; if (version == GTP_V0) @@ -1292,7 +1314,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, if (!pctx) pctx = pctx_tid; - ipv4_pdp_fill(pctx, info); + pdp_fill(pctx, info); if (pctx->gtp_version == GTP_V0) netdev_dbg(dev, "GTPv0-U: update tunnel id = %llx (pdp %p)\n", @@ -1312,7 +1334,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, sock_hold(sk); pctx->sk = sk; pctx->dev = gtp->dev; - ipv4_pdp_fill(pctx, info); + pdp_fill(pctx, info); atomic_set(&pctx->tx_seq, 0); switch (pctx->gtp_version) { @@ -1334,14 +1356,14 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, switch (pctx->gtp_version) { case GTP_V0: - netdev_dbg(dev, "GTPv0-U: new PDP ctx id=%llx ssgn=%pI4 ms=%pI4 (pdp=%p)\n", - pctx->u.v0.tid, &ipv4(&pctx->peer_addr), - &ipv4(&pctx->ms_addr), pctx); + netdev_dbg(dev, "GTPv0-U: new PDP ctx id=%llx ssgn=%pI6 ms=%pI6 (pdp=%p)\n", + pctx->u.v0.tid, &pctx->peer_addr, + &pctx->ms_addr, pctx); break; case GTP_V1: - netdev_dbg(dev, "GTPv1-U: new PDP ctx id=%x/%x ssgn=%pI4 ms=%pI4 (pdp=%p)\n", + netdev_dbg(dev, "GTPv1-U: new PDP ctx id=%x/%x ssgn=%pI6 ms=%pI6 (pdp=%p)\n", pctx->u.v1.i_tei, pctx->u.v1.o_tei, - &ipv4(&pctx->peer_addr), &ipv4(&pctx->ms_addr), pctx); + &pctx->peer_addr, &pctx->ms_addr, pctx); break; } @@ -1374,9 +1396,13 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) int err; if (!info->attrs[GTPA_VERSION] || - !info->attrs[GTPA_LINK] || - !info->attrs[GTPA_PEER_ADDRESS] || - !info->attrs[GTPA_MS_ADDRESS]) + !info->attrs[GTPA_LINK]) + return -EINVAL; + + if (!info->attrs[GTPA_PEER_ADDRESS] == !info->attrs[GTPA_PEER_IPV6]) + return -EINVAL; + + if (!info->attrs[GTPA_MS_ADDRESS] == !info->attrs[GTPA_MS_IPV6]) return -EINVAL; version = nla_get_u32(info->attrs[GTPA_VERSION]); @@ -1439,7 +1465,11 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net, if (!gtp) return ERR_PTR(-ENODEV); - if (nla[GTPA_MS_ADDRESS]) { + if (nla[GTPA_MS_IPV6]) { + struct in6_addr ip = nla_get_in6_addr(nla[GTPA_MS_IPV6]); + + return ipv6_pdp_find(gtp, &ip); + } else if (nla[GTPA_MS_ADDRESS]) { __be32 ip = nla_get_be32(nla[GTPA_MS_ADDRESS]); return ipv4_pdp_find(gtp, ip); @@ -1522,9 +1552,19 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq, goto nlmsg_failure; if (nla_put_u32(skb, GTPA_VERSION, pctx->gtp_version) || - nla_put_u32(skb, GTPA_LINK, pctx->dev->ifindex) || - nla_put_be32(skb, GTPA_PEER_ADDRESS, ipv4(&pctx->peer_addr)) || - nla_put_be32(skb, GTPA_MS_ADDRESS, ipv4(&pctx->ms_addr))) + nla_put_u32(skb, GTPA_LINK, pctx->dev->ifindex)) + goto nla_put_failure; + + if ((pctx->flags & PDP_F_PEER_V6) && + nla_put_in6_addr(skb, GTPA_PEER_IPV6, &pctx->peer_addr)) + goto nla_put_failure; + else if (nla_put_be32(skb, GTPA_PEER_ADDRESS, ipv4(&pctx->peer_addr))) + goto nla_put_failure; + + if ((pctx->flags & PDP_F_MS_V6) && + nla_put_in6_addr(skb, GTPA_MS_IPV6, &pctx->ms_addr)) + goto nla_put_failure; + else if (nla_put_be32(skb, GTPA_MS_ADDRESS, ipv4(&pctx->ms_addr))) goto nla_put_failure; switch (pctx->gtp_version) { @@ -1660,6 +1700,8 @@ static const struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = { [GTPA_TID] = { .type = NLA_U64, }, [GTPA_PEER_ADDRESS] = { .type = NLA_U32, }, [GTPA_MS_ADDRESS] = { .type = NLA_U32, }, + [GTPA_PEER_IPV6] = { .len = sizeof(struct in6_addr), }, + [GTPA_MS_IPV6] = { .len = sizeof(struct in6_addr), }, [GTPA_FLOW] = { .type = NLA_U16, }, [GTPA_NET_NS_FD] = { .type = NLA_U32, }, [GTPA_I_TEI] = { .type = NLA_U32, }, diff --git a/include/uapi/linux/gtp.h b/include/uapi/linux/gtp.h index 79f9191bbb24..5fe0ca6a917e 100644 --- a/include/uapi/linux/gtp.h +++ b/include/uapi/linux/gtp.h @@ -30,6 +30,8 @@ enum gtp_attrs { GTPA_I_TEI, /* for GTPv1 only */ GTPA_O_TEI, /* for GTPv1 only */ GTPA_PAD, + GTPA_PEER_IPV6, + GTPA_MS_IPV6, __GTPA_MAX, }; #define GTPA_MAX (__GTPA_MAX + 1) -- 2.27.0