diff mbox series

[net-next,v2,11/12] gtp: netlink update for ipv6

Message ID 20201211122612.869225-12-jonas@norrbonn.se
State New
Headers show
Series gtp: IPv6 support | expand

Commit Message

Jonas Bonn Dec. 11, 2020, 12:26 p.m. UTC
This patch adds the netlink changes required to support IPv6.

Signed-off-by: Jonas Bonn <jonas@norrbonn.se>
---
 drivers/net/gtp.c        | 84 ++++++++++++++++++++++++++++++----------
 include/uapi/linux/gtp.h |  2 +
 2 files changed, 65 insertions(+), 21 deletions(-)

Comments

Harald Welte Dec. 12, 2020, 11:25 a.m. UTC | #1
On Fri, Dec 11, 2020 at 01:26:11PM +0100, Jonas Bonn wrote:
> This patch adds the netlink changes required to support IPv6.


See my related comment to the other IPv6 patch in this series.

It is not legal to assume that v4/v6 are an either-or decision,
but it can be either v4-only, v6-only or v4 and v6 in the same PDP context.

For the "peer" (outer) address, I think it is correct to assume only either v4 or v6.

But for the inner "ms" address, it is not.

Regards,
	Harald

-- 
- Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)
diff mbox series

Patch

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)