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

Reply via email to