DragonFly BSD
DragonFly submit List (threaded) for 2005-11
[Date Prev][Date Next]  [Thread Prev][Thread Next]  [Date Index][Thread Index]

802.11 patch


From: "Andrew Atrens" <atrens@xxxxxxxxxx>
Date: Thu, 24 Nov 2005 13:01:36 -0500


brings in new 802.11 stack from FreeBSD-current



diff -N -u -r src.preview/sbin/ifconfig/Makefile src/sbin/ifconfig/Makefile
--- src.preview/sbin/ifconfig/Makefile	2005-03-03 21:29:19.000000000 -0500
+++ src/sbin/ifconfig/Makefile	2005-09-27 15:02:10.000000000 -0400
@@ -1,25 +1,31 @@
 #	From: @(#)Makefile	8.1 (Berkeley) 6/5/93
-# $FreeBSD: src/sbin/ifconfig/Makefile,v 1.14.2.7 2002/02/15 03:58:37 luigi Exp $
-# $DragonFly: src/sbin/ifconfig/Makefile,v 1.3 2005/03/04 02:29:19 cpressey Exp $
+# $FreeBSD$
 
 PROG=	ifconfig
 WARNS?=	6
-SRCS=	ifconfig.c
-
-#comment out to exclude SIOC[GS]IFMEDIA support
-SRCS+=	ifmedia.c
-CFLAGS+=-DUSE_IF_MEDIA
-CFLAGS+=-DINET6
-
-#comment out to exclude SIOC[GS]ETVLAN support
-SRCS+=	ifvlan.c
-CFLAGS+=-DUSE_VLANS
-
-#comment out to exclude SIOC[GS]IEEE80211 support
-SRCS+=	ifieee80211.c
-CFLAGS+=-DUSE_IEEE80211
+SRCS=	ifconfig.c		# base support
 
 MAN=	ifconfig.8
+#
+# NB: The order here defines the order in which the constructors
+#     are called.  This in turn defines the default order in which
+#     status is displayed.  Probably should add a priority mechanism
+#     to the registration process so we don't depend on this aspect
+#     of the toolchain.
+#
+SRCS+=	af_link.c		# LLC support
+SRCS+=	af_inet.c		# IPv4 support
+SRCS+=	af_inet6.c		# IPv6 support
+SRCS+=	af_atalk.c		# AppleTalk support
+
+SRCS+=	ifclone.c		# clone device support
+# SRCS+=	ifmac.c			# MAC support
+SRCS+=	ifmedia.c		# SIOC[GS]IFMEDIA support
+SRCS+=	ifvlan.c		# SIOC[GS]ETVLAN support
+SRCS+=	ifieee80211.c		# SIOC[GS]IEEE80211 support
+
+#SRCS+=	ifcarp.c		# SIOC[GS]VH support
+#SRCS+=	ifpfsync.c		# pfsync(4) support
 
 .if defined(RELEASE_CRUNCH)
 CFLAGS+=-DNO_IPX
diff -N -u -r src.preview/sbin/ifconfig/af_atalk.c src/sbin/ifconfig/af_atalk.c
--- src.preview/sbin/ifconfig/af_atalk.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_atalk.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>		/* for RTX_IFA */
+
+#include <netatalk/at.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include "ifconfig.h"
+
+static struct netrange at_nr;		/* AppleTalk net range */
+static struct ifaliasreq at_addreq;
+
+/* XXX  FIXME -- should use strtoul for better parsing. */
+static void
+setatrange(const char *range, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	u_int	first = 123, last = 123;
+
+	if (sscanf(range, "%u-%u", &first, &last) != 2
+	    || first == 0 || first > 0xffff
+	    || last == 0 || last > 0xffff || first > last)
+		errx(1, "%s: illegal net range: %u-%u", range, first, last);
+	at_nr.nr_firstnet = htons(first);
+	at_nr.nr_lastnet = htons(last);
+}
+
+static void
+setatphase(const char *phase, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	if (!strcmp(phase, "1"))
+		at_nr.nr_phase = 1;
+	else if (!strcmp(phase, "2"))
+		at_nr.nr_phase = 2;
+	else
+		errx(1, "%s: illegal phase", phase);
+}
+
+static void
+at_status(int s __unused, const struct rt_addrinfo * info)
+{
+	struct sockaddr_at *sat, null_sat;
+	struct netrange *nr;
+
+	memset(&null_sat, 0, sizeof(null_sat));
+
+	sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
+	if (sat == NULL)
+		return;
+	nr = &sat->sat_range.r_netrange;
+	printf("\tatalk %d.%d range %d-%d phase %d",
+		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
+		ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
+	if (flags & IFF_POINTOPOINT) {
+		/* note RTAX_BRD overlap with IFF_BROADCAST */
+		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
+		if (!sat)
+			sat = &null_sat;
+		printf("--> %d.%d",
+			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
+	}
+	if (flags & IFF_BROADCAST) {
+		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
+		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
+		if (sat)
+			printf(" broadcast %d.%d",
+				ntohs(sat->sat_addr.s_net),
+				sat->sat_addr.s_node);
+	}
+
+	putchar('\n');
+}
+
+static void
+at_getaddr(const char *addr, int which)
+{
+	struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
+	u_int net, node;
+
+	sat->sat_family = AF_APPLETALK;
+	sat->sat_len = sizeof(*sat);
+	if (which == MASK)
+		errx(1, "AppleTalk does not use netmasks");
+	if (sscanf(addr, "%u.%u", &net, &node) != 2
+	    || net > 0xffff || node > 0xfe)
+		errx(1, "%s: illegal address", addr);
+	sat->sat_addr.s_net = htons(net);
+	sat->sat_addr.s_node = node;
+}
+
+static void
+at_postproc(int s, const struct afswtch *afp)
+{
+	struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
+
+	if (at_nr.nr_phase == 0)
+		at_nr.nr_phase = 2;	/* Default phase 2 */
+	if (at_nr.nr_firstnet == 0)
+		at_nr.nr_firstnet =	/* Default range of one */
+		at_nr.nr_lastnet = sat->sat_addr.s_net;
+	printf("\tatalk %d.%d range %d-%d phase %d\n",
+		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
+		ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet),
+		at_nr.nr_phase);
+	if ((u_short) ntohs(at_nr.nr_firstnet) >
+			(u_short) ntohs(sat->sat_addr.s_net)
+		    || (u_short) ntohs(at_nr.nr_lastnet) <
+			(u_short) ntohs(sat->sat_addr.s_net))
+		errx(1, "AppleTalk address is not in range");
+	sat->sat_range.r_netrange = at_nr;
+}
+
+static struct cmd atalk_cmds[] = {
+	DEF_CMD_ARG("range",	setatrange),
+	DEF_CMD_ARG("phase",	setatphase),
+};
+
+static struct afswtch af_atalk = {
+	.af_name	= "atalk",
+	.af_af		= AF_APPLETALK,
+	.af_status	= at_status,
+	.af_getaddr	= at_getaddr,
+	.af_postproc	= at_postproc,
+	.af_difaddr	= SIOCDIFADDR,
+	.af_aifaddr	= SIOCAIFADDR,
+	.af_ridreq	= &at_addreq,
+	.af_addreq	= &at_addreq,
+};
+
+static __constructor void
+atalk_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(atalk_cmds);  i++)
+		cmd_register(&atalk_cmds[i]);
+	af_register(&af_atalk);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/af_inet.c src/sbin/ifconfig/af_inet.c
--- src.preview/sbin/ifconfig/af_inet.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_inet.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>		/* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h>		/* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq in_addreq;
+static struct ifreq in_ridreq;
+
+static void
+in_status(int s __unused, const struct rt_addrinfo * info)
+{
+	struct sockaddr_in *sin, null_sin;
+	
+	memset(&null_sin, 0, sizeof(null_sin));
+
+	sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
+	if (sin == NULL)
+		return;
+
+	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+
+	if (flags & IFF_POINTOPOINT) {
+		/* note RTAX_BRD overlap with IFF_BROADCAST */
+		sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
+		if (!sin)
+			sin = &null_sin;
+		printf("--> %s ", inet_ntoa(sin->sin_addr));
+	}
+
+	sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
+	if (!sin)
+		sin = &null_sin;
+	printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+
+	if (flags & IFF_BROADCAST) {
+		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
+		sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
+		if (sin && sin->sin_addr.s_addr != 0)
+			printf("broadcast %s", inet_ntoa(sin->sin_addr));
+	}
+	putchar('\n');
+}
+
+#define SIN(x) ((struct sockaddr_in *) &(x))
+static struct sockaddr_in *sintab[] = {
+	SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
+	SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
+};
+
+static void
+in_getaddr(const char *s, int which)
+{
+#define	MIN(a,b)	((a)<(b)?(a):(b))
+	struct sockaddr_in *sin = sintab[which];
+	struct hostent *hp;
+	struct netent *np;
+
+	sin->sin_len = sizeof(*sin);
+	if (which != MASK)
+		sin->sin_family = AF_INET;
+
+	if (which == ADDR) {
+		char *p = NULL;
+
+		if((p = strrchr(s, '/')) != NULL) {
+			/* address is `name/masklen' */
+			int masklen;
+			int ret;
+			struct sockaddr_in *min = sintab[MASK];
+			*p = '\0';
+			ret = sscanf(p+1, "%u", &masklen);
+			if(ret != 1 || (masklen < 0 || masklen > 32)) {
+				*p = '/';
+				errx(1, "%s: bad value", s);
+			}
+			min->sin_len = sizeof(*min);
+			min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 
+				              0xffffffff);
+		}
+	}
+
+	if (inet_aton(s, &sin->sin_addr))
+		return;
+	if ((hp = gethostbyname(s)) != 0)
+		bcopy(hp->h_addr, (char *)&sin->sin_addr, 
+		    MIN(hp->h_length, sizeof(sin->sin_addr)));
+	else if ((np = getnetbyname(s)) != 0)
+		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
+	else
+		errx(1, "%s: bad value", s);
+#undef MIN
+}
+
+static void
+in_status_tunnel(int s)
+{
+	char src[NI_MAXHOST];
+	char dst[NI_MAXHOST];
+	struct ifreq ifr;
+	const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+	if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
+		return;
+	if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
+		src[0] = '\0';
+
+	if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
+		return;
+	if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
+		dst[0] = '\0';
+
+	printf("\ttunnel inet %s --> %s\n", src, dst);
+}
+
+static void
+in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+	struct ifaliasreq addreq;
+
+	memset(&addreq, 0, sizeof(addreq));
+	strncpy(addreq.ifra_name, name, IFNAMSIZ);
+	memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+	memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
+
+	if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
+		warn("SIOCSIFPHYADDR");
+}
+
+static struct afswtch af_inet = {
+	.af_name	= "inet",
+	.af_af		= AF_INET,
+	.af_status	= in_status,
+	.af_getaddr	= in_getaddr,
+	.af_status_tunnel = in_status_tunnel,
+	.af_settunnel	= in_set_tunnel,
+	.af_difaddr	= SIOCDIFADDR,
+	.af_aifaddr	= SIOCAIFADDR,
+	.af_ridreq	= &in_ridreq,
+	.af_addreq	= &in_addreq,
+};
+
+static __constructor void
+inet_ctor(void)
+{
+	af_register(&af_inet);
+}
diff -N -u -r src.preview/sbin/ifconfig/af_inet6.c src/sbin/ifconfig/af_inet6.c
--- src.preview/sbin/ifconfig/af_inet6.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_inet6.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>		/* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h>		/* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <netinet6/nd6.h>	/* Define ND6_INFINITE_LIFETIME */
+
+#include "ifconfig.h"
+
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define	NI_WITHSCOPEID	0
+#endif
+
+static	struct in6_ifreq in6_ridreq;
+static	struct in6_aliasreq in6_addreq = 
+  { { 0 }, 
+    { 0 }, 
+    { 0 }, 
+    { 0 }, 
+    0, 
+    { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
+static	int ip6lifetime;
+
+static	void in6_fillscopeid(struct sockaddr_in6 *sin6);
+static	int prefix(void *, int);
+static	char *sec2str(time_t);
+static	int explicit_prefix = 0;
+
+static	char addr_buf[MAXHOSTNAMELEN *2 + 1];	/*for getnameinfo()*/
+
+static void
+setifprefixlen(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+        if (afp->af_getprefix != NULL)
+                afp->af_getprefix(addr, MASK);
+	explicit_prefix = 1;
+}
+
+static void
+setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
+    const struct afswtch *afp)
+{
+	if (afp->af_af != AF_INET6)
+		err(1, "address flags can be set only for inet6 addresses");
+
+	if (flag < 0)
+		in6_addreq.ifra_flags &= ~(-flag);
+	else
+		in6_addreq.ifra_flags |= flag;
+}
+
+static void
+setip6lifetime(const char *cmd, const char *val, int s, 
+    const struct afswtch *afp)
+{
+	time_t newval, t;
+	char *ep;
+
+	t = time(NULL);
+	newval = (time_t)strtoul(val, &ep, 0);
+	if (val == ep)
+		errx(1, "invalid %s", cmd);
+	if (afp->af_af != AF_INET6)
+		errx(1, "%s not allowed for the AF", cmd);
+	if (strcmp(cmd, "vltime") == 0) {
+		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
+		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
+	} else if (strcmp(cmd, "pltime") == 0) {
+		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
+		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+	}
+}
+
+static void
+setip6pltime(const char *seconds, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	setip6lifetime("pltime", seconds, s, afp);
+}
+
+static void
+setip6vltime(const char *seconds, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	setip6lifetime("vltime", seconds, s, afp);
+}
+
+static void
+setip6eui64(const char *cmd, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+	struct ifaddrs *ifap, *ifa;
+	const struct sockaddr_in6 *sin6 = NULL;
+	const struct in6_addr *lladdr = NULL;
+	struct in6_addr *in6;
+
+	if (afp->af_af != AF_INET6)
+		errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
+ 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
+		errx(EXIT_FAILURE, "interface index is already filled");
+	if (getifaddrs(&ifap) != 0)
+		err(EXIT_FAILURE, "getifaddrs");
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr->sa_family == AF_INET6 &&
+		    strcmp(ifa->ifa_name, name) == 0) {
+			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
+			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+				lladdr = &sin6->sin6_addr;
+				break;
+			}
+		}
+	}
+	if (!lladdr)
+		errx(EXIT_FAILURE, "could not determine link local address"); 
+
+ 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
+
+	freeifaddrs(ifap);
+}
+
+static void
+in6_fillscopeid(struct sockaddr_in6 *sin6)
+{
+#if defined(__KAME__) && defined(KAME_SCOPEID)
+	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+		sin6->sin6_scope_id =
+			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
+	}
+#endif
+}
+
+static void
+in6_status(int s __unused, const struct rt_addrinfo * info)
+{
+	struct sockaddr_in6 *sin, null_sin;
+	struct in6_ifreq ifr6;
+	int s6;
+	u_int32_t flags6;
+	struct in6_addrlifetime lifetime;
+	time_t t = time(NULL);
+	int error;
+	u_int32_t scopeid;
+
+	memset(&null_sin, 0, sizeof(null_sin));
+
+	sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+	if (sin == NULL)
+		return;
+
+	strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+		warn("socket(AF_INET6,SOCK_DGRAM)");
+		return;
+	}
+	ifr6.ifr_addr = *sin;
+	if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+		warn("ioctl(SIOCGIFAFLAG_IN6)");
+		close(s6);
+		return;
+	}
+	flags6 = ifr6.ifr_ifru.ifru_flags6;
+	memset(&lifetime, 0, sizeof(lifetime));
+	ifr6.ifr_addr = *sin;
+	if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
+		warn("ioctl(SIOCGIFALIFETIME_IN6)");
+		close(s6);
+		return;
+	}
+	lifetime = ifr6.ifr_ifru.ifru_lifetime;
+	close(s6);
+
+	/* XXX: embedded link local addr check */
+	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+	    *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+		u_short index;
+
+		index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+		*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+		if (sin->sin6_scope_id == 0)
+			sin->sin6_scope_id = ntohs(index);
+	}
+	scopeid = sin->sin6_scope_id;
+
+	error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
+			    sizeof(addr_buf), NULL, 0,
+			    NI_NUMERICHOST|NI_WITHSCOPEID);
+	if (error != 0)
+		inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+			  sizeof(addr_buf));
+	printf("\tinet6 %s ", addr_buf);
+
+	if (flags & IFF_POINTOPOINT) {
+		/* note RTAX_BRD overlap with IFF_BROADCAST */
+		sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+		/*
+		 * some of the interfaces do not have valid destination
+		 * address.
+		 */
+		if (sin && sin->sin6_family == AF_INET6) {
+			int error;
+
+			/* XXX: embedded link local addr check */
+			if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+			    *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+				u_short index;
+
+				index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+				*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+				if (sin->sin6_scope_id == 0)
+					sin->sin6_scope_id = ntohs(index);
+			}
+
+			error = getnameinfo((struct sockaddr *)sin,
+					    sin->sin6_len, addr_buf,
+					    sizeof(addr_buf), NULL, 0,
+					    NI_NUMERICHOST|NI_WITHSCOPEID);
+			if (error != 0)
+				inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+					  sizeof(addr_buf));
+			printf("--> %s ", addr_buf);
+		}
+	}
+
+	sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
+	if (!sin)
+		sin = &null_sin;
+	printf("prefixlen %d ", prefix(&sin->sin6_addr,
+		sizeof(struct in6_addr)));
+
+	if ((flags6 & IN6_IFF_ANYCAST) != 0)
+		printf("anycast ");
+	if ((flags6 & IN6_IFF_TENTATIVE) != 0)
+		printf("tentative ");
+	if ((flags6 & IN6_IFF_DUPLICATED) != 0)
+		printf("duplicated ");
+	if ((flags6 & IN6_IFF_DETACHED) != 0)
+		printf("detached ");
+	if ((flags6 & IN6_IFF_DEPRECATED) != 0)
+		printf("deprecated ");
+	if ((flags6 & IN6_IFF_AUTOCONF) != 0)
+		printf("autoconf ");
+	if ((flags6 & IN6_IFF_TEMPORARY) != 0)
+		printf("temporary ");
+
+        if (scopeid)
+		printf("scopeid 0x%x ", scopeid);
+
+	if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+		printf("pltime ");
+		if (lifetime.ia6t_preferred) {
+			printf("%s ", lifetime.ia6t_preferred < t
+				? "0" : sec2str(lifetime.ia6t_preferred - t));
+		} else
+			printf("infty ");
+
+		printf("vltime ");
+		if (lifetime.ia6t_expire) {
+			printf("%s ", lifetime.ia6t_expire < t
+				? "0" : sec2str(lifetime.ia6t_expire - t));
+		} else
+			printf("infty ");
+	}
+
+	putchar('\n');
+}
+
+#define	SIN6(x) ((struct sockaddr_in6 *) &(x))
+static struct	sockaddr_in6 *sin6tab[] = {
+	SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+	SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
+};
+
+static void
+in6_getprefix(const char *plen, int which)
+{
+	struct sockaddr_in6 *sin = sin6tab[which];
+	u_char *cp;
+	int len = atoi(plen);
+
+	if ((len < 0) || (len > 128))
+		errx(1, "%s: bad value", plen);
+	sin->sin6_len = sizeof(*sin);
+	if (which != MASK)
+		sin->sin6_family = AF_INET6;
+	if ((len == 0) || (len == 128)) {
+		memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
+		return;
+	}
+	memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
+	for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+		*cp++ = 0xff;
+	*cp = 0xff << (8 - len);
+}
+
+static void
+in6_getaddr(const char *s, int which)
+{
+	struct sockaddr_in6 *sin = sin6tab[which];
+	struct addrinfo hints, *res;
+	int error = -1;
+
+	newaddr &= 1;
+
+	sin->sin6_len = sizeof(*sin);
+	if (which != MASK)
+		sin->sin6_family = AF_INET6;
+
+	if (which == ADDR) {
+		char *p = NULL;
+		if((p = strrchr(s, '/')) != NULL) {
+			*p = '\0';
+			in6_getprefix(p + 1, MASK);
+			explicit_prefix = 1;
+		}
+	}
+
+	if (sin->sin6_family == AF_INET6) {
+		bzero(&hints, sizeof(struct addrinfo));
+		hints.ai_family = AF_INET6;
+		error = getaddrinfo(s, NULL, &hints, &res);
+	}
+	if (error != 0) {
+		if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+			errx(1, "%s: bad value", s);
+	} else
+		bcopy(res->ai_addr, sin, res->ai_addrlen);
+}
+
+static int
+prefix(void *val, int size)
+{
+        u_char *name = (u_char *)val;
+        int byte, bit, plen = 0;
+
+        for (byte = 0; byte < size; byte++, plen += 8)
+                if (name[byte] != 0xff)
+                        break;
+	if (byte == size)
+		return (plen);
+	for (bit = 7; bit != 0; bit--, plen++)
+                if (!(name[byte] & (1 << bit)))
+                        break;
+        for (; bit != 0; bit--)
+                if (name[byte] & (1 << bit))
+                        return(0);
+        byte++;
+        for (; byte < size; byte++)
+                if (name[byte])
+                        return(0);
+        return (plen);
+}
+
+static char *
+sec2str(time_t total)
+{
+	static char result[256];
+	int days, hours, mins, secs;
+	int first = 1;
+	char *p = result;
+
+	if (0) {
+		days = total / 3600 / 24;
+		hours = (total / 3600) % 24;
+		mins = (total / 60) % 60;
+		secs = total % 60;
+
+		if (days) {
+			first = 0;
+			p += sprintf(p, "%dd", days);
+		}
+		if (!first || hours) {
+			first = 0;
+			p += sprintf(p, "%dh", hours);
+		}
+		if (!first || mins) {
+			first = 0;
+			p += sprintf(p, "%dm", mins);
+		}
+		sprintf(p, "%ds", secs);
+	} else
+		sprintf(result, "%lu", (unsigned long)total);
+
+	return(result);
+}
+
+static void
+in6_postproc(int s, const struct afswtch *afp)
+{
+	if (explicit_prefix == 0) {
+		/* Aggregatable address architecture defines all prefixes
+		   are 64. So, it is convenient to set prefixlen to 64 if
+		   it is not specified. */
+		setifprefixlen("64", 0, s, afp);
+		/* in6_getprefix("64", MASK) if MASK is available here... */
+	}
+}
+
+static void
+in6_status_tunnel(int s)
+{
+	char src[NI_MAXHOST];
+	char dst[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+	const int niflag = NI_NUMERICHOST;
+#endif
+	struct in6_ifreq in6_ifr;
+	const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
+
+	memset(&in6_ifr, 0, sizeof(in6_ifr));
+	strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
+
+	if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
+		return;
+	if (sa->sa_family == AF_INET6)
+		in6_fillscopeid(&in6_ifr.ifr_addr);
+	if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, niflag) != 0)
+		src[0] = '\0';
+
+	if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
+		return;
+	if (sa->sa_family == AF_INET6)
+		in6_fillscopeid(&in6_ifr.ifr_addr);
+	if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, niflag) != 0)
+		dst[0] = '\0';
+
+	printf("\ttunnel inet6 %s --> %s\n", src, dst);
+}
+
+static void
+in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+	struct in6_aliasreq in6_addreq; 
+
+	memset(&in6_addreq, 0, sizeof(in6_addreq));
+	strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
+	memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+	memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
+	    dstres->ai_addr->sa_len);
+
+	if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
+		warn("SIOCSIFPHYADDR_IN6");
+}
+
+static struct cmd inet6_cmds[] = {
+	DEF_CMD_ARG("prefixlen",			setifprefixlen),
+	DEF_CMD("tentative",	IN6_IFF_TENTATIVE,	setip6flags),
+	DEF_CMD("-tentative",	-IN6_IFF_TENTATIVE,	setip6flags),
+	DEF_CMD("deprecated",	IN6_IFF_DEPRECATED,	setip6flags),
+	DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED,	setip6flags),
+	DEF_CMD("autoconf",	IN6_IFF_AUTOCONF,	setip6flags),
+	DEF_CMD("-autoconf",	-IN6_IFF_AUTOCONF,	setip6flags),
+	DEF_CMD_ARG("pltime",        			setip6pltime),
+	DEF_CMD_ARG("vltime",        			setip6vltime),
+	DEF_CMD("eui64",	0,			setip6eui64),
+};
+
+static struct afswtch af_inet6 = {
+	.af_name	= "inet6",
+	.af_af		= AF_INET6,
+	.af_status	= in6_status,
+	.af_getaddr	= in6_getaddr,
+	.af_getprefix	= in6_getprefix,
+	.af_postproc	= in6_postproc,
+	.af_status_tunnel = in6_status_tunnel,
+	.af_settunnel	= in6_set_tunnel,
+	.af_difaddr	= SIOCDIFADDR_IN6,
+	.af_aifaddr	= SIOCAIFADDR_IN6,
+	.af_ridreq	= &in6_addreq,
+	.af_addreq	= &in6_addreq,
+};
+
+static void
+in6_Lopt_cb(const char *optarg __unused)
+{
+	ip6lifetime++;	/* print IPv6 address lifetime */
+}
+static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
+
+static __constructor void
+inet6_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(inet6_cmds);  i++)
+		cmd_register(&inet6_cmds[i]);
+	af_register(&af_inet6);
+	opt_register(&in6_Lopt);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/af_ipx.c src/sbin/ifconfig/af_ipx.c
--- src.preview/sbin/ifconfig/af_ipx.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_ipx.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if_var.h>
+#define	IPXIP
+#define IPTUNNEL
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq ipx_addreq;
+static struct ifreq ipx_ridreq;
+
+static void
+ipx_status(int s __unused, const struct rt_addrinfo * info)
+{
+	struct sockaddr_ipx *sipx, null_sipx;
+
+	sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
+	if (sipx == NULL)
+		return;
+
+	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
+
+	if (flags & IFF_POINTOPOINT) {
+		sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
+		if (!sipx) {
+			memset(&null_sipx, 0, sizeof(null_sipx));
+			sipx = &null_sipx;
+		}
+		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
+	}
+	putchar('\n');
+}
+
+#define SIPX(x) ((struct sockaddr_ipx *) &(x))
+struct sockaddr_ipx *sipxtab[] = {
+	SIPX(ipx_ridreq.ifr_addr), SIPX(ipx_addreq.ifra_addr),
+	SIPX(ipx_addreq.ifra_mask), SIPX(ipx_addreq.ifra_broadaddr)
+};
+
+static void
+ipx_getaddr(const char *addr, int which)
+{
+	struct sockaddr_ipx *sipx = sipxtab[which];
+
+	sipx->sipx_family = AF_IPX;
+	sipx->sipx_len = sizeof(*sipx);
+	sipx->sipx_addr = ipx_addr(addr);
+	if (which == MASK)
+		printf("Attempt to set IPX netmask will be ineffectual\n");
+}
+
+static void
+ipx_postproc(int s, const struct afswtch *afp)
+{
+	if (setipdst) {
+		struct ipxip_req rq;
+		int size = sizeof(rq);
+
+		rq.rq_ipx = ipx_addreq.ifra_addr;
+		rq.rq_ip = ipx_addreq.ifra_dstaddr;
+
+		if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
+			Perror("Encapsulation Routing");
+	}
+}
+
+static struct afswtch af_ipx = {
+	.af_name	= "ipx",
+	.af_af		= AF_IPX,
+	.af_status	= ipx_status,
+	.af_getaddr	= ipx_getaddr,
+	.af_postproc	= ipx_postproc,
+	.af_difaddr	= SIOCDIFADDR,
+	.af_aifaddr	= SIOCAIFADDR,
+	.af_ridreq	= &ipx_ridreq,
+	.af_addreq	= &ipx_addreq,
+};
+
+static __constructor void
+ipx_ctor(void)
+{
+	af_register(&af_ipx);
+}
diff -N -u -r src.preview/sbin/ifconfig/af_link.c src/sbin/ifconfig/af_link.c
--- src.preview/sbin/ifconfig/af_link.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/af_link.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>		/* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include "ifconfig.h"
+
+static struct ifreq link_ridreq;
+
+static void
+link_status(int s __unused, const struct rt_addrinfo *info)
+{
+	const struct sockaddr_dl *sdl =
+		(const struct sockaddr_dl *) info->rti_info[RTAX_IFA];
+
+	if (sdl != NULL && sdl->sdl_alen > 0) {
+		if (sdl->sdl_type == IFT_ETHER &&
+		    sdl->sdl_alen == ETHER_ADDR_LEN)
+			printf("\tether %s\n",
+			    ether_ntoa((const struct ether_addr *)LLADDR(sdl)));
+		else {
+			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+			printf("\tlladdr %s\n", link_ntoa(sdl) + n);
+		}
+	}
+}
+
+static void
+link_getaddr(const char *addr, int which)
+{
+	char *temp;
+	struct sockaddr_dl sdl;
+	struct sockaddr *sa = &link_ridreq.ifr_addr;
+
+	if (which != ADDR)
+		errx(1, "can't set link-level netmask or broadcast");
+	if ((temp = malloc(strlen(addr) + 1)) == NULL)
+		errx(1, "malloc failed");
+	temp[0] = ':';
+	strcpy(temp + 1, addr);
+	sdl.sdl_len = sizeof(sdl);
+	link_addr(temp, &sdl);
+	free(temp);
+	if (sdl.sdl_alen > sizeof(sa->sa_data))
+		errx(1, "malformed link-level address");
+	sa->sa_family = AF_LINK;
+	sa->sa_len = sdl.sdl_alen;
+	bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
+}
+
+static struct afswtch af_link = {
+	.af_name	= "link",
+	.af_af		= AF_LINK,
+	.af_status	= link_status,
+	.af_getaddr	= link_getaddr,
+	.af_aifaddr	= SIOCSIFLLADDR,
+	.af_addreq	= &link_ridreq,
+};
+static struct afswtch af_ether = {
+	.af_name	= "ether",
+	.af_af		= AF_LINK,
+	.af_status	= link_status,
+	.af_getaddr	= link_getaddr,
+	.af_aifaddr	= SIOCSIFLLADDR,
+	.af_addreq	= &link_ridreq,
+};
+static struct afswtch af_lladdr = {
+	.af_name	= "lladdr",
+	.af_af		= AF_LINK,
+	.af_status	= link_status,
+	.af_getaddr	= link_getaddr,
+	.af_aifaddr	= SIOCSIFLLADDR,
+	.af_addreq	= &link_ridreq,
+};
+
+static __constructor void
+link_ctor(void)
+{
+	af_register(&af_link);
+	af_register(&af_ether);
+	af_register(&af_lladdr);
+}
diff -N -u -r src.preview/sbin/ifconfig/ifcarp.c src/sbin/ifconfig/ifcarp.c
--- src.preview/sbin/ifconfig/ifcarp.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/ifcarp.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,199 @@
+/*	$FreeBSD$ */
+/*	from $OpenBSD: ifconfig.c,v 1.82 2003/10/19 05:43:35 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
+ * Copyright (c) 2003 Ryan McBride. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/ip_carp.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static const char *carp_states[] = { CARP_STATES };
+
+void carp_status(int s);
+void setcarp_advbase(const char *,int, int, const struct afswtch *rafp);
+void setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
+void setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
+void setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
+
+void
+carp_status(int s)
+{
+	const char *state;
+	struct carpreq carpr;
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data = (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+		return;
+
+	if (carpr.carpr_vhid > 0) {
+		if (carpr.carpr_state > CARP_MAXSTATE)
+			state = "<UNKNOWN>";
+		else
+			state = carp_states[carpr.carpr_state];
+
+		printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
+		    state, carpr.carpr_vhid, carpr.carpr_advbase,
+		    carpr.carpr_advskew);
+	}
+
+	return;
+
+}
+
+void
+setcarp_passwd(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct carpreq carpr;
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data = (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGVH");
+
+	/* XXX Should hash the password into the key here, perhaps? */
+	strlcpy(carpr.carpr_key, val, CARP_KEY_LEN);
+
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSVH");
+
+	return;
+}
+
+void
+setcarp_vhid(const char *val, int d, int s, const struct afswtch *afp)
+{
+	int vhid;
+	struct carpreq carpr;
+
+	vhid = atoi(val);
+
+	if (vhid <= 0)
+		errx(1, "vhid must be greater than 0");
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data = (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGVH");
+
+	carpr.carpr_vhid = vhid;
+
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSVH");
+
+	return;
+}
+
+void
+setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
+{
+	int advskew;
+	struct carpreq carpr;
+
+	advskew = atoi(val);
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data = (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGVH");
+
+	carpr.carpr_advskew = advskew;
+
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSVH");
+
+	return;
+}
+
+void
+setcarp_advbase(const char *val, int d, int s, const struct afswtch *afp)
+{
+	int advbase;
+	struct carpreq carpr;
+
+	advbase = atoi(val);
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data = (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGVH");
+
+	carpr.carpr_advbase = advbase;
+
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSVH");
+
+	return;
+}
+
+static struct cmd carp_cmds[] = {
+	DEF_CMD_ARG("advbase",	setcarp_advbase),
+	DEF_CMD_ARG("advskew",	setcarp_advskew),
+	DEF_CMD_ARG("pass",	setcarp_passwd),
+	DEF_CMD_ARG("vhid",	setcarp_vhid),
+};
+static struct afswtch af_carp = {
+	.af_name	= "af_carp",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = carp_status,
+};
+
+static __constructor void
+carp_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(carp_cmds);  i++)
+		cmd_register(&carp_cmds[i]);
+	af_register(&af_carp);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifclone.c src/sbin/ifconfig/ifclone.c
--- src.preview/sbin/ifconfig/ifclone.c	1969-12-31 19:00:00.000000000 -0500
+++ src/sbin/ifconfig/ifclone.c	2005-09-27 15:02:10.000000000 -0400
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void
+list_cloners(void)
+{
+	struct if_clonereq ifcr;
+	char *cp, *buf;
+	int idx;
+	int s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s == -1)
+		err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+	memset(&ifcr, 0, sizeof(ifcr));
+
+	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+		err(1, "SIOCIFGCLONERS for count");
+
+	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
+	if (buf == NULL)
+		err(1, "unable to allocate cloner name buffer");
+
+	ifcr.ifcr_count = ifcr.ifcr_total;
+	ifcr.ifcr_buffer = buf;
+
+	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+		err(1, "SIOCIFGCLONERS for names");
+
+	/*
+	 * In case some disappeared in the mean time, clamp it down.
+	 */
+	if (ifcr.ifcr_count > ifcr.ifcr_total)
+		ifcr.ifcr_count = ifcr.ifcr_total;
+
+	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
+		if (idx > 0)
+			putchar(' ');
+		printf("%s", cp);
+	}
+
+	putchar('\n');
+	free(buf);
+}
+
+void
+clone_create(void)
+{
+	int s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s == -1)
+		err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+	memset(&ifr, 0, sizeof(ifr));
+	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
+		err(1, "SIOCIFCREATE");
+
+	/*
+	 * If we get a different name back then we put in, we probably
+	 * want to print it out, but we might change our mind later so
+	 * we just signal our intrest and leave the printout for later.
+	 */
+	if (strcmp(name, ifr.ifr_name) != 0) {
+		printname = 1;
+		strlcpy(name, ifr.ifr_name, sizeof(name));
+	}
+
+	close(s);
+}
+
+static void
+clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+		err(1, "SIOCIFDESTROY");
+	/*
+	 * If we create and destroy an interface in the same command,
+	 * there isn't any reason to print it's name.
+	 */
+	printname = 0;
+}
+
+static struct cmd clone_cmds[] = {
+	DEF_CMD("destroy",	0,	clone_destroy),
+	DEF_CMD("unplumb",	0,	clone_destroy),
+};
+
+static void
+clone_Copt_cb(const char *optarg __unused)
+{
+	list_cloners();
+	exit(0);
+}
+static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+
+static __constructor void
+clone_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(clone_cmds);  i++)
+		cmd_register(&clone_cmds[i]);
+	opt_register(&clone_Copt);
+#undef N
+}
diff -N -u -r src.preview/sbin/ifconfig/ifconfig.8 src/sbin/ifconfig/ifconfig.8
--- src.preview/sbin/ifconfig/ifconfig.8	2005-04-25 13:33:26.000000000 -0400
+++ src/sbin/ifconfig/ifconfig.8	2005-09-27 15:02:10.000000000 -0400
@@ -26,10 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
-.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.85 2004/07/27 09:51:49 yar Exp $
-.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.7 2005/04/25 17:33:26 swildner Exp $
+.\" $FreeBSD$
 .\"
-.Dd July 26, 2004
+.Dd November 2, 2004
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -56,6 +55,7 @@
 .Op Fl d
 .Op Fl m
 .Op Fl u
+.Op Fl v
 .Op Ar address_family
 .Nm
 .Fl l
@@ -67,6 +67,7 @@
 .Op Fl d
 .Op Fl m
 .Op Fl u
+.Op Fl v
 .Op Fl C
 .Sh DESCRIPTION
 The
@@ -224,6 +225,14 @@
 .It Fl arp
 Disable the use of the Address Resolution Protocol
 .Pq Xr arp 4 .
+.It Cm staticarp
+If the Address Resolution Protocol is enabled,
+the host will only reply to requests for its addresses,
+and will never send any requests.
+.It Fl staticarp
+If the Address Resolution Protocol is enabled,
+the host will perform normally,
+sending out requests and listening for replies.
 .It Cm broadcast
 (Inet only.)
 Specify the address to use to represent broadcasts to the
@@ -256,15 +265,18 @@
 Fill interface index
 (lowermost 64bit of an IPv6 address)
 automatically.
-.\" .It Cm ipdst
-.\" This is used to specify an Internet host who is willing to receive
-.\" ip packets encapsulating NS packets bound for a remote network.
-.\" An apparent point to point link is constructed, and
-.\" the address specified will be taken as the NS address and network
-.\" of the destination.
-.\" IP encapsulation of
-.\" .Tn CLNP
-.\" packets is done differently.
+.It Cm ipdst
+This is used to specify an Internet host who is willing to receive
+IP packets encapsulating IPX packets bound for a remote network.
+An apparent point to point link is constructed, and
+the address specified will be taken as the IPX address and network
+of the destination.
+.\".It Cm maclabel Ar label
+.\"If Mandatory Access Control support is enabled in the kernel,
+.\"set the MAC label to
+.\".Ar label .
+.\" (see
+.\" .Xr maclabel 7 ) .
 .It Cm media Ar type
 If the driver supports the media selection system, set the media type
 of the interface to
@@ -318,18 +330,18 @@
 of each other, so setting one may also set the other.
 The driver will offload as much checksum work as it can reliably
 support, the exact level of offloading varies between drivers.
-.\".It Fl rxcsum , Fl txcsum
-.\"If the driver supports user-configurable checksum offloading,
-.\"disable receive (or transmit) checksum offloading on the interface.
-.\"These settings may not always be independent of each other.
-.\".It Cm polling
-.\"If the driver has user-configurable
-.\".Xr polling 4
-.\"support, select the polling mode on the interface.
-.\".It Fl polling
-.\"If the driver has user-configurable
-.\".Xr polling 4
-.\"support, select the interrupt mode on the interface.
+.It Fl rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+disable receive (or transmit) checksum offloading on the interface.
+These settings may not always be independent of each other.
+.It Cm polling
+If the driver has user-configurable
+.Xr polling 4
+support, select the polling mode on the interface.
+.It Fl polling
+If the driver has user-configurable
+.Xr polling 4
+support, select the interrupt mode on the interface.
 .It Cm tunnel Ar src_addr dest_addr
 (IP tunnel devices only.)
 Configure the physical source and destination address for IP tunnel
@@ -350,7 +362,10 @@
 If the interface is given without a unit number, try to create a new
 device with an arbitrary unit number.
 If creation of an arbitrary device is successful, the new device name is
-printed to standard output.
+printed to standard output unless the interface is renamed or destroyed
+in the same
+.Nm
+invocation.
 .It Cm destroy
 Destroy the specified network pseudo-device.
 .It Cm plumb
@@ -446,7 +461,7 @@
 not on a
 .Xr vlan 4
 interface itself.
-.It Fl vlanmtu , Fl vlanhwtag
+.It Fl vlanmtu , vlanhwtag
 If the driver offers user-configurable VLAN support, disable
 reception of extended frames or tag processing in hardware,
 respectively.
@@ -568,13 +583,13 @@
 .It Fl link Op Cm 0 No - Cm 2
 .Sm on
 Disable special processing at the link level with the specified interface.
-.\".It Cm monitor
-.\"Put the interface in monitor mode.
-.\"No packets are transmitted, and received packets are discarded after
-.\".Xr bpf 4
-.\"processing.
-.\".It Fl monitor
-.\"Take the interface out of monitor mode.
+.It Cm monitor
+Put the interface in monitor mode.
+No packets are transmitted, and received packets are discarded after
+.Xr bpf 4
+processing.
+.It Fl monitor
+Take the interface out of monitor mode.
 .It Cm up
 Mark an interface
 .Dq up .
@@ -583,64 +598,104 @@
 It happens automatically when setting the first address on an interface.
 If the interface was reset when previously marked down,
 the hardware will be re-initialized.
-.It Cm ssid Ar ssid
-For IEEE 802.11 wireless interfaces, set the desired Service Set
-Identifier (aka network name).
-The SSID is a string up to 32 characters
-in length and may be specified as either a normal string or in
-hexadecimal when proceeded by
-.Ql 0x .
-Additionally, the SSID may be cleared by setting it to
-.Ql - .
-.It Cm nwid Ar ssid
-Another name for the
-.Cm ssid
-parameter.
-Included for
-.Nx
-compatibility.
-.It Cm stationname Ar name
-For IEEE 802.11 wireless interfaces, set the name of this station.
-It appears that the station name is not really part of the IEEE 802.11
-protocol though all interfaces seem to support it.
-As such it only
-seems to be meaningful to identical or virtually identical equipment.
-Setting the station name is identical in syntax to setting the SSID.
-.It Cm station Ar name
-Another name for the
-.Cm stationname
-parameter.
-Included for
-.Bsx
-compatibility.
-.It Cm channel Ar number
-For IEEE 802.11 wireless interfaces, set the desired channel.
-Channels range from 1 to 14, but the exact selection available
-depends on the region your adaptor was manufactured for.
-Setting
-the channel to 0 will give you the default for your adaptor.
-Many
-adaptors ignore this setting unless you are in ad-hoc mode.
+.El
+.Pp
+The following parameters are specific to IEEE 802.11 wireless interfaces:
+.Bl -tag -width indent
+.It Cm apbridge
+When operating as an access point, pass packets between
+wireless clients directly (default).
+To instead let them pass up through the
+system and be forwarded using some other mechanism, use
+.Fl apbridge .
+Disabling the internal bridging
+is useful when traffic is to be processed with
+packet filtering.
 .It Cm authmode Ar mode
-For IEEE 802.11 wireless interfaces, set the desired authentication mode
-in infrastructure mode.
+Set the desired authentication mode in infrastructure mode.
 Not all adaptors support all modes.
 The set of
 valid modes is
 .Dq Li none ,
 .Dq Li open ,
+.Dq Li shared
+(shared key),
+.Dq Li 8021x
+(IEEE 802.1x),
+or
+.Dq Li wpa
+(IEEE WPA/WPA2/802.11i).
+The
+.Dq Li 8021x
 and
-.Dq Li shared .
+.Dq Li wpa
+modes are only useful when used an authentication service
+(a supplicant for client operation or an authenticator when
+operating as an access point).
 Modes are case insensitive.
+.It Cm bssid Ar address
+Specify the MAC address of the access point to use when operating
+as a station in a BSS network.
+This overrides any automatic selection done by the system.
+To disable a previously selected access point, supply
+.Dq Li any ,
+.Dq Li none ,
+or
+.Dq Li -
+for the address.
+This option is useful when more than one access points have the same SSID.
+Another name for the
+.Cm bssid
+parameter is
+.Cm ap .
+.It Cm chanlist Ar channels
+Set the desired channels to use when scanning for access
+points, neighbors in an IBSS network, or looking for unoccupied
+channels when operating as an access point.
+The set of channels is specified as a comma-separated list with
+each element in the list representing either a single channel number or a range
+of the form
+.Dq Li a-b .
+Channel numbers must be in the range 1 to 255 and be permissible
+according to the operating characteristics of the device.
+.It Cm channel Ar number
+Set a single desired channel.
+Channels range from 1 to 255, but the exact selection available
+depends on the region your adaptor was manufactured for.
+Setting
+the channel to
+.Dq Li 0 ,
+.Dq Li any ,
+or
+.Dq Li -
+will give you the default for your adaptor.
+Many
+adaptors ignore this setting unless you are in ad-hoc mode.
+Alternatively the frequency, in megahertz, may be specified
+instead of the channel number.
+.It Cm hidessid
+When operating as an access point, do not broadcast the SSID
+in beacon frames.
+By default, the SSID is included in beacon frames.
+To re-enable the broadcast of the SSID, use
+.Fl hidessid .
 .It Cm powersave
-For IEEE 802.11 wireless interfaces, enable powersave mode.
-.It Fl powersave
-For IEEE 802.11 wireless interfaces, disable powersave mode.
+Enable powersave operation.
+When operating as a client, the station will conserve power by
+periodically turning off the radio and listening for
+messages from the access point telling it there are packets waiting.
+The station must then retrieve the packets.
+When operating as an access point, the station must honor power
+save operation of associated clients.
+Not all devices support power save operation, either as a client
+or as an access point.
+Use
+.Fl powersave
+to disable powersave operation.
 .It Cm powersavesleep Ar sleep
-For IEEE 802.11 wireless interfaces, set the desired max powersave sleep
-time in milliseconds.
+Set the desired max powersave sleep time in milliseconds.
 .It Cm protmode Ar technique
-For IEEE 802.11 wireless interfaces operating in 11g, use the specified
+For interfaces operating in 802.11g, use the specified
 .Ar technique
 for protecting OFDM frames in a mixed 11b/11g network.
 The set of valid techniques is
@@ -651,8 +706,26 @@
 .Dq Li rtscts
 (RTS/CTS).
 Technique names are case insensitive.
+.It Cm roaming Ar mode
+When operating as a station, control how the system will
+behave when communication with the current access point
+is broken.
+The
+.Ar mode
+argument may be one of
+.Dq Li device
+(leave it to the hardware device to decide),
+.Dq Li auto
+(handle either in the device or the operating system\[em]as appropriate),
+.Dq Li manual
+(do nothing until explicitly instructed).
+By default, the device is left to handle this if it is
+capable; otherwise, the operating system will automatically
+attempt to reestablish communication.
+Manual mode is mostly useful when an application wants to
+control the selection of an access point.
 .It Cm rtsthreshold Ar length
-For IEEE 802.11 wireless interfaces, set the threshold for which
+Set the threshold for which
 transmitted frames are preceded by transmission of an
 RTS
 control frame.
@@ -661,8 +734,26 @@
 argument
 is the frame size in bytes and must be in the range 1 to 2312.
 Not all adaptors support setting the RTS threshold.
+.It Cm ssid Ar ssid
+Set the desired Service Set Identifier (aka network name).
+The SSID is a string up to 32 characters
+in length and may be specified as either a normal string or in
+hexadecimal when proceeded by
+.Ql 0x .
+Additionally, the SSID may be cleared by setting it to
+.Ql - .
+.It Cm scan
+Display the current set of scanned neighbors and/or trigger a new scan.
+Only the super-user can trigger a scan.
+.It Cm stationname Ar name
+Set the name of this station.
+It appears that the station name is not really part of the IEEE 802.11
+protocol though all interfaces seem to support it.
+As such it only
+seems to be meaningful to identical or virtually identical equipment.
+Setting the station name is identical in syntax to setting the SSID.
 .It Cm txpower Ar power
-For IEEE 802.11 wireless interfaces, set the power used to transmit frames.
+Set the power used to transmit frames.
 The
 .Ar power
 argument
@@ -673,7 +764,7 @@
 the driver will use the setting closest to the specified value.
 Not all adaptors support changing the transmit power.
 .It Cm wepmode Ar mode
-For IEEE 802.11 wireless interfaces, set the desired WEP mode.
+Set the desired WEP mode.
 Not all adaptors support all modes.
 The set of valid modes is
 .Dq Li off ,
@@ -693,10 +784,9 @@
 .Dq Li mixed .
 Modes are case insensitive.
 .It Cm weptxkey Ar index
-For IEEE 802.11 wireless interfaces, set the WEP key to be used for
-transmission.
+Set the WEP key to be used for transmission.
 .It Cm wepkey Ar key Ns | Ns Ar index : Ns Ar key
-For IEEE 802.11 wireless interfaces, set the selected WEP key.
+Set the selected WEP key.
 If an
 .Ar index
 is not given, key 1 is set.
@@ -719,6 +809,31 @@
 If that is the case, then the first four keys
 (1-4) will be the standard temporary keys and any others will be adaptor
 specific keys such as permanent keys stored in NVRAM.
+.It Cm wme
+Enable Wireless Media Extensions (WME) support, if available,
+for the specified interface.
+WME is a subset of the IEEE 802.11e standard to support the
+efficient communication of realtime and multimedia data.
+To disable WME support, use
+.Fl wme .
+.El
+.Pp
+The following parameters are support for compatibility with other systems:
+.Bl -tag -width indent
+.It Cm nwid Ar ssid
+Another name for the
+.Cm ssid
+parameter.
+Included for
+.Nx
+compatibility.
+.It Cm station Ar name
+Another name for the
+.Cm stationname
+parameter.
+Included for
+.Bsx
+compatibility.
 .It Cm wep
 Another way of saying
 .Cm wepmode on .
@@ -733,9 +848,7 @@
 compatibility.
 .It Cm nwkey key
 Another way of saying:
-.Pp
 .Dq Li "wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-" .
-.Pp
 Included for
 .Nx
 compatibility.
@@ -745,16 +858,13 @@
 .Sm on
 .Xc
 Another way of saying
-.Pp
 .Dq Li "wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4" .
-.Pp
 Included for
 .Nx
 compatibility.
 .It Fl nwkey
 Another way of saying
 .Cm wepmode off .
-.Pp
 Included for
 .Nx
 compatibility.
@@ -768,9 +878,6 @@
 .Nm
 will report only the details specific to that protocol family.
 .Pp
-If the driver does supports the media selection system, the supported
-media list will be included in the output.
-.Pp
 If the
 .Fl m
 flag is passed before an interface name,
@@ -810,6 +917,10 @@
 (only list interfaces that are up).
 .Pp
 The
+.Fl v
+flag may be used to get more verbose status for an interface.
+.Pp
+The
 .Fl C
 flag may be used to list all of the interface cloners available on
 the system, with no additional information.
@@ -823,22 +934,10 @@
 Messages indicating the specified interface does not exist, the
 requested address is unknown, or the user is not privileged and
 tried to alter an interface's configuration.
-.Sh BUGS
-Basic IPv6 node operation requires a link-local address on each
-interface configured for IPv6.
-Normally, such an address is automatically configured by the
-kernel on each interface added to the system; this behaviour may
-be disabled by setting the sysctl MIB variable
-.Va net.inet6.ip6.auto_linklocal
-to 0.
-.Pp
-If you delete such an address using
-.Nm ,
-the kernel may act very oddly.
-Do this at your own risk.
 .Sh SEE ALSO
 .Xr netstat 1 ,
 .Xr netintro 4 ,
+.Xr polling 4 ,
 .Xr vlan 4 ,
 .\" .Xr eon 5 ,
 .Xr rc 8 ,
@@ -849,3 +948,16 @@
 .Nm
 utility appeared in
 .Bx 4.2 .
+.Sh BUGS
+Basic IPv6 node operation requires a link-local address on each
+interface configured for IPv6.
+Normally, such an address is automatically configured by the
+kernel on each interface added to the system; this behaviour may
+be disabled by setting the sysctl MIB variable
+.Va net.inet6.ip6.auto_linklocal
+to 0.
+.Pp
+If you delete such an address using
+.Nm ,
+the kernel may act very oddly.
+Do this at your own risk.
diff -N -u -r src.preview/sbin/ifconfig/ifconfig.c src/sbin/ifconfig/ifconfig.c
--- src.preview/sbin/ifconfig/ifconfig.c	2005-05-26 05:06:40.000000000 -0400
+++ src/sbin/ifconfig/ifconfig.c	2005-09-27 15:03:42.000000000 -0400
@@ -25,17 +25,25 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * @(#) Copyright (c) 1983, 1993 The Regents of the University of California.  All rights reserved.
- * @(#)ifconfig.c	8.2 (Berkeley) 2/16/94
- * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.96 2004/02/27 06:43:14 kan Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.24 2005/05/26 09:06:40 dillon Exp $
  */
 
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
+#endif
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
-#include <sys/sockio.h>
 #include <sys/sysctl.h>
 #include <sys/time.h>
 #include <sys/module.h>
@@ -54,30 +62,6 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
-#ifdef INET6
-#include <netinet6/nd6.h>	/* Define ND6_INFINITE_LIFETIME */
-#endif
-
-#ifndef NO_IPX
-/* IPX */
-#define	IPXIP
-#define IPTUNNEL
-#include <netipx/ipx.h>
-#include <netipx/ipx_if.h>
-#endif
-
-/* Appletalk */
-#include <netatalk/at.h>
-
-/* XNS */
-#ifdef NS
-#define	NSIP
-#include <netns/ns.h>
-#include <netns/ns_if.h>
-#endif
-
-/* OSI */
-
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -86,34 +70,15 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <ifaddrs.h>
 
 #include "ifconfig.h"
 
-/* wrapper for KAME-special getnameinfo() */
-#ifndef NI_WITHSCOPEID
-#define	NI_WITHSCOPEID	0
-#endif
-
 /*
  * Since "struct ifreq" is composed of various union members, callers
  * should pay special attention to interprete the value.
  * (.e.g. little/big endian difference in the structure.)
  */
-struct	ifreq		ifr, ridreq;
-struct	ifaliasreq	addreq;
-#ifdef INET6
-struct	in6_ifreq	in6_ridreq;
-struct	in6_aliasreq	in6_addreq = 
-  { { 0 }, 
-    { 0, 0, 0, 0, { { { 0 } } }, 0 }, 
-    { 0, 0, 0, 0, { { { 0 } } }, 0 }, 
-    { 0, 0, 0, 0, { { { 0 } } }, 0 }, 
-    0, 
-    { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
-#endif
-struct	sockaddr_in	netmask;
-struct	netrange	at_nr;		/* AppleTalk net range */
+struct	ifreq ifr;
 
 char	name[IFNAMSIZ];
 int	flags;
@@ -123,326 +88,78 @@
 int	doalias;
 int	clearaddr;
 int	newaddr = 1;
-#ifdef INET6
-static	int ip6lifetime;
-#endif
+int	verbose;
 
-struct	afswtch;
+int	supmedia = 0;
+int	printname = 0;		/* Print the name of the created interface. */
 
-int supmedia = 0;
-int listcloners = 0;
-int printname = 0;		/* Print the name of the created interface. */
-
-#ifdef INET6
-char	addr_buf[MAXHOSTNAMELEN *2 + 1];	/*for getnameinfo()*/
-#endif
-
-void	Perror(const char *cmd);
-void	checkatrange(struct sockaddr_at *);
-int	ifconfig(int argc, char *const *argv, const struct afswtch *afp);
-void	notealias(const char *, int, int, const struct afswtch *afp);
-void	list_cloners(void);
-void	printb(const char *s, unsigned value, const char *bits);
-void	rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
-void	status(const struct afswtch *afp, int addrcount,
+static	int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
+static	void status(const struct afswtch *afp, int addrcount,
 		    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
 		    struct ifa_msghdr *ifam);
-void	tunnel_status(int s);
-void	usage(void);
-void	ifmaybeload(char *if_nm);
-
-#ifdef INET6
-void	in6_fillscopeid(struct sockaddr_in6 *sin6);
-int	prefix(void *, int);
-static	char *sec2str(time_t);
-int	explicit_prefix = 0;
-#endif
-
-typedef	void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
-typedef	void c_func2(const char *arg, const char *arg2, int s, const struct afswtch *afp);
-c_func	setatphase, setatrange;
-c_func	setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
-c_func2	settunnel;
-c_func	deletetunnel;
-#ifdef INET6
-c_func	setifprefixlen;
-c_func	setip6flags;
-c_func  setip6pltime;
-c_func  setip6vltime;
-c_func2	setip6lifetime;
-c_func	setip6eui64;
-#endif
-c_func	setifipdst;
-c_func	setifflags, setifmetric, setifmtu, setifcap;
-c_func	clone_destroy;
-c_func	setifname;
-
-void clone_create(void);
-
-
-#define	NEXTARG		0xffffff
-#define	NEXTARG2	0xfffffe
-
-const
-struct	cmd {
-	const	char *c_name;
-	int	c_parameter;		/* NEXTARG means next argv */
-	void	(*c_func)(const char *, int, int, const struct afswtch *afp);
-	void	(*c_func2)(const char *, const char *, int, const struct afswtch *afp);
-} cmds[] = {
-	{ "up",		IFF_UP,		setifflags,	NULL },
-	{ "down",	-IFF_UP,	setifflags,	NULL },
-	{ "polling",	IFF_POLLING,	setifflags,	NULL },
-	{ "-polling",	-IFF_POLLING,	setifflags,	NULL },
-	{ "arp",	-IFF_NOARP,	setifflags,	NULL },
-	{ "-arp",	IFF_NOARP,	setifflags,	NULL },
-	{ "debug",	IFF_DEBUG,	setifflags,	NULL },
-	{ "-debug",	-IFF_DEBUG,	setifflags,	NULL },
-	{ "promisc",	IFF_PPROMISC,	setifflags,	NULL },
-	{ "-promisc",	-IFF_PPROMISC,	setifflags,	NULL },
-	{ "add",	IFF_UP,		notealias,	NULL },
-	{ "alias",	IFF_UP,		notealias,	NULL },
-	{ "-alias",	-IFF_UP,	notealias,	NULL },
-	{ "delete",	-IFF_UP,	notealias,	NULL },
-	{ "remove",	-IFF_UP,	notealias,	NULL },
-#ifdef notdef
-#define	EN_SWABIPS	0x1000
-	{ "swabips",	EN_SWABIPS,	setifflags,	NULL },
-	{ "-swabips",	-EN_SWABIPS,	setifflags,	NULL },
-#endif
-	{ "netmask",	NEXTARG,	setifnetmask,	NULL },
-#ifdef INET6
-	{ "prefixlen",	NEXTARG,	setifprefixlen,	NULL },
-	{ "anycast",	IN6_IFF_ANYCAST, setip6flags,	NULL },
-	{ "tentative",	IN6_IFF_TENTATIVE, setip6flags,	NULL },
-	{ "-tentative",	-IN6_IFF_TENTATIVE, setip6flags, NULL },
-	{ "deprecated",	IN6_IFF_DEPRECATED, setip6flags, NULL },
-	{ "-deprecated", -IN6_IFF_DEPRECATED, setip6flags, NULL },
-	{ "autoconf",	IN6_IFF_AUTOCONF, setip6flags,	NULL },
-	{ "-autoconf",	-IN6_IFF_AUTOCONF, setip6flags,	NULL },
-	{ "pltime",     NEXTARG,        setip6pltime,	NULL },
-	{ "vltime",     NEXTARG,        setip6vltime,	NULL },
-	{ "eui64",	0,		setip6eui64,	NULL },
-#endif
-	{ "range",	NEXTARG,	setatrange,	NULL },
-	{ "phase",	NEXTARG,	setatphase,	NULL },
-	{ "metric",	NEXTARG,	setifmetric,	NULL },
-	{ "broadcast",	NEXTARG,	setifbroadaddr,	NULL },
-	{ "ipdst",	NEXTARG,	setifipdst,	NULL },
-	{ "tunnel",	NEXTARG2,	NULL,		settunnel },
-	{ "deletetunnel", 0,		deletetunnel,	NULL },
-	{ "link0",	IFF_LINK0,	setifflags,	NULL },
-	{ "-link0",	-IFF_LINK0,	setifflags,	NULL },
-	{ "link1",	IFF_LINK1,	setifflags,	NULL },
-	{ "-link1",	-IFF_LINK1,	setifflags,	NULL },
-	{ "link2",	IFF_LINK2,	setifflags,	NULL },
-	{ "-link2",	-IFF_LINK2,	setifflags,	NULL },
-#if notyet
-	{ "monitor",	IFF_MONITOR,	setifflags,	NULL },
-	{ "-monitor",	-IFF_MONITOR,	setifflags,	NULL },
-	{ "staticarp",	IFF_STATICARP,	setifflags,	NULL },
-	{ "-staticarp",	-IFF_STATICARP,	setifflags,	NULL },
-#endif
+static	void tunnel_status(int s);
+static	void usage(void);
 
-#ifdef USE_IF_MEDIA
-	{ "media",	NEXTARG,	setmedia,	NULL },
-	{ "mode",	NEXTARG,	setmediamode,	NULL },
-	{ "mediaopt",	NEXTARG,	setmediaopt,	NULL },
-	{ "-mediaopt",	NEXTARG,	unsetmediaopt,	NULL },
-#endif
-#ifdef USE_VLANS
-	{ "vlan",	NEXTARG,	setvlantag,	NULL },
-	{ "vlandev",	NEXTARG,	setvlandev,	NULL },
-	{ "-vlandev",	NEXTARG,	unsetvlandev,	NULL },
-#endif
-#if 0
-	/* XXX `create' special-cased below */
-	{"create",	0,		clone_create,	NULL },
-	{"plumb",	0,		clone_create,	NULL },
-#endif
-	{"destroy",	0,		clone_destroy,	NULL },
-	{"unplumb",	0,		clone_destroy,	NULL },
-#ifdef USE_IEEE80211
-	{ "ssid",	NEXTARG,	set80211ssid,	NULL },
-	{ "nwid",	NEXTARG,	set80211ssid,	NULL },
-	{ "stationname", NEXTARG,	set80211stationname,	NULL },
-	{ "station",	NEXTARG,	set80211stationname,	NULL },	/* BSD/OS */
-	{ "channel",	NEXTARG,	set80211channel,	NULL },
-	{ "authmode",	NEXTARG,	set80211authmode,	NULL },
-	{ "powersavemode", NEXTARG,	set80211powersavemode,	NULL },
-	{ "powersave",	1,		set80211powersave,	NULL },
-	{ "-powersave",	0,		set80211powersave,	NULL },
-	{ "powersavesleep", NEXTARG,	set80211powersavesleep,	NULL },
-	{ "wepmode",	NEXTARG,	set80211wepmode,	NULL },
-	{ "wep",	1,		set80211wep,	NULL },
-	{ "-wep",	0,		set80211wep,	NULL },
-	{ "weptxkey",	NEXTARG,	set80211weptxkey,	NULL },
-	{ "wepkey",	NEXTARG,	set80211wepkey,	NULL },
-	{ "nwkey",	NEXTARG,	set80211nwkey,	NULL },	/* NetBSD */
-	{ "-nwkey",	0,		set80211wep,	NULL },		/* NetBSD */
-	{ "rtsthreshold",NEXTARG,	set80211rtsthreshold,	NULL },
-	{ "protmode",	NEXTARG,	set80211protmode,	NULL },
-	{ "txpower",	NEXTARG,	set80211txpower,	NULL },
-#endif
-	{ "rxcsum",	IFCAP_RXCSUM,	setifcap,	NULL },
-	{ "-rxcsum",	-IFCAP_RXCSUM,	setifcap,	NULL },
-	{ "txcsum",	IFCAP_TXCSUM,	setifcap,	NULL },
-	{ "-txcsum",	-IFCAP_TXCSUM,	setifcap,	NULL },
-	{ "netcons",	IFCAP_NETCONS,	setifcap,	NULL },
-	{ "-netcons",	-IFCAP_NETCONS,	setifcap,	NULL },
-	{ "vlanmtu",	IFCAP_VLAN_MTU,		setifcap,	NULL },
-	{ "-vlanmtu",	-IFCAP_VLAN_MTU,	setifcap,	NULL },
-	{ "vlanhwtag",	IFCAP_VLAN_HWTAGGING,	setifcap,	NULL },
-	{ "-vlanhwtag",	-IFCAP_VLAN_HWTAGGING,	setifcap,	NULL },
-	{ "normal",	-IFF_LINK0,	setifflags,	NULL },
-	{ "compress",	IFF_LINK0,	setifflags,	NULL },
-	{ "noicmp",	IFF_LINK1,	setifflags,	NULL },
-	{ "mtu",	NEXTARG,	setifmtu,	NULL },
-	{ "name",	NEXTARG,	setifname,	NULL },
-	{ NULL,		0,		setifaddr,	NULL },
-	{ NULL,		0,		setifdstaddr,	NULL },
-};
-
-/*
- * XNS support liberally adapted from code written at the University of
- * Maryland principally by James O'Toole and Chris Torek.
- */
-typedef	void af_status(int, struct rt_addrinfo *);
-typedef	void af_getaddr(const char *, int);
-typedef void af_getprefix(const char *, int);
-
-af_status	in_status, at_status, link_status;
-af_getaddr	in_getaddr, at_getaddr, link_getaddr;
-
-#ifndef NO_IPX
-af_status	ipx_status;
-af_getaddr	ipx_getaddr;
-#endif
+static struct afswtch *af_getbyname(const char *name);
+static struct afswtch *af_getbyfamily(int af);
+static void af_other_status(int);
 
-#ifdef INET6
-af_status	in6_status;
-af_getaddr	in6_getaddr;
-af_getprefix	in6_getprefix;
-#endif /*INET6*/
-#ifdef NS
-af_status	xns_status;
-af_getaddr	xns_getaddr;
-#endif
-
-/* Known address families */
-const
-struct	afswtch {
-	const char *af_name;
-	short af_af;
-	af_status *af_status;
-	af_getaddr *af_getaddr;
-	af_getprefix *af_getprefix;
-	u_long af_difaddr;
-	u_long af_aifaddr;
-	caddr_t af_ridreq;
-	caddr_t af_addreq;
-} afs[] = {
-#define C(x) ((caddr_t) &x)
-	{ "inet", AF_INET, in_status, in_getaddr, NULL,
-	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#ifdef INET6
-	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
-	     SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
-	     C(in6_ridreq), C(in6_addreq) },
-#endif /*INET6*/
-#ifndef NO_IPX
-	{ "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
-	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#endif
-	{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
-	     SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
-#ifdef NS
-	{ "ns", AF_NS, xns_status, xns_getaddr, NULL,
-	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#endif
-	{ "link", AF_LINK, link_status, link_getaddr, NULL,
-	     0, SIOCSIFLLADDR, NULL, C(ridreq) },
-	{ "ether", AF_LINK, link_status, link_getaddr, NULL,
-	     0, SIOCSIFLLADDR, NULL, C(ridreq) },
-	{ "lladdr", AF_LINK, link_status, link_getaddr, NULL,
-	     0, SIOCSIFLLADDR, NULL, C(ridreq) },
-	{ NULL,	0,	NULL, NULL, NULL,	0, 0,	NULL, NULL }
-};
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-
-#define ROUNDUP(a) \
-        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+static struct option *opts = NULL;
 
 void
-rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
+opt_register(struct option *p)
 {
-        struct sockaddr *sa;
-        int i;
-
-        memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-        for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-                if ((rtinfo->rti_addrs & (1 << i)) == 0)
-                        continue;
-                rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-                ADVANCE(cp, sa);
-        }
+	p->next = opts;
+	opts = p;
 }
 
-
-void
+static void
 usage(void)
 {
-#ifndef INET6
-	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-	"usage: ifconfig interface address_family [address [dest_address]]",
-	"                [parameters]",
-	"       ifconfig -C",
-	"       ifconfig interface create",
-	"       ifconfig -a [-d] [-m] [-u] [address_family]",
-	"       ifconfig -l [-d] [-u] [address_family]",
-	"       ifconfig [-d] [-m] [-u]");
-#else
-	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-	"usage: ifconfig [-L] interface address_family [address [dest_address]]",
-	"                [parameters]",
-	"       ifconfig -C",
-	"       ifconfig interface create",
-	"       ifconfig -a [-L] [-d] [-m] [-u] [address_family]",
-	"       ifconfig -l [-d] [-u] [address_family]",
-	"       ifconfig [-L] [-d] [-m] [-u]");
-#endif
+	char options[1024];
+	struct option *p;
+
+	/* XXX not right but close enough for now */
+	options[0] = '\0';
+	for (p = opts; p != NULL; p = p->next) {
+		strlcat(options, p->opt_usage, sizeof(options));
+		strlcat(options, " ", sizeof(options));
+	}
+
+	fprintf(stderr,
+	"usage: ifconfig %sinterface address_family [address [dest_address]]\n"
+	"                [parameters]\n"
+	"       ifconfig interface create\n"
+	"       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
+	"       ifconfig -l [-d] [-u] [address_family]\n"
+	"       ifconfig %s[-d] [-m] [-u] [-v]\n",
+		options, options, options);
 	exit(1);
 }
 
 int
-main(int argc, char * const *argv)
+main(int argc, char *argv[])
 {
-	int c;
-	int all, namesonly, downonly, uponly;
+	int c, all, namesonly, downonly, uponly;
 	int need_nl = 0, count = 0;
-	const struct afswtch *afp = 0;
+	const struct afswtch *afp = NULL;
 	int addrcount, ifindex;
-	struct	if_msghdr *ifm, *nextifm;
-	struct	ifa_msghdr *ifam;
-	struct	sockaddr_dl *sdl;
-	char	*buf, *lim, *next;
-
+	struct if_msghdr *ifm, *nextifm;
+	struct ifa_msghdr *ifam;
+	struct sockaddr_dl *sdl;
+	char *buf, *lim, *next;
 	size_t needed;
 	int mib[6];
+	char options[1024];
+	struct option *p;
+
+	all = downonly = uponly = namesonly = verbose = 0;
 
 	/* Parse leading line options */
-	all = downonly = uponly = namesonly = 0;
-	while ((c = getopt(argc, argv, "adlmuC"
-#ifdef INET6
-					"L"
-#endif
-			)) != -1) {
+	strlcpy(options, "adlmuv", sizeof(options));
+	for (p = opts; p != NULL; p = p->next)
+		strlcat(options, p->opt, sizeof(options));
+	while ((c = getopt(argc, argv, options)) != -1) {
 		switch (c) {
 		case 'a':	/* scan all interfaces */
 			all++;
@@ -459,32 +176,23 @@
 		case 'u':	/* restrict scan to "up" interfaces */
 			uponly++;
 			break;
-		case 'C':
-			listcloners = 1;
+		case 'v':
+			verbose++;
 			break;
-#ifdef INET6
-		case 'L':
-			ip6lifetime++;	/* print IPv6 address lifetime */
-			break;
-#endif
 		default:
-			usage();
+			for (p = opts; p != NULL; p = p->next)
+				if (p->opt[0] == c) {
+					p->cb(optarg);
+					break;
+				}
+			if (p == NULL)
+				usage();
 			break;
 		}
 	}
 	argc -= optind;
 	argv += optind;
 
-	if (listcloners) {
-		/* -C must be solitary */
-		if (all || supmedia || uponly || downonly || namesonly ||
-		    argc > 0)
-			usage();
-		
-		list_cloners();
-		exit(0);
-	}
-
 	/* -l cannot be used with -a or -m */
 	if (namesonly && (all || supmedia))
 		usage();
@@ -504,13 +212,11 @@
 
 		ifindex = 0;
 		if (argc == 1) {
-			for (afp = afs; afp->af_name; afp++)
-				if (strcmp(afp->af_name, *argv) == 0) {
-					argc--, argv++;
-					break;
-				}
-			if (afp->af_name == NULL)
+			afp = af_getbyname(*argv);
+			if (afp == NULL)
 				usage();
+			if (afp->af_name != NULL)
+				argc--, argv++;
 			/* leave with afp non-zero */
 		}
 	} else {
@@ -543,13 +249,9 @@
 
 	/* Check for address family */
 	if (argc > 0) {
-		for (afp = afs; afp->af_name; afp++)
-			if (strcmp(afp->af_name, *argv) == 0) {
-				argc--, argv++;
-				break;
-			}
-		if (afp->af_name == NULL)
-			afp = NULL;	/* not a family, NULL */
+		afp = af_getbyname(*argv);
+		if (afp != NULL)
+			argc--, argv++;
 	}
 
 retry:
@@ -561,7 +263,7 @@
 	mib[5] = ifindex;		/* interface index */
 
 	/* if particular family specified, only ask about it */
-	if (afp)
+	if (afp != NULL)
 		mib[3] = afp->af_af;
 
 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
@@ -586,10 +288,10 @@
 		
 		if (ifm->ifm_type == RTM_IFINFO) {
 #if  notyet
-			if (ifm->ifm_data.ifi_datalen == 0)
-				ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
-			sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
-			     sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
+                        if (ifm->ifm_data.ifi_datalen == 0)
+                                ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
+                        sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
+                             sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
 #else
                        sdl = (struct sockaddr_dl *)(ifm + 1);
 #endif
@@ -627,14 +329,6 @@
 		    sizeof(name)-1 : sdl->sdl_nlen] = '\0';
 
 		if (all || namesonly) {
-			size_t len;
-
-			/* sdl_data may not be terminated, don't use strlcpy */
-			if ((len = sdl->sdl_nlen) > sizeof(name) - 1)
-				len = sizeof(name) - 1;
-			bcopy(sdl->sdl_data, name, len);
-			name[len] = 0;
-
 			if (uponly)
 				if ((flags & IFF_UP) == 0)
 					continue; /* not up */
@@ -642,9 +336,8 @@
 				if (flags & IFF_UP)
 					continue; /* not down */
 			if (namesonly) {
-				if (afp == NULL ||
-					afp->af_status != link_status ||
-					sdl->sdl_type == IFT_ETHER) {
+				if (afp == NULL || afp->af_af != AF_LINK ||
+				    sdl->sdl_type == IFT_ETHER) {
 					if (need_nl)
 						putchar(' ');
 					fputs(name, stdout);
@@ -670,92 +363,192 @@
 	exit (0);
 }
 
+static struct afswtch *afs = NULL;
 
-int
+void
+af_register(struct afswtch *p)
+{
+	p->af_next = afs;
+	afs = p;
+}
+
+static struct afswtch *
+af_getbyname(const char *name)
+{
+	struct afswtch *afp;
+
+	for (afp = afs; afp !=  NULL; afp = afp->af_next)
+		if (strcmp(afp->af_name, name) == 0)
+			return afp;
+	return NULL;
+}
+
+static struct afswtch *
+af_getbyfamily(int af)
+{
+	struct afswtch *afp;
+
+	for (afp = afs; afp != NULL; afp = afp->af_next)
+		if (afp->af_af == af)
+			return afp;
+	return NULL;
+}
+
+static void
+af_other_status(int s)
+{
+	struct afswtch *afp;
+	uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+	memset(afmask, 0, sizeof(afmask));
+	for (afp = afs; afp != NULL; afp = afp->af_next) {
+		if (afp->af_other_status == NULL)
+			continue;
+		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+			continue;
+		afp->af_other_status(s);
+		setbit(afmask, afp->af_af);
+	}
+}
+
+static void
+af_all_tunnel_status(int s)
+{
+	struct afswtch *afp;
+	uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+	memset(afmask, 0, sizeof(afmask));
+	for (afp = afs; afp != NULL; afp = afp->af_next) {
+		if (afp->af_status_tunnel == NULL)
+			continue;
+		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+			continue;
+		afp->af_status_tunnel(s);
+		setbit(afmask, afp->af_af);
+	}
+}
+
+static struct cmd *cmds = NULL;
+
+void
+cmd_register(struct cmd *p)
+{
+	p->c_next = cmds;
+	cmds = p;
+}
+
+static const struct cmd *
+cmd_lookup(const char *name)
+{
+#define	N(a)	(sizeof(a)/sizeof(a[0]))
+	const struct cmd *p;
+
+	for (p = cmds; p != NULL; p = p->c_next)
+		if (strcmp(name, p->c_name) == 0)
+			return p;
+	return NULL;
+#undef N
+}
+
+struct callback {
+	callback_func *cb_func;
+	void	*cb_arg;
+	struct callback *cb_next;
+};
+static struct callback *callbacks = NULL;
+
+void
+callback_register(callback_func *func, void *arg)
+{
+	struct callback *cb;
+
+	cb = malloc(sizeof(struct callback));
+	if (cb == NULL)
+		errx(1, "unable to allocate memory for callback");
+	cb->cb_func = func;
+	cb->cb_arg = arg;
+	cb->cb_next = callbacks;
+	callbacks = cb;
+}
+
+/* specially-handled commands */
+static void setifaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
+
+static void setifdstaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifdstaddr_cmd =
+	DEF_CMD("ifdstaddr", 0, setifdstaddr);
+
+static int
 ifconfig(int argc, char *const *argv, const struct afswtch *afp)
 {
+	struct callback *cb;
 	int s;
 
 	if (afp == NULL)
-		afp = &afs[0];
-	ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
+		afp = af_getbyname("inet");
+	ifr.ifr_addr.sa_family =
+		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
+		AF_INET : afp->af_af;
 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
 
 	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
-		err(1, "socket");
+		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
 
 	while (argc > 0) {
 		const struct cmd *p;
 
-		for (p = cmds; p->c_name; p++)
-			if (strcmp(*argv, p->c_name) == 0)
-				break;
-		if (p->c_name == 0 && setaddr)
-			p++;	/* got src, do dst */
-		if (p->c_func || p->c_func2) {
+		p = cmd_lookup(*argv);
+		if (p == NULL) {
+			/*
+			 * Not a recognized command, choose between setting
+			 * the interface address and the dst address.
+			 */
+			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
+		}
+		if (p->c_u.c_func || p->c_u.c_func2) {
 			if (p->c_parameter == NEXTARG) {
 				if (argv[1] == NULL)
 					errx(1, "'%s' requires argument",
 					    p->c_name);
-				(*p->c_func)(argv[1], 0, s, afp);
+				p->c_u.c_func(argv[1], 0, s, afp);
 				argc--, argv++;
+			} else if (p->c_parameter == OPTARG) {
+				p->c_u.c_func(argv[1], 0, s, afp);
+				if (argv[1] != NULL)
+					argc--, argv++;
 			} else if (p->c_parameter == NEXTARG2) {
 				if (argc < 3)
 					errx(1, "'%s' requires 2 arguments",
 					    p->c_name);
-				(*p->c_func2)(argv[1], argv[2], s, afp);
+				p->c_u.c_func2(argv[1], argv[2], s, afp);
 				argc -= 2, argv += 2;
 			} else
-				(*p->c_func)(*argv, p->c_parameter, s, afp);
+				p->c_u.c_func(*argv, p->c_parameter, s, afp);
 		}
 		argc--, argv++;
 	}
-#ifdef INET6
-	if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) {
-		/* Aggregatable address architecture defines all prefixes
-		   are 64. So, it is convenient to set prefixlen to 64 if
-		   it is not specified. */
-		setifprefixlen("64", 0, s, afp);
-		/* in6_getprefix("64", MASK) if MASK is available here... */
-	}
-#endif
-#ifndef NO_IPX
-	if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
-		struct ipxip_req rq;
-		int size = sizeof(rq);
-
-		rq.rq_ipx = addreq.ifra_addr;
-		rq.rq_ip = addreq.ifra_dstaddr;
-
-		if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
-			Perror("Encapsulation Routing");
-	}
-#endif
-	if (ifr.ifr_addr.sa_family == AF_APPLETALK)
-		checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
-#ifdef NS
-	if (setipdst && ifr.ifr_addr.sa_family == AF_NS) {
-		struct nsip_req rq;
-		int size = sizeof(rq);
 
-		rq.rq_ns = addreq.ifra_addr;
-		rq.rq_ip = addreq.ifra_dstaddr;
-
-		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
-			Perror("Encapsulation Routing");
-	}
-#endif
+	/*
+	 * Do any post argument processing required by the address family.
+	 */
+	if (afp->af_postproc != NULL)
+		afp->af_postproc(s, afp);
+	/*
+	 * Do deferred operations.
+	 */
 	if (clearaddr) {
 		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
 			warnx("interface %s cannot change %s addresses!",
 			      name, afp->af_name);
-			clearaddr = NULL;
+			clearaddr = 0;
 		}
 	}
 	if (clearaddr) {
 		int ret;
 		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
-		if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
+		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
+		if (ret < 0) {
 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
 				/* means no previous address for interface */
 			} else
@@ -774,20 +567,23 @@
 		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
 			Perror("ioctl (SIOCAIFADDR)");
 	}
+
+	/*
+	 * Do deferred callbacks registered while processing
+	 * command-line arguments.
+	 */
+	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
+		cb->cb_func(s, cb->cb_arg);
+
 	close(s);
 	return(0);
 }
-#define RIDADDR 0
-#define ADDR	1
-#define MASK	2
-#define DSTADDR	3
 
 /*ARGSUSED*/
-void
-setifaddr(const char *addr, int param __unused, int s __unused,
-	  const struct afswtch *afp)
+static void
+setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
 {
-	if (*afp->af_getaddr == NULL)
+	if (afp->af_getaddr == NULL)
 		return;
 	/*
 	 * Delay the ioctl to set the interface addr until flags are all set.
@@ -797,21 +593,20 @@
 	setaddr++;
 	if (doalias == 0 && afp->af_af != AF_LINK)
 		clearaddr = 1;
-	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
+	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
 }
 
-void
+static void
 settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
 {
-	struct addrinfo hints, *srcres, *dstres;
-	struct ifaliasreq addr_req;
+	struct addrinfo *srcres, *dstres;
 	int ecode;
-#ifdef INET6
-	struct in6_aliasreq in6_addr_req; 
-#endif
 
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = afp->af_af;
+	if (afp->af_settunnel == NULL) {
+		warn("address family %s does not support tunnel setup",
+			afp->af_name);
+		return;
+	}
 
 	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
 		errx(1, "error in parsing address string: %s",
@@ -825,178 +620,58 @@
 		errx(1,
 		    "source and destination address families do not match");
 
-	switch (srcres->ai_addr->sa_family) {
-	case AF_INET:
-		memset(&addr_req, 0, sizeof(addr_req));
-		strncpy(addr_req.ifra_name, name, IFNAMSIZ);
-		memcpy(&addr_req.ifra_addr, srcres->ai_addr,
-		    srcres->ai_addr->sa_len);
-		memcpy(&addr_req.ifra_dstaddr, dstres->ai_addr,
-		    dstres->ai_addr->sa_len);
-
-		if (ioctl(s, SIOCSIFPHYADDR, &addr_req) < 0)
-			warn("SIOCSIFPHYADDR");
-		break;
-
-#ifdef INET6
-	case AF_INET6:
-		memset(&in6_addr_req, 0, sizeof(in6_addr_req));
-		strncpy(in6_addr_req.ifra_name, name, IFNAMSIZ);
-		memcpy(&in6_addr_req.ifra_addr, srcres->ai_addr,
-		    srcres->ai_addr->sa_len);
-		memcpy(&in6_addr_req.ifra_dstaddr, dstres->ai_addr,
-		    dstres->ai_addr->sa_len);
-
-		if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addr_req) < 0)
-			warn("SIOCSIFPHYADDR_IN6");
-		break;
-#endif /* INET6 */
-
-	default:
-		warn("address family not supported");
-	}
+	afp->af_settunnel(s, srcres, dstres);
 
 	freeaddrinfo(srcres);
 	freeaddrinfo(dstres);
 }
 
 /* ARGSUSED */
-void
-deletetunnel(const char *vname __unused, int param __unused, int s,
-	     const struct afswtch *afp __unused)
+static void
+deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
 {
+
 	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
 		err(1, "SIOCDIFPHYADDR");
 }
 
-void
-setifnetmask(const char *addr, int dummy __unused, int s __unused,
-             const struct afswtch *afp)
-{
-	if (*afp->af_getaddr == NULL)
-		return;
-	setmask++;
-	(*afp->af_getaddr)(addr, MASK);
-}
-
-#ifdef INET6
-void
-setifprefixlen(const char *addr, int dummy __unused, int s __unused,
-               const struct afswtch *afp)
-{
-        if (*afp->af_getprefix)
-                (*afp->af_getprefix)(addr, MASK);
-	explicit_prefix = 1;
-}
-
-void
-setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
-            const struct afswtch *afp)
-{
-	if (afp->af_af != AF_INET6)
-		err(1, "address flags can be set only for inet6 addresses");
-
-	if (flag < 0)
-		in6_addreq.ifra_flags &= ~(-flag);
-	else
-		in6_addreq.ifra_flags |= flag;
-}
-
-void
-setip6pltime(const char *seconds, int dummy __unused, int s,
-             const struct afswtch *afp)
+static void
+setifnetmask(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
 {
-	setip6lifetime("pltime", seconds, s, afp);
-}
-
-void
-setip6vltime(const char *seconds, int dummy __unused, int s,
-             const struct afswtch *afp)
-{
-	setip6lifetime("vltime", seconds, s, afp);
-}
-
-void
-setip6lifetime(const char *cmd, const char *val, int s __unused,
-               const struct afswtch *afp)
-{
-	time_t newval, t;
-	char *ep;
-
-	t = time(NULL);
-	newval = (time_t)strtoul(val, &ep, 0);
-	if (val == ep)
-		errx(1, "invalid %s", cmd);
-	if (afp->af_af != AF_INET6)
-		errx(1, "%s not allowed for the AF", cmd);
-	if (strcmp(cmd, "vltime") == 0) {
-		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
-		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
-	} else if (strcmp(cmd, "pltime") == 0) {
-		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
-		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+	if (afp->af_getaddr != NULL) {
+		setmask++;
+		afp->af_getaddr(addr, MASK);
 	}
 }
 
-void
-setip6eui64(const char *cmd, int dummy __unused, int s __unused,
-            const struct afswtch *afp)
+static void
+setifbroadaddr(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
 {
-	struct ifaddrs *ifap, *ifa;
-	const struct sockaddr_in6 *sin6 = NULL;
-	const struct in6_addr *lladdr = NULL;
-	struct in6_addr *in6;
-
-	if (afp->af_af != AF_INET6)
-		errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
- 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
-	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
-		errx(EXIT_FAILURE, "interface index is already filled");
-	if (getifaddrs(&ifap) != 0)
-		err(EXIT_FAILURE, "getifaddrs");
-	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-		if (ifa->ifa_addr->sa_family == AF_INET6 &&
-		    strcmp(ifa->ifa_name, name) == 0) {
-			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
-			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
-				lladdr = &sin6->sin6_addr;
-				break;
-			}
-		}
-	}
-	if (!lladdr)
-		errx(EXIT_FAILURE, "could not determine link local address"); 
-
- 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
-
-	freeifaddrs(ifap);
+	if (afp->af_getaddr != NULL)
+		afp->af_getaddr(addr, DSTADDR);
 }
-#endif
 
-void
-setifbroadaddr(const char *addr, int dummy __unused, int s __unused,
-               const struct afswtch *afp)
+static void
+setifipdst(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
 {
-	if (*afp->af_getaddr == NULL)
-		return;
-	(*afp->af_getaddr)(addr, DSTADDR);
-}
+	const struct afswtch *inet;
 
-void
-setifipdst(const char *addr, int dummy __unused, int s __unused,
-           const struct afswtch *afp __unused)
-{
-	in_getaddr(addr, DSTADDR);
+	inet = af_getbyname("inet");
+	if (inet == NULL)
+		return;
+	inet->af_getaddr(addr, DSTADDR);
 	setipdst++;
 	clearaddr = 0;
 	newaddr = 0;
 }
-#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
 
-void
-notealias(const char *addr __unused, int param, int s __unused,
-	  const struct afswtch *afp)
+static void
+notealias(const char *addr, int param, int s, const struct afswtch *afp)
 {
+#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
 	if (setaddr && doalias == 0 && param < 0)
 		if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
 			bcopy((caddr_t)rqtosa(af_addreq),
@@ -1008,16 +683,16 @@
 		newaddr = 0;
 	} else
 		clearaddr = 0;
+#undef rqtosa
 }
 
 /*ARGSUSED*/
-void
-setifdstaddr(const char *addr, int param __unused, int s __unused,
-             const struct afswtch *afp)
+static void
+setifdstaddr(const char *addr, int param __unused, int s, 
+    const struct afswtch *afp)
 {
-	if (*afp->af_getaddr == NULL)
-		return;
-	(*afp->af_getaddr)(addr, DSTADDR);
+	if (afp->af_getaddr != NULL)
+		afp->af_getaddr(addr, DSTADDR);
 }
 
 /*
@@ -1025,9 +700,8 @@
  * of the ifreq structure, which may confuse other parts of ifconfig.
  * Make a private copy so we can avoid that.
  */
-void
-setifflags(const char *vname, int value, int s,
-	   const struct afswtch *afp __unused)
+static void
+setifflags(const char *vname, int value, int s, const struct afswtch *afp)
 {
 	struct ifreq		my_ifr;
 
@@ -1052,8 +726,7 @@
 }
 
 void
-setifcap(const char *vname, int value, int s,
-	 const struct afswtch *afp __unused)
+setifcap(const char *vname, int value, int s, const struct afswtch *afp)
 {
 
  	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
@@ -1071,9 +744,9 @@
 		Perror(vname);
 }
 
-void
-setifmetric(const char *val, int dummy __unused, int s,
-            const struct afswtch *afp __unused)
+static void
+setifmetric(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
 {
 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
 	ifr.ifr_metric = atoi(val);
@@ -1081,9 +754,9 @@
 		warn("ioctl (set metric)");
 }
 
-void
-setifmtu(const char *val, int dummy __unused, int s,
-	 const struct afswtch *afp __unused)
+static void
+setifmtu(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
 {
 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
 	ifr.ifr_mtu = atoi(val);
@@ -1091,14 +764,17 @@
 		warn("ioctl (set mtu)");
 }
 
-void
+static void
 setifname(const char *val, int dummy __unused, int s, 
-	  const struct afswtch *afp __unused)
+    const struct afswtch *afp)
 {
-	char	*newname;
+	char *newname;
 
 	newname = strdup(val);
-	
+	if (newname == NULL) {
+		warn("no memory to set ifname");
+		return;
+	}
 	ifr.ifr_data = newname;
 	if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
 		warn("ioctl (set name)");
@@ -1106,7 +782,6 @@
 		return;
 	}
 	strlcpy(name, newname, sizeof(name));
-
 	free(newname);
 
 	/*
@@ -1116,38 +791,62 @@
 	printname = 0;
 }
 
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+#define SA_SIZE(sa)                                             \
+	(  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
+	sizeof(long)            :                               \
+	1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
+
+static void
+rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
+{
+	struct sockaddr *sa;
+	int i;
+
+	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+		if ((rtinfo->rti_addrs & (1 << i)) == 0)
+			continue;
+		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+		cp += SA_SIZE(sa);
+	}
+}
+
 #define	IFFBITS \
 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
 "\20MULTICAST\21POLLING\23MONITOR\24STATICARP"
 
 #define	IFCAPBITS \
-"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING"
+"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU"
 
 /*
  * Print the status of the interface.  If an address family was
- * specified, show it and it only; otherwise, show them all.
+ * specified, show only it; otherwise, show them all.
  */
-void
-status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
-       struct if_msghdr *ifm, struct ifa_msghdr *ifam)
+static void
+status(const struct afswtch *afp, int addrcount, struct	sockaddr_dl *sdl,
+    struct if_msghdr *ifm, struct ifa_msghdr *ifam)
 {
-	const struct afswtch *p = NULL;
 	struct	rt_addrinfo info;
 	int allfamilies, s;
 	struct ifstat ifs;
 
 	if (afp == NULL) {
 		allfamilies = 1;
-		afp = &afs[0];
+		afp = af_getbyname("inet");
 	} else
 		allfamilies = 0;
 
 	ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
-	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
 
-	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
-		err(1, "socket");
+	s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+	if (s < 0)
+		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
 
 	printf("%s: ", name);
 	printb("flags", flags, IFFBITS);
@@ -1163,8 +862,7 @@
 			putchar('\n');
 		}
 		if (supmedia && ifr.ifr_reqcap != 0) {
-			printf("\tcapability list:\n");
-			printb("\t\t", ifr.ifr_reqcap, IFCAPBITS);
+			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
 			putchar('\n');
 		}
 	}
@@ -1172,395 +870,53 @@
 	tunnel_status(s);
 
 	while (addrcount > 0) {
-		
 		info.rti_addrs = ifam->ifam_addrs;
-
 		/* Expand the compacted addresses */
 		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
 			  &info);
 
-		if (!allfamilies) {
-			if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) {
-				p = afp;
-				(*p->af_status)(s, &info);
-			}
-		} else for (p = afs; p->af_name; p++) {
-			if (p->af_af == info.rti_info[RTAX_IFA]->sa_family)
-				(*p->af_status)(s, &info);
-		}
+		if (allfamilies) {
+			const struct afswtch *p;
+			p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family);
+			if (p != NULL)
+				p->af_status(s, &info);
+		} else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family)
+			afp->af_status(s, &info);
 		addrcount--;
 		ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
 	}
-	if (allfamilies || afp->af_status == link_status)
-		link_status(s, (struct rt_addrinfo *)sdl);
-#ifdef USE_IF_MEDIA
-	if (allfamilies || afp->af_status == media_status)
-		media_status(s, NULL);
-#endif
-#ifdef USE_VLANS
-	if (allfamilies || afp->af_status == vlan_status)
-		vlan_status(s, NULL);
-#endif
-#ifdef USE_IEEE80211
-	if (allfamilies || afp->af_status == ieee80211_status)
-		ieee80211_status(s, NULL);
-#endif
-	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
-	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
-		printf("%s", ifs.ascii);
-
-	if (!allfamilies && !p &&
-#ifdef USE_IF_MEDIA
-	    afp->af_status != media_status &&
-#endif
-	    afp->af_status != link_status
-#ifdef USE_VLANS
-	    && afp->af_status != vlan_status
-#endif
-		)
-		warnx("%s has no %s interface address!", name, afp->af_name);
-
-	close(s);
-	return;
-}
-
-void
-tunnel_status(int s)
-{
-	char psrcaddr[NI_MAXHOST];
-	char pdstaddr[NI_MAXHOST];
-	u_long srccmd, dstcmd;
-	struct ifreq *ifrp;
-	const char *ver = "";
-#ifdef NI_WITHSCOPEID
-	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
-#else
-	const int niflag = NI_NUMERICHOST;
-#endif
-#ifdef INET6
-	struct in6_ifreq in6_ifr;
-	int s6;
-#endif /* INET6 */
-
-	psrcaddr[0] = pdstaddr[0] = '\0';
-
-#ifdef INET6
-	memset(&in6_ifr, 0, sizeof(in6_ifr));
-	strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
-	s6 = socket(AF_INET6, SOCK_DGRAM, 0);
-	if (s6 < 0) {
-		srccmd = SIOCGIFPSRCADDR;
-		dstcmd = SIOCGIFPDSTADDR;
-		ifrp = &ifr;
-	} else {
-		close(s6);
-		srccmd = SIOCGIFPSRCADDR_IN6;
-		dstcmd = SIOCGIFPDSTADDR_IN6;
-		ifrp = (struct ifreq *)&in6_ifr;
-	}
-#else /* INET6 */
-	srccmd = SIOCGIFPSRCADDR;
-	dstcmd = SIOCGIFPDSTADDR;
-	ifrp = &ifr;
-#endif /* INET6 */
-
-	if (ioctl(s, srccmd, (caddr_t)ifrp) < 0)
-		return;
-#if defined(INET6) && defined(__KAME__) && defined(KAME_SCOPEID)
-	if (ifrp->ifr_addr.sa_family == AF_INET6)
-		in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
-#endif
-	getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
-	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
-#ifdef INET6
-	if (ifrp->ifr_addr.sa_family == AF_INET6)
-		ver = "6";
-#endif
-
-	if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0)
-		return;
-#if defined(INET6) && defined(__KAME__) && defined(KAME_SCOPEID)
-	if (ifrp->ifr_addr.sa_family == AF_INET6)
-		in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
-#endif
-	getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
-	    pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
-
-	printf("\ttunnel inet%s %s --> %s\n", ver,
-	    psrcaddr, pdstaddr);
-}
-
-void
-in_status(int s __unused, struct rt_addrinfo *info)
-{
-	struct sockaddr_in *addr_in, null_in;
-
-	memset(&null_in, 0, sizeof(null_in));
-
-	addr_in = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
-	printf("\tinet %s ", inet_ntoa(addr_in->sin_addr));
-
-	if (flags & IFF_POINTOPOINT) {
-		/* note RTAX_BRD overlap with IFF_BROADCAST */
-		addr_in = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
-		if (!addr_in)
-			addr_in = &null_in;
-		printf("--> %s ", inet_ntoa(addr_in->sin_addr));
-	}
-
-	addr_in = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
-	if (!addr_in)
-		addr_in = &null_in;
-	printf("netmask 0x%lx ",
-	       (unsigned long)ntohl(addr_in->sin_addr.s_addr));
-
-	if (flags & IFF_BROADCAST) {
-		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
-		addr_in = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
-		if (addr_in && addr_in->sin_addr.s_addr != 0)
-			printf("broadcast %s", inet_ntoa(addr_in->sin_addr));
-	}
-	putchar('\n');
-}
-
-#ifdef INET6
-#if defined(__KAME__) && defined(KAME_SCOPEID)
-void
-in6_fillscopeid(struct sockaddr_in6 *sin6 __unused)
-{
-	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
-		sin6->sin6_scope_id =
-			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
-		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
-	}
-}
-#endif /* defined(__KAME__) && defined(KAME_SCOPEID) */
-
-void
-in6_status(int s __unused, struct rt_addrinfo *info)
-{
-	struct sockaddr_in6 *addr_in, null_in;
-	struct in6_ifreq ifr6;
-	int s6;
-	u_int32_t flags6;
-	struct in6_addrlifetime lifetime;
-	time_t t = time(NULL);
-	int error;
-	u_int32_t scopeid;
-
-	memset(&null_in, 0, sizeof(null_in));
-
-	addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
-	strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
-	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
-		perror("ifconfig: socket");
-		return;
-	}
-	ifr6.ifr_addr = *addr_in;
-	if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
-		perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)");
-		close(s6);
-		return;
-	}
-	flags6 = ifr6.ifr_ifru.ifru_flags6;
-	memset(&lifetime, 0, sizeof(lifetime));
-	ifr6.ifr_addr = *addr_in;
-	if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
-		perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)");
-		close(s6);
-		return;
-	}
-	lifetime = ifr6.ifr_ifru.ifru_lifetime;
-	close(s6);
+	if (allfamilies || afp->af_af == AF_LINK) {
+		const struct afswtch *lafp;
 
-	/* XXX: embedded link local addr check */
-	if (IN6_IS_ADDR_LINKLOCAL(&addr_in->sin6_addr) &&
-	    *(u_short *)&addr_in->sin6_addr.s6_addr[2] != 0) {
-		u_short idx;
-
-		idx = *(u_short *)&addr_in->sin6_addr.s6_addr[2];
-		*(u_short *)&addr_in->sin6_addr.s6_addr[2] = 0;
-		if (addr_in->sin6_scope_id == 0)
-			addr_in->sin6_scope_id = ntohs(idx);
-	}
-	scopeid = addr_in->sin6_scope_id;
-
-	error = getnameinfo((struct sockaddr *)addr_in, addr_in->sin6_len, addr_buf,
-			    sizeof(addr_buf), NULL, 0,
-			    NI_NUMERICHOST|NI_WITHSCOPEID);
-	if (error != 0)
-		inet_ntop(AF_INET6, &addr_in->sin6_addr, addr_buf,
-			  sizeof(addr_buf));
-	printf("\tinet6 %s ", addr_buf);
-
-	if (flags & IFF_POINTOPOINT) {
-		/* note RTAX_BRD overlap with IFF_BROADCAST */
-		addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
 		/*
-		 * some of the interfaces do not have valid destination
-		 * address.
+		 * Hack; the link level address is received separately
+		 * from the routing information so any address is not
+		 * handled above.  Cobble together an entry and invoke
+		 * the status method specially.
 		 */
-		if (addr_in && addr_in->sin6_family == AF_INET6) {
-			/* XXX: embedded link local addr check */
-			if (IN6_IS_ADDR_LINKLOCAL(&addr_in->sin6_addr) &&
-			    *(u_short *)&addr_in->sin6_addr.s6_addr[2] != 0) {
-				u_short idx;
-
-				idx = *(u_short *)&addr_in->sin6_addr.s6_addr[2];
-				*(u_short *)&addr_in->sin6_addr.s6_addr[2] = 0;
-				if (addr_in->sin6_scope_id == 0)
-					addr_in->sin6_scope_id = ntohs(idx);
-			}
-
-			error = getnameinfo((struct sockaddr *)addr_in,
-					    addr_in->sin6_len, addr_buf,
-					    sizeof(addr_buf), NULL, 0,
-					    NI_NUMERICHOST|NI_WITHSCOPEID);
-			if (error != 0)
-				inet_ntop(AF_INET6, &addr_in->sin6_addr, addr_buf,
-					  sizeof(addr_buf));
-			printf("--> %s ", addr_buf);
+		lafp = af_getbyname("lladdr");
+		if (lafp != NULL) {
+			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
+			lafp->af_status(s, &info);
 		}
 	}
+	if (allfamilies)
+		af_other_status(s);
+		afp->af_other_status(s);
 
-	addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
-	if (!addr_in)
-		addr_in = &null_in;
-	printf("prefixlen %d ", prefix(&addr_in->sin6_addr,
-		sizeof(struct in6_addr)));
-
-	if ((flags6 & IN6_IFF_ANYCAST) != 0)
-		printf("anycast ");
-	if ((flags6 & IN6_IFF_TENTATIVE) != 0)
-		printf("tentative ");
-	if ((flags6 & IN6_IFF_DUPLICATED) != 0)
-		printf("duplicated ");
-	if ((flags6 & IN6_IFF_DETACHED) != 0)
-		printf("detached ");
-	if ((flags6 & IN6_IFF_DEPRECATED) != 0)
-		printf("deprecated ");
-	if ((flags6 & IN6_IFF_AUTOCONF) != 0)
-		printf("autoconf ");
-	if ((flags6 & IN6_IFF_TEMPORARY) != 0)
-		printf("temporary ");
-
-        if (scopeid)
-		printf("scopeid 0x%x ", scopeid);
-
-	if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
-		printf("pltime ");
-		if (lifetime.ia6t_preferred) {
-			printf("%s ", lifetime.ia6t_preferred < t
-				? "0" : sec2str(lifetime.ia6t_preferred - t));
-		} else
-			printf("infty ");
-
-		printf("vltime ");
-		if (lifetime.ia6t_expire) {
-			printf("%s ", lifetime.ia6t_expire < t
-				? "0" : sec2str(lifetime.ia6t_expire - t));
-		} else
-			printf("infty ");
-	}
-
-	putchar('\n');
-}
-#endif /*INET6*/
-
-#ifndef NO_IPX
-void
-ipx_status(int s __unused, struct rt_addrinfo *info)
-{
-	struct sockaddr_ipx *sipx, null_sipx;
-
-	memset(&null_sipx, 0, sizeof(null_sipx));
-
-	sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
-	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
-
-	if (flags & IFF_POINTOPOINT) {
-		sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
-		if (!sipx)
-			sipx = &null_sipx;
-		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
-	}
-	putchar('\n');
-}
-#endif
-
-void
-at_status(int s __unused, struct rt_addrinfo *info)
-{
-	struct sockaddr_at *sat, null_sat;
-	struct netrange *nr;
-
-	memset(&null_sat, 0, sizeof(null_sat));
-
-	sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
-	nr = &sat->sat_range.r_netrange;
-	printf("\tatalk %d.%d range %d-%d phase %d",
-		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
-		ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
-	if (flags & IFF_POINTOPOINT) {
-		/* note RTAX_BRD overlap with IFF_BROADCAST */
-		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
-		if (!sat)
-			sat = &null_sat;
-		printf("--> %d.%d",
-			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
-	}
-	if (flags & IFF_BROADCAST) {
-		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
-		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
-		if (sat)
-			printf(" broadcast %d.%d",
-				ntohs(sat->sat_addr.s_net),
-				sat->sat_addr.s_node);
-	}
-
-	putchar('\n');
-}
-
-#ifdef NS
-void
-xns_status(int s __unused, struct rt_addrinfo *info)
-{
-	struct sockaddr_ns *sns, null_sns;
-
-	memset(&null_sns, 0, sizeof(null_sns));
-
-	sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA];
-	printf("\tns %s ", ns_ntoa(sns->sns_addr));
-
-	if (flags & IFF_POINTOPOINT) {
-		sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD];
-		if (!sns)
-			sns = &null_sns;
-		printf("--> %s ", ns_ntoa(sns->sns_addr));
-	}
+	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
+		printf("%s", ifs.ascii);
 
-	putchar('\n');
 	close(s);
+	return;
 }
-#endif
-
 
-void
-link_status(int s __unused, struct rt_addrinfo *info)
+static void
+tunnel_status(int s)
 {
-	struct sockaddr_dl *sdl = (struct sockaddr_dl *)info;
-
-	if (sdl->sdl_alen > 0) {
-		if (sdl->sdl_type == IFT_ETHER &&
-		    sdl->sdl_alen == ETHER_ADDR_LEN)
-			printf("\tether %s\n",
-			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
-		else {
-			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
-
-			printf("\tlladdr %s\n", link_ntoa(sdl) + n);
-		}
-	}
+	af_all_tunnel_status(s);
 }
 
 void
@@ -1581,116 +937,6 @@
 	}
 }
 
-#define SIN(x) ((struct sockaddr_in *) &(x))
-struct sockaddr_in *sintab[] = {
-SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
-SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
-
-void
-in_getaddr(const char *s, int which)
-{
-	struct sockaddr_in *addr_in = sintab[which];
-	struct hostent *hp;
-	struct netent *np;
-
-	addr_in->sin_len = sizeof(*addr_in);
-	if (which != MASK)
-		addr_in->sin_family = AF_INET;
-
-	if (which == ADDR) {
-		char *p = NULL;
-
-		if((p = strrchr(s, '/')) != NULL) {
-			/* address is `name/masklen' */
-			int masklen;
-			int ret;
-			struct sockaddr_in *min = sintab[MASK];
-			*p = '\0';
-			ret = sscanf(p+1, "%u", &masklen);
-			if(ret != 1 || (masklen < 0 || masklen > 32)) {
-				*p = '/';
-				errx(1, "%s: bad value", s);
-			}
-			min->sin_len = sizeof(*min);
-			min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 
-				              0xffffffff);
-		}
-	}
-
-	if (inet_aton(s, &addr_in->sin_addr))
-		return;
-	if ((hp = gethostbyname(s)) != 0)
-		bcopy(hp->h_addr, (char *)&addr_in->sin_addr, 
-		    MIN((size_t)hp->h_length, sizeof(addr_in->sin_addr)));
-	else if ((np = getnetbyname(s)) != 0)
-		addr_in->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
-	else
-		errx(1, "%s: bad value", s);
-}
-
-#ifdef INET6
-#define	SIN6(x) ((struct sockaddr_in6 *) &(x))
-struct	sockaddr_in6 *sin6tab[] = {
-SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
-SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
-
-void
-in6_getaddr(const char *s, int which)
-{
-	struct sockaddr_in6 *addr_in = sin6tab[which];
-	struct addrinfo hints, *res;
-	int error = -1;
-
-	newaddr &= 1;
-
-	addr_in->sin6_len = sizeof(*addr_in);
-	if (which != MASK)
-		addr_in->sin6_family = AF_INET6;
-
-	if (which == ADDR) {
-		char *p = NULL;
-		if((p = strrchr(s, '/')) != NULL) {
-			*p = '\0';
-			in6_getprefix(p + 1, MASK);
-			explicit_prefix = 1;
-		}
-	}
-
-	if (addr_in->sin6_family == AF_INET6) {
-		bzero(&hints, sizeof(struct addrinfo));
-		hints.ai_family = AF_INET6;
-		error = getaddrinfo(s, NULL, &hints, &res);
-	}
-	if (error != 0) {
-		if (inet_pton(AF_INET6, s, &addr_in->sin6_addr) != 1)
-			errx(1, "%s: bad value", s);
-	} else
-		bcopy(res->ai_addr, addr_in, res->ai_addrlen);
-}
-
-void
-in6_getprefix(const char *plen, int which)
-{
-	struct sockaddr_in6 *addr_in = sin6tab[which];
-	u_char *cp;
-	int len = atoi(plen);
-
-	if ((len < 0) || (len > 128))
-		errx(1, "%s: bad value", plen);
-	addr_in->sin6_len = sizeof(*addr_in);
-	if (which != MASK)
-		addr_in->sin6_family = AF_INET6;
-	if ((len == 0) || (len == 128)) {
-		memset(&addr_in->sin6_addr, 0xff, sizeof(struct in6_addr));
-		return;
-	}
-	memset((void *)&addr_in->sin6_addr, 0x00, sizeof(addr_in->sin6_addr));
-	for (cp = (u_char *)&addr_in->sin6_addr; len > 7; len -= 8)
-		*cp++ = 0xff;
-	*cp = 0xff << (8 - len);
-}
-#endif
-
 /*
  * Print a value a la the %b format of the kernel's printf
  */
@@ -1722,200 +968,16 @@
 	}
 }
 
-#ifndef NO_IPX
-#define SIPX(x) ((struct sockaddr_ipx *) &(x))
-struct sockaddr_ipx *sipxtab[] = {
-SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
-SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
-
-void
-ipx_getaddr(const char *addr, int which)
-{
-	struct sockaddr_ipx *sipx = sipxtab[which];
-
-	sipx->sipx_family = AF_IPX;
-	sipx->sipx_len = sizeof(*sipx);
-	sipx->sipx_addr = ipx_addr(addr);
-	if (which == MASK)
-		printf("Attempt to set IPX netmask will be ineffectual\n");
-}
-#endif
-
-void
-at_getaddr(const char *addr, int which)
-{
-	struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
-	u_int net, node;
-
-	sat->sat_family = AF_APPLETALK;
-	sat->sat_len = sizeof(*sat);
-	if (which == MASK)
-		errx(1, "AppleTalk does not use netmasks");
-	if (sscanf(addr, "%u.%u", &net, &node) != 2
-	    || net > 0xffff || node > 0xfe)
-		errx(1, "%s: illegal address", addr);
-	sat->sat_addr.s_net = htons(net);
-	sat->sat_addr.s_node = node;
-}
-
-void
-link_getaddr(const char *addr, int which)
-{
-	char *temp;
-	struct sockaddr_dl sdl;
-	struct sockaddr *sa = &ridreq.ifr_addr;
-
-	if (which != ADDR)
-		errx(1, "can't set link-level netmask or broadcast");
-	if ((temp = malloc(strlen(addr) + 1)) == NULL)
-		errx(1, "malloc failed");
-	temp[0] = ':';
-	strcpy(temp + 1, addr);
-	sdl.sdl_len = sizeof(sdl);
-	link_addr(temp, &sdl);
-	free(temp);
-	if (sdl.sdl_alen > sizeof(sa->sa_data))
-		errx(1, "malformed link-level address");
-	sa->sa_family = AF_LINK;
-	sa->sa_len = sdl.sdl_alen;
-	bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
-}
-
-/* XXX  FIXME -- should use strtoul for better parsing. */
-void
-setatrange(const char *range, int dummy __unused, int s __unused,
-           const struct afswtch *afp __unused)
-{
-	u_int	first = 123, last = 123;
-
-	if (sscanf(range, "%u-%u", &first, &last) != 2
-	    || first == 0 || first > 0xffff
-	    || last == 0 || last > 0xffff || first > last)
-		errx(1, "%s: illegal net range: %u-%u", range, first, last);
-	at_nr.nr_firstnet = htons(first);
-	at_nr.nr_lastnet = htons(last);
-}
-
-void
-setatphase(const char *phase, int dummy __unused, int s __unused,
-           const struct afswtch *afp __unused)
-{
-	if (!strcmp(phase, "1"))
-		at_nr.nr_phase = 1;
-	else if (!strcmp(phase, "2"))
-		at_nr.nr_phase = 2;
-	else
-		errx(1, "%s: illegal phase", phase);
-}
-
-void
-checkatrange(struct sockaddr_at *sat)
-{
-	if (at_nr.nr_phase == 0)
-		at_nr.nr_phase = 2;	/* Default phase 2 */
-	if (at_nr.nr_firstnet == 0)
-		at_nr.nr_firstnet =	/* Default range of one */
-		at_nr.nr_lastnet = sat->sat_addr.s_net;
-printf("\tatalk %d.%d range %d-%d phase %d\n",
-	ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
-	ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
-	if ((u_short) ntohs(at_nr.nr_firstnet) >
-			(u_short) ntohs(sat->sat_addr.s_net)
-		    || (u_short) ntohs(at_nr.nr_lastnet) <
-			(u_short) ntohs(sat->sat_addr.s_net))
-		errx(1, "AppleTalk address is not in range");
-	sat->sat_range.r_netrange = at_nr;
-}
-
-#ifdef NS
-#define SNS(x) ((struct sockaddr_ns *) &(x))
-struct sockaddr_ns *snstab[] = {
-SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
-SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
-
-void
-xns_getaddr(const char *addr, int which)
-{
-	struct sockaddr_ns *sns = snstab[which];
-
-	sns->sns_family = AF_NS;
-	sns->sns_len = sizeof(*sns);
-	sns->sns_addr = ns_addr(addr);
-	if (which == MASK)
-		printf("Attempt to set XNS netmask will be ineffectual\n");
-}
-#endif
-
-#ifdef INET6
-int
-prefix(void *val, int size)
-{
-	u_char *addr = (u_char *)val;
-	int byte, bit, plen = 0;
-
-        for (byte = 0; byte < size; byte++, plen += 8)
-		if (addr[byte] != 0xff)
-                        break;
-	if (byte == size)
-		return (plen);
-	for (bit = 7; bit != 0; bit--, plen++)
-                if (!(addr[byte] & (1 << bit)))
-                        break;
-        for (; bit != 0; bit--)
-                if (addr[byte] & (1 << bit))
-                        return(0);
-        byte++;
-        for (; byte < size; byte++)
-                if (addr[byte])
-                        return(0);
-        return (plen);
-}
-
-static char *
-sec2str(time_t total)
-{
-	static char result[256];
-	int days, hours, mins, secs;
-	int first = 1;
-	char *p = result;
-
-	if (0) {
-		days = total / 3600 / 24;
-		hours = (total / 3600) % 24;
-		mins = (total / 60) % 60;
-		secs = total % 60;
-
-		if (days) {
-			first = 0;
-			p += sprintf(p, "%dd", days);
-		}
-		if (!first || hours) {
-			first = 0;
-			p += sprintf(p, "%dh", hours);
-		}
-		if (!first || mins) {
-			first = 0;
-			p += sprintf(p, "%dm", mins);
-		}
-		sprintf(p, "%ds", secs);
-	} else
-		sprintf(result, "%lu", (unsigned long)total);
-
-	return(result);
-}
-#endif /*INET6*/
-
 void
-ifmaybeload(char *if_nm)
+ifmaybeload(char *name)
 {
 	struct module_stat mstat;
 	int fileid, modid;
 	char ifkind[35], *cp, *dp;
 
-
 	/* turn interface and unit into module name */
 	strcpy(ifkind, "if_");
-	for (cp = if_nm, dp = ifkind + 3;
+	for (cp = name, dp = ifkind + 3;
 	    (*cp != 0) && !isdigit(*cp); cp++, dp++)
 		*dp = *cp;
 	*dp = 0;
@@ -1935,8 +997,8 @@
 				cp = mstat.name;
 			}
 			/* already loaded? */
-			if (strncmp(if_nm, cp, strlen(cp)) == 0 ||
-				strncmp(ifkind, cp, strlen(cp)) == 0)
+			if (strncmp(name, cp, strlen(cp)) == 0 ||
+			    strncmp(ifkind, cp, strlen(cp)) == 0)
 				return;
 		}
 	}
@@ -1945,87 +1007,61 @@
 	kldload(ifkind);
 }
 
-void
-list_cloners(void)
-{
-	struct if_clonereq ifcr;
-	char *cp, *buf;
-	int idx;
-	int s;
-
-	s = socket(AF_INET, SOCK_DGRAM, 0);
-	if (s == -1)
-		err(1, "socket");
-
-	memset(&ifcr, 0, sizeof(ifcr));
-
-	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
-		err(1, "SIOCIFGCLONERS for count");
-
-	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
-	if (buf == NULL)
-		err(1, "unable to allocate cloner name buffer");
-
-	ifcr.ifcr_count = ifcr.ifcr_total;
-	ifcr.ifcr_buffer = buf;
-
-	if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
-		err(1, "SIOCIFGCLONERS for names");
-
-	/*
-	 * In case some disappeared in the mean time, clamp it down.
-	 */
-	if (ifcr.ifcr_count > ifcr.ifcr_total)
-		ifcr.ifcr_count = ifcr.ifcr_total;
-
-	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
-		if (idx &g