Blob Blame History Raw
From c4b26bbcfeb6ca3deaa926c6f7921df83e9db06c Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Fri, 26 Sep 2014 23:19:43 +0200
Subject: [PATCH] link/inet6: add support for tokenized interface identifiers

http://tools.ietf.org/html/draft-chown-6man-tokenised-ipv6-identifiers-02

[thaller@redhat.com: Add OOM handling, fix whitespace issues]

https://github.com/thom311/libnl/pull/63

(cherry picked from b0d0d339cd69834bd05cb5c704fbf06677f754eb)

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 include/Makefile.am                |  1 +
 include/linux/if_link.h            |  1 +
 include/netlink/route/link/inet6.h | 31 +++++++++++++++++
 lib/route/link/inet6.c             | 70 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+)
 create mode 100644 include/netlink/route/link/inet6.h

diff --git a/include/Makefile.am b/include/Makefile.am
index 765cf5a..40ed84f 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -48,6 +48,7 @@ nobase_libnlinclude_HEADERS = \
 	netlink/route/link/bridge.h \
 	netlink/route/link/can.h \
 	netlink/route/link/inet.h \
+	netlink/route/link/inet6.h \
 	netlink/route/link/info-api.h \
 	netlink/route/link/macvlan.h \
 	netlink/route/link/vlan.h \
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 8b84939..bbe6991 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -196,6 +196,7 @@ enum {
 	IFLA_INET6_MCAST,	/* MC things. What of them?	*/
 	IFLA_INET6_CACHEINFO,	/* time values and max reasm size */
 	IFLA_INET6_ICMP6STATS,	/* statistics (icmpv6)		*/
+	IFLA_INET6_TOKEN,	/* device token			*/
 	__IFLA_INET6_MAX
 };
 
diff --git a/include/netlink/route/link/inet6.h b/include/netlink/route/link/inet6.h
new file mode 100644
index 0000000..71886d7
--- /dev/null
+++ b/include/netlink/route/link/inet6.h
@@ -0,0 +1,31 @@
+/*
+ * netlink/route/link/inet6.h	INET6 Link Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2014 Dan Williams <dcbw@redhat.com>
+ */
+
+#ifndef NETLINK_LINK_INET6_H_
+#define NETLINK_LINK_INET6_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int		rtnl_link_inet6_get_token(struct rtnl_link *,
+						  struct nl_addr **);
+
+extern int		rtnl_link_inet6_set_token(struct rtnl_link *,
+						  struct nl_addr *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c
index 6fa2741..eb4fa3f 100644
--- a/lib/route/link/inet6.c
+++ b/lib/route/link/inet6.c
@@ -20,6 +20,7 @@ struct inet6_data
 	uint32_t		i6_flags;
 	struct ifla_cacheinfo	i6_cacheinfo;
 	uint32_t		i6_conf[DEVCONF_MAX];
+	struct in6_addr		i6_token;
 };
 
 static void *inet6_alloc(struct rtnl_link *link)
@@ -48,6 +49,7 @@ static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
 	[IFLA_INET6_CONF]	= { .minlen = 4 },
 	[IFLA_INET6_STATS]	= { .minlen = 8 },
 	[IFLA_INET6_ICMP6STATS]	= { .minlen = 8 },
+	[IFLA_INET6_TOKEN]	= { .minlen = sizeof(struct in6_addr) },
 };
 
 static const uint8_t map_stat_id_from_IPSTATS_MIB_v1[__IPSTATS_MIB_MAX] = {
@@ -155,6 +157,10 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
 	if (tb[IFLA_INET6_CONF])
 		nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
 			   sizeof(i6->i6_conf));
+
+	if (tb[IFLA_INET6_TOKEN])
+		nla_memcpy(&i6->i6_token, tb[IFLA_INET6_TOKEN],
+			   sizeof(struct in6_addr));
  
 	/*
 	 * Due to 32bit data alignment, these addresses must be copied to an
@@ -264,6 +270,7 @@ static void inet6_dump_details(struct rtnl_link *link,
 				struct nl_dump_params *p, void *data)
 {
 	struct inet6_data *i6 = data;
+	struct nl_addr *addr;
 	char buf[64], buf2[64];
 	int i, n = 0;
 
@@ -281,6 +288,11 @@ static void inet6_dump_details(struct rtnl_link *link,
 	nl_dump(p, " retrans-time %s\n",
 		nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
 
+	addr = nl_addr_build(AF_INET6, &i6->i6_token, sizeof(i6->i6_token));
+	nl_dump(p, " token %s\n",
+		nl_addr2str(addr, buf, sizeof(buf)));
+	nl_addr_put(addr);
+
 	nl_dump_line(p, "      devconf:\n");
 	nl_dump_line(p, "      ");
 
@@ -473,6 +485,64 @@ static struct rtnl_link_af_ops inet6_ops = {
 	.ao_protinfo_policy		= &protinfo_policy,
 };
 
+/**
+ * Get IPv6 tokenized interface identifier
+ * @arg link		Link object
+ * @arg token		Tokenized interface identifier on success
+ *
+ * Returns the link's IPv6 tokenized interface identifier.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM	failure to allocate struct nl_addr result
+ * @return -NLE_NOATTR configuration setting not available
+ * @return -NLE_NOADDR tokenized interface identifier is not set
+ */
+int rtnl_link_inet6_get_token(struct rtnl_link *link, struct nl_addr **addr)
+{
+	struct inet6_data *id;
+
+	if (!(id = rtnl_link_af_data(link, &inet6_ops)))
+		return -NLE_NOATTR;
+
+	*addr = nl_addr_build(AF_INET6, &id->i6_token, sizeof(id->i6_token));
+	if (!*addr)
+		return -NLE_NOMEM;
+	if (nl_addr_iszero(*addr)) {
+		nl_addr_put(*addr);
+		*addr = NULL;
+		return -NLE_NOADDR;
+	}
+
+	return 0;
+}
+
+/**
+ * Set IPv6 tokenized interface identifier
+ * @arg link		Link object
+ * @arg token		Tokenized interface identifier
+ *
+ * Sets the link's IPv6 tokenized interface identifier.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM could not allocate inet6 data
+ * @return -NLE_INVAL addr is not a valid inet6 address
+ */
+int rtnl_link_inet6_set_token(struct rtnl_link *link, struct nl_addr *addr)
+{
+	struct inet6_data *id;
+
+	if ((nl_addr_get_family(addr) != AF_INET6) ||
+	    (nl_addr_get_len(addr) != sizeof(id->i6_token)))
+		return -NLE_INVAL;
+
+	if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
+		return -NLE_NOMEM;
+
+	memcpy(&id->i6_token, nl_addr_get_binary_addr(addr),
+	       sizeof(id->i6_token));
+	return 0;
+}
+
 static void __init inet6_init(void)
 {
 	rtnl_link_af_register(&inet6_ops);
-- 
1.9.3