Subject: EUI64 patch for ifconfig.c
To: None <tech-net@netbsd.org>
From: None <ww@styx.org>
List: tech-net
Date: 06/13/2002 18:34:24
There has been some discussion on various lists recently
about making it possible to cause ifconfig to automatically
calculate the appropriate IPv6 address to use, given a 
prefix. I guess there are differing opinions about where
such functionality belongs. In any case, below is a patch
that makes it possible to do something like:

# ifconfig hme0 inet6 3ffe:1cdc:0:1234:: eui64

and have the lower 64 bits of the address filled in
for you.

Is the consensus that this is something useful and good,
or misguided and inappropriate?

Cheers,
-w

Index: ifconfig.c
===================================================================
RCS file: /cvs/NetBSD/basesrc/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.124
diff -u -r1.124 ifconfig.c
--- ifconfig.c	2002/05/23 21:38:01	1.124
+++ ifconfig.c	2002/06/13 22:21:08
@@ -181,6 +181,7 @@
 void	setia6pltime __P((const char *, int));
 void	setia6vltime __P((const char *, int));
 void	setia6lifetime __P((const char *, const char *));
+void	setia6eui64 __P((const char *, int));
 #endif
 void	checkatrange __P ((struct sockaddr_at *));
 void	setmedia __P((const char *, int));
@@ -261,6 +262,7 @@
 	{ "-deprecated", -IN6_IFF_DEPRECATED,	0,	setia6flags },
 	{ "pltime",	NEXTARG,	0,		setia6pltime },
 	{ "vltime",	NEXTARG,	0,		setia6vltime },
+	{ "eui64",	0,		0,		setia6eui64 },
 #endif /*INET6*/
 #ifndef INET_ONLY
 	{ "range",	NEXTARG,	0,		setatrange },
@@ -1213,6 +1215,44 @@
 		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
 	}
+}
+
+void
+setia6eui64(cmd, val)
+	const char *cmd;
+	int val;
+{
+	struct ifaddrs *ifap, *ifa;
+	const struct sockaddr_dl *sdl = NULL;
+	struct in6_addr *in6;
+
+	if (getifaddrs(&ifap) != 0)
+		err(EXIT_FAILURE, "getifaddrs");
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr->sa_family == AF_LINK) {
+			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
+			break;
+		}
+	}
+	if (!sdl)
+		err(EXIT_FAILURE, "could not determine link layer address"); 
+
+	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+
+	/* make EUI64 address */
+	if (sdl->sdl_alen == 8)
+		bcopy(LLADDR(sdl), &in6->s6_addr[8], 8);
+	else if (sdl->sdl_alen == 6) {
+		in6->s6_addr[8] = LLADDR(sdl)[0];
+		in6->s6_addr[9] = LLADDR(sdl)[1];
+		in6->s6_addr[10] = LLADDR(sdl)[2];
+		in6->s6_addr[11] = 0xff;
+		in6->s6_addr[12] = 0xfe;
+		in6->s6_addr[13] = LLADDR(sdl)[3];
+		in6->s6_addr[14] = LLADDR(sdl)[4];
+		in6->s6_addr[15] = LLADDR(sdl)[5];
+	} else
+		err(EXIT_FAILURE, "could not construct EUI64");
 }
 #endif