changeset 2229:b3fca173d19c draft

Detect IPv6 address flags at interface discovery on Linux.
author Roy Marples <roy@marples.name>
date Sun, 19 Jan 2014 22:35:52 +0000
parents 4c295fa3c929
children 6f64cbf7fa50
files if-linux.c ipv6.c
diffstat 2 files changed, 34 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/if-linux.c	Sat Jan 18 15:17:37 2014 +0000
+++ b/if-linux.c	Sun Jan 19 22:35:52 2014 +0000
@@ -833,11 +833,40 @@
 }
 
 int
-in6_addr_flags(__unused const char *ifname,
-    __unused const struct in6_addr *addr)
+in6_addr_flags(const char *ifname, const struct in6_addr *addr)
 {
+	FILE *fp;
+	char *ent, address[33], name[IF_NAMESIZE + 1];
+	unsigned int ifindex;
+	int prefix, scope, flags, i, ret;
+	struct in6_addr addr6;
+	static const char *hex = "0123456789abcdef";
 
-	/* How do I get IPv6 address flags on Linux? */
-	return 0;
+	fp = fopen("/proc/net/if_inet6", "r");
+	if (fp == NULL)
+		return -1;
+	while ((ent = get_line(fp))) {
+		i = sscanf(ent, "%32[a-f0-9] %x %x %x %x %16s\n",
+		    address, &ifindex, &prefix, &scope, &flags, name);
+		if (i != 6 || strlen(address) != 32) {
+			fclose(fp);
+			errno = ENOTSUP;
+			return -1;
+		}
+		if (strcmp(ifname, name))
+			continue;
+		for (i = 0; i < 16; i++) {
+			addr6.s6_addr[i] =
+			    ((strchr(hex, address[i * 2]) - hex) << 4) |
+			    (strchr(hex, address[i * 2 + 1]) - hex);
+		}
+		if (IN6_ARE_ADDR_EQUAL(addr, &addr6)) {
+			fclose(fp);
+			return flags;
+		}
+	}
+	fclose(fp);
+	errno = ESRCH;
+	return -1;
 }
 #endif
--- a/ipv6.c	Sat Jan 18 15:17:37 2014 +0000
+++ b/ipv6.c	Sun Jan 19 22:35:52 2014 +0000
@@ -510,7 +510,7 @@
 
 	/* Safety, remove tentative addresses */
 	if (cmd == RTM_NEWADDR) {
-		if (flags & IN6_IFF_TENTATIVE)
+		if (flags & (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED))
 			cmd = RTM_DELADDR;
 #ifdef IN6_IFF_DETACHED
 		if (flags & IN6_IFF_DETACHED)