[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1556579063-1367-9-git-send-email-tom@quantonium.net>
Date: Mon, 29 Apr 2019 16:04:23 -0700
From: Tom Herbert <tom@...bertland.com>
To: davem@...emloft.net, netdev@...r.kernel.org
Cc: Tom Herbert <tom@...ntonium.net>
Subject: [PATCH v8 net-next 8/8] ipv6tlvs: API for manipuateling TLVs on a connect socket
This patch provides an interface for adding a deleting
individual Hop-by-Hop or Destination Options on a socket.
The following IPv6 socket options are created:
IPV6_HOPOPTS_TLV
IPV6_RTHDRDSTOPTS_TLV
IPV6_DSTOPTS_TLV
IPV6_HOPOPTS_DEL_TLV
IPV6_RTHDRDSTOPTS_DEL_TLV
IPV6_DSTOPTS_DEL_TLV
The function txoptions_from_tlv_opt does the heavy lifting to
copy an options from userspace, validate the option, and call
insert of delete TLV function.
Signed-off-by: Tom Herbert <tom@...ntonium.net>
---
include/net/ipv6.h | 7 +++++
include/uapi/linux/in6.h | 9 ++++++
net/ipv6/exthdrs_common.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++
net/ipv6/ipv6_sockglue.c | 27 ++++++++++++++++++
4 files changed, 113 insertions(+)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index bf6e593f..6aa4d8f 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -529,6 +529,13 @@ struct ipv6_txoptions *txoptions_from_opt(struct sock *sk,
unsigned int max_len,
unsigned int max_cnt);
+struct ipv6_opt_hdr *txoptions_from_tlv_opt(struct sock *sk,
+ struct tlv_param_table
+ *tlv_param_table,
+ struct ipv6_txoptions *opt,
+ int optname, char __user *optval,
+ unsigned int optlen, int *which);
+
static inline bool ipv6_accept_ra(struct inet6_dev *idev)
{
/* If forwarding is enabled, RA are not accepted unless the special
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 1c79361..018fc6f 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -289,6 +289,15 @@ struct in6_flowlabel_req {
#define IPV6_RECVFRAGSIZE 77
#define IPV6_FREEBIND 78
+/* API to set single Destination or Hop-by-Hop options */
+
+#define IPV6_HOPOPTS_TLV 79
+#define IPV6_RTHDRDSTOPTS_TLV 80
+#define IPV6_DSTOPTS_TLV 81
+#define IPV6_HOPOPTS_DEL_TLV 82
+#define IPV6_RTHDRDSTOPTS_DEL_TLV 83
+#define IPV6_DSTOPTS_DEL_TLV 84
+
/*
* Multicast Routing:
* see include/uapi/linux/mroute6.h.
diff --git a/net/ipv6/exthdrs_common.c b/net/ipv6/exthdrs_common.c
index 8acff49..9e9ad85 100644
--- a/net/ipv6/exthdrs_common.c
+++ b/net/ipv6/exthdrs_common.c
@@ -1272,6 +1272,76 @@ struct ipv6_txoptions *txoptions_from_opt(struct sock *sk,
}
EXPORT_SYMBOL(txoptions_from_opt);
+struct ipv6_opt_hdr *txoptions_from_tlv_opt(struct sock *sk,
+ struct tlv_param_table
+ *tlv_param_table,
+ struct ipv6_txoptions *opt,
+ int optname, char __user *optval,
+ unsigned int optlen, int *whichp)
+{
+ struct ipv6_opt_hdr *old = NULL, *new = NULL;
+ struct net *net = sock_net(sk);
+ bool deleting = false;
+ void *new_opt = NULL;
+ int which = -1, retv;
+ bool admin;
+
+ new_opt = memdup_user(optval, optlen);
+ if (IS_ERR(new_opt))
+ return new_opt;
+
+ switch (optname) {
+ case IPV6_HOPOPTS_DEL_TLV:
+ deleting = true;
+ /* Fallthrough */
+ case IPV6_HOPOPTS_TLV:
+ if (opt)
+ old = opt->hopopt;
+ which = IPV6_HOPOPTS;
+ break;
+ case IPV6_RTHDRDSTOPTS_DEL_TLV:
+ deleting = true;
+ /* Fallthrough */
+ case IPV6_RTHDRDSTOPTS_TLV:
+ if (opt)
+ old = opt->dst0opt;
+ which = IPV6_RTHDRDSTOPTS;
+ break;
+ case IPV6_DSTOPTS_DEL_TLV:
+ deleting = true;
+ /* Fallthrough */
+ case IPV6_DSTOPTS_TLV:
+ if (opt)
+ old = opt->dst1opt;
+ which = IPV6_DSTOPTS;
+ break;
+ }
+
+ *whichp = which;
+
+ admin = ns_capable(net->user_ns, CAP_NET_RAW);
+
+ retv = ipv6_opt_validate_single_tlv(net, tlv_param_table, which,
+ new_opt, optlen, deleting, admin);
+ if (retv < 0)
+ return ERR_PTR(retv);
+
+ if (deleting) {
+ if (!old)
+ return NULL;
+ new = ipv6_opt_tlv_delete(net, tlv_param_table, old, new_opt,
+ admin);
+ } else {
+ new = ipv6_opt_tlv_insert(net, tlv_param_table, old, which,
+ new_opt, admin);
+ }
+
+ kfree(new_opt);
+
+ return new;
+}
+EXPORT_SYMBOL(txoptions_from_tlv_opt);
+
const struct nla_policy tlv_nl_policy[IPV6_TLV_ATTR_MAX + 1] = {
[IPV6_TLV_ATTR_TYPE] = { .type = NLA_U8, },
[IPV6_TLV_ATTR_ORDER] = { .type = NLA_U8, },
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index b8ef0ea..3e4c0eb 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -476,6 +476,33 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
break;
}
+ case IPV6_HOPOPTS_TLV:
+ case IPV6_RTHDRDSTOPTS_TLV:
+ case IPV6_DSTOPTS_TLV:
+ case IPV6_HOPOPTS_DEL_TLV:
+ case IPV6_RTHDRDSTOPTS_DEL_TLV:
+ case IPV6_DSTOPTS_DEL_TLV:
+ {
+ struct ipv6_txoptions *opt;
+ struct ipv6_opt_hdr *new;
+ int which;
+
+ opt = rcu_dereference_protected(np->opt,
+ lockdep_sock_is_held(sk));
+ new = txoptions_from_tlv_opt(sk, &ipv6_tlv_param_table, opt,
+ optname, optval, optlen, &which);
+ if (IS_ERR(new)) {
+ retv = PTR_ERR(new);
+ break;
+ }
+
+ retv = ipv6_opt_update(sk, opt, which, new);
+
+ kfree(new);
+
+ break;
+ }
+
case IPV6_PKTINFO:
{
struct in6_pktinfo pkt;
--
2.7.4
Powered by blists - more mailing lists