[rtems-libbsd commit] Added the ifconfig command.

Jennifer Averett jennifer at rtems.org
Fri Sep 7 18:12:26 UTC 2012


Module:    rtems-libbsd
Branch:    master
Commit:    ebbe3cc71f18159cf021192241a2a7a397fff4f8
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=ebbe3cc71f18159cf021192241a2a7a397fff4f8

Author:    Jennifer Averett <jennifer.averett at oarcorp.com>
Date:      Fri Sep  7 13:16:22 2012 -0500

Added the ifconfig command.

---

 freebsd-userspace/Makefile                         |   29 +
 .../commands/sbin/ifconfig/af_atalk.c              |  182 +
 freebsd-userspace/commands/sbin/ifconfig/af_inet.c |  213 +
 .../commands/sbin/ifconfig/af_inet6.c              |  556 ++
 freebsd-userspace/commands/sbin/ifconfig/af_ipx.c  |  122 +
 freebsd-userspace/commands/sbin/ifconfig/af_link.c |  133 +
 freebsd-userspace/commands/sbin/ifconfig/af_nd6.c  |  238 +
 .../commands/sbin/ifconfig/ifbridge.c              |  767 +++
 freebsd-userspace/commands/sbin/ifconfig/ifcarp.c  |  204 +
 freebsd-userspace/commands/sbin/ifconfig/ifclone.c |  198 +
 .../commands/sbin/ifconfig/ifconfig.8              | 2555 ++++++++++
 .../commands/sbin/ifconfig/ifconfig.c              | 1185 +++++
 .../commands/sbin/ifconfig/ifconfig.h              |  154 +
 freebsd-userspace/commands/sbin/ifconfig/ifgif.c   |  138 +
 freebsd-userspace/commands/sbin/ifconfig/ifgre.c   |  102 +
 freebsd-userspace/commands/sbin/ifconfig/ifgroup.c |  186 +
 .../commands/sbin/ifconfig/ifieee80211.c           | 5295 ++++++++++++++++++++
 freebsd-userspace/commands/sbin/ifconfig/iflagg.c  |  198 +
 freebsd-userspace/commands/sbin/ifconfig/ifmac.c   |  125 +
 freebsd-userspace/commands/sbin/ifconfig/ifmedia.c |  844 ++++
 .../commands/sbin/ifconfig/ifpfsync.c              |  220 +
 freebsd-userspace/commands/sbin/ifconfig/ifvlan.c  |  210 +
 .../commands/sbin/ifconfig/regdomain.c             |  705 +++
 .../commands/sbin/ifconfig/regdomain.h             |  126 +
 freebsd-userspace/from-freebsd.sh                  |    1 +
 freebsd-userspace/include/sys/mman.h               |    3 +
 26 files changed, 14689 insertions(+), 0 deletions(-)

diff --git a/freebsd-userspace/Makefile b/freebsd-userspace/Makefile
index 8e5cc2f..8e8adee 100644
--- a/freebsd-userspace/Makefile
+++ b/freebsd-userspace/Makefile
@@ -107,6 +107,35 @@ C_FILES += commands/sbin/dhclient/privsep.c
 C_FILES += commands/sbin/dhclient/tables.c
 C_FILES += commands/sbin/dhclient/tree.c
 
+# ifconfig command sources
+C_FILES += commands/sbin/ifconfig/af_atalk.c
+C_FILES += commands/sbin/ifconfig/af_inet.c
+C_FILES += commands/sbin/ifconfig/af_link.c
+C_FILES += commands/sbin/ifconfig/ifbridge.c
+C_FILES += commands/sbin/ifconfig/ifclone.c
+C_FILES += commands/sbin/ifconfig/ifgif.c
+C_FILES += commands/sbin/ifconfig/ifgroup.c
+C_FILES += commands/sbin/ifconfig/iflagg.c
+C_FILES += commands/sbin/ifconfig/ifmedia.c
+C_FILES += commands/sbin/ifconfig/ifvlan.c
+C_FILES += commands/sbin/ifconfig/af_inet6.c
+C_FILES += commands/sbin/ifconfig/af_nd6.c
+C_FILES += commands/sbin/ifconfig/ifcarp.c
+C_FILES += commands/sbin/ifconfig/ifconfig.c
+C_FILES += commands/sbin/ifconfig/ifgre.c
+C_FILES += commands/sbin/ifconfig/ifieee80211.c
+C_FILES += commands/sbin/ifconfig/ifmac.c
+C_FILES += commands/sbin/ifconfig/ifpfsync.c
+
+# The following two files were left out to avoid
+# porting issues.  regdomain uses an xml parser
+# that is not part of the standard release and
+# af_ipx uses thread0 which we are trying to avoid
+# pulling in.
+#
+# C_FILES += commands/sbin/ifconfig/regdomain.c
+# C_FILES += commands/sbin/ifconfig/af_ipx.c
+
 C_O_FILES = $(C_FILES:%.c=%.o)
 C_D_FILES = $(C_FILES:%.c=%.d)
 
diff --git a/freebsd-userspace/commands/sbin/ifconfig/af_atalk.c b/freebsd-userspace/commands/sbin/ifconfig/af_atalk.c
new file mode 100644
index 0000000..c50e0fd
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/af_atalk.c
@@ -0,0 +1,182 @@
+/*
+ * 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 <netatalk/at.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.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 ifaddrs *ifa)
+{
+	struct sockaddr_at *sat, null_sat;
+	struct netrange *nr;
+
+	memset(&null_sat, 0, sizeof(null_sat));
+
+	sat = (struct sockaddr_at *)ifa->ifa_addr;
+	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 (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sat = (struct sockaddr_at *)ifa->ifa_dstaddr;
+		if (sat == NULL)
+			sat = &null_sat;
+		printf("--> %d.%d",
+			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
+	}
+	if (ifa->ifa_flags & IFF_BROADCAST) {
+		sat = (struct sockaddr_at *)ifa->ifa_broadaddr;
+		if (sat != NULL)
+			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]))
+	size_t i;
+
+	for (i = 0; i < N(atalk_cmds);  i++)
+		cmd_register(&atalk_cmds[i]);
+	af_register(&af_atalk);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/af_inet.c b/freebsd-userspace/commands/sbin/ifconfig/af_inet.c
new file mode 100644
index 0000000..65488a3
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/af_inet.c
@@ -0,0 +1,213 @@
+/*
+ * 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 <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <netinet/in.h>
+#ifdef __rtems__
+#include <freebsd/net/if_var.h>		/* for struct ifaddr */
+#include <freebsd/netinet/in_var.h>
+#else
+#include <net/if_var.h>		/* for struct ifaddr */
+#include <netinet/in_var.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "ifconfig.h"
+
+#ifdef __rtems__
+#include <freebsd/sys/sockio.h>
+#endif
+
+static struct in_aliasreq in_addreq;
+static struct ifreq in_ridreq;
+
+static void
+in_status(int s __unused, const struct ifaddrs *ifa)
+{
+	struct sockaddr_in *sin, null_sin;
+	
+	memset(&null_sin, 0, sizeof(null_sin));
+
+	sin = (struct sockaddr_in *)ifa->ifa_addr;
+	if (sin == NULL)
+		return;
+
+	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
+		if (sin == NULL)
+			sin = &null_sin;
+		printf("--> %s ", inet_ntoa(sin->sin_addr));
+	}
+
+	sin = (struct sockaddr_in *)ifa->ifa_netmask;
+	if (sin == NULL)
+		sin = &null_sin;
+	printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+
+	if (ifa->ifa_flags & IFF_BROADCAST) {
+		sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
+		if (sin != NULL && 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) {
+			const char *errstr;
+			/* address is `name/masklen' */
+			int masklen;
+			struct sockaddr_in *min = sintab[MASK];
+			*p = '\0';
+			if (!isdigit(*(p + 1)))
+				errstr = "invalid";
+			else
+				masklen = (int)strtonum(p + 1, 0, 32, &errstr);
+			if (errstr != NULL) {
+				*p = '/';
+				errx(1, "%s: bad value (width %s)", s, errstr);
+			}
+			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((size_t)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 (sa->sa_family != AF_INET)
+		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 (sa->sa_family != AF_INET)
+		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 in_aliasreq 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 --git a/freebsd-userspace/commands/sbin/ifconfig/af_inet6.c b/freebsd-userspace/commands/sbin/ifconfig/af_inet6.c
new file mode 100644
index 0000000..c09c778
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/af_inet6.c
@@ -0,0 +1,556 @@
+/*
+ * 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 <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>
+#ifdef __rtems__
+#include <freebsd/net/if_var.h>		/* for struct ifaddr */
+#include <freebsd/netinet/in_var.h>
+#else
+#include <net/if_var.h>		/* for struct ifaddr */
+#include <netinet/in_var.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef __rtems__
+#include <freebsd/netinet6/nd6.h>	/* Define ND6_INFINITE_LIFETIME */
+#else
+#include <netinet6/nd6.h>	/* Define ND6_INFINITE_LIFETIME */
+#endif
+
+#include "ifconfig.h"
+
+static	struct in6_ifreq in6_ridreq;
+static	struct in6_aliasreq in6_addreq = 
+  { .ifra_flags = 0, 
+    .ifra_lifetime = { 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;
+
+extern void setnd6flags(const char *, int, int, const struct afswtch *);
+extern void setnd6defif(const char *, int, int, const struct afswtch *);
+
+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 ifaddrs *ifa)
+{
+	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 *)ifa->ifa_addr;
+	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);
+	if (error != 0)
+		inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+			  sizeof(addr_buf));
+	printf("\tinet6 %s ", addr_buf);
+
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+		/*
+		 * some of the interfaces do not have valid destination
+		 * address.
+		 */
+		if (sin != NULL && 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);
+			if (error != 0)
+				inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+					  sizeof(addr_buf));
+			printf("--> %s ", addr_buf);
+		}
+	}
+
+	sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
+	if (sin == NULL)
+		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];
+	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)
+		return;
+	in6_fillscopeid(&in6_ifr.ifr_addr);
+	if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
+	    NI_NUMERICHOST) != 0)
+		src[0] = '\0';
+
+	if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
+		return;
+	if (sa->sa_family != AF_INET6)
+		return;
+	in6_fillscopeid(&in6_ifr.ifr_addr);
+	if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
+	    NI_NUMERICHOST) != 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("anycast",	IN6_IFF_ANYCAST,	setip6flags),
+	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("accept_rtadv",	ND6_IFF_ACCEPT_RTADV,	setnd6flags),
+	DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV,	setnd6flags),
+	DEF_CMD("defaultif",	1,			setnd6defif),
+	DEF_CMD("-defaultif",	-1,			setnd6defif),
+	DEF_CMD("ifdisabled",	ND6_IFF_IFDISABLED,	setnd6flags),
+	DEF_CMD("-ifdisabled",	-ND6_IFF_IFDISABLED,	setnd6flags),
+	DEF_CMD("nud",		ND6_IFF_PERFORMNUD,	setnd6flags),
+	DEF_CMD("-nud",		-ND6_IFF_PERFORMNUD,	setnd6flags),
+	DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE,	setnd6flags),
+	DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags),
+	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 = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb };
+
+static __constructor void
+inet6_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t 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 --git a/freebsd-userspace/commands/sbin/ifconfig/af_ipx.c b/freebsd-userspace/commands/sbin/ifconfig/af_ipx.c
new file mode 100644
index 0000000..c7b718a
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/af_ipx.c
@@ -0,0 +1,122 @@
+/*
+ * 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 <ifaddrs.h>
+
+#ifdef __rtems__
+#include <freebsd/net/if_var.h>
+#else
+#include <net/if_var.h>
+#endif
+#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 ifaddrs *ifa)
+{
+	struct sockaddr_ipx *sipx, null_sipx;
+
+	sipx = (struct sockaddr_ipx *)ifa->ifa_addr;
+	if (sipx == NULL)
+		return;
+
+	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
+
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sipx = (struct sockaddr_ipx *)ifa->ifa_dstaddr;
+		if (sipx == NULL) {
+			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)
+{
+
+}
+
+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 --git a/freebsd-userspace/commands/sbin/ifconfig/af_link.c b/freebsd-userspace/commands/sbin/ifconfig/af_link.c
new file mode 100644
index 0000000..2de8504
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/af_link.c
@@ -0,0 +1,133 @@
+/*
+ * 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 <ifaddrs.h>
+
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include "ifconfig.h"
+
+#ifdef __rtems__
+#include <freebsd/sys/sockio.h>
+#endif
+
+static struct ifreq link_ridreq;
+
+static void
+link_status(int s __unused, const struct ifaddrs *ifa)
+{
+	/* XXX no const 'cuz LLADDR is defined wrong */
+	struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+
+	if (sdl != NULL && sdl->sdl_alen > 0) {
+		if ((sdl->sdl_type == IFT_ETHER ||
+		    sdl->sdl_type == IFT_L2VLAN ||
+		    sdl->sdl_type == IFT_BRIDGE) &&
+		    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);
+		}
+	}
+}
+
+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) + 2)) == 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 --git a/freebsd-userspace/commands/sbin/ifconfig/af_nd6.c b/freebsd-userspace/commands/sbin/ifconfig/af_nd6.c
new file mode 100644
index 0000000..7482073
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/af_nd6.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2009 Hiroki Sato.  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 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 <sys/sysctl.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#ifdef __rtems__
+#include <freebsd/net/if_var.h>
+#include <freebsd/netinet/in_var.h>
+#else
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef __rtems__
+#include <freebsd/netinet6/nd6.h>
+#else
+#include <netinet6/nd6.h>
+#endif
+
+#include "ifconfig.h"
+
+#define	MAX_SYSCTL_TRY	5
+#define	ND6BITS	"\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
+		"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
+		"\020DEFAULTIF"
+
+static int isnd6defif(int);
+void setnd6flags(const char *, int, int, const struct afswtch *);
+void setnd6defif(const char *, int, int, const struct afswtch *);
+
+void
+setnd6flags(const char *dummyaddr __unused,
+	int d, int s,
+	const struct afswtch *afp)
+{
+	struct in6_ndireq nd;
+	int error;
+
+	memset(&nd, 0, sizeof(nd));
+	strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+	error = ioctl(s, SIOCGIFINFO_IN6, &nd);
+	if (error) {
+		warn("ioctl(SIOCGIFINFO_IN6)");
+		return;
+	}
+	if (d < 0)
+		nd.ndi.flags &= ~(-d);
+	else
+		nd.ndi.flags |= d;
+	error = ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd);
+	if (error)
+		warn("ioctl(SIOCSIFINFO_IN6)");
+}
+
+void
+setnd6defif(const char *dummyaddr __unused,
+	int d, int s,
+	const struct afswtch *afp)
+{
+	struct in6_ndifreq ndifreq;
+	int ifindex;
+	int error;
+
+	memset(&ndifreq, 0, sizeof(ndifreq));
+	strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
+
+	if (d < 0) {
+		if (isnd6defif(s)) {
+			/* ifindex = 0 means to remove default if */
+			ifindex = 0;
+		} else
+			return;
+	} else if ((ifindex = if_nametoindex(ndifreq.ifname)) == 0) {
+		warn("if_nametoindex(%s)", ndifreq.ifname);
+		return;
+	}
+
+	ndifreq.ifindex = ifindex;
+	error = ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq);
+	if (error)
+		warn("ioctl(SIOCSDEFIFACE_IN6)");
+}
+
+static int
+isnd6defif(int s)
+{
+	struct in6_ndifreq ndifreq;
+	unsigned int ifindex;
+	int error;
+
+	memset(&ndifreq, 0, sizeof(ndifreq));
+	strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
+
+	ifindex = if_nametoindex(ndifreq.ifname);
+	error = ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq);
+	if (error) {
+		warn("ioctl(SIOCGDEFIFACE_IN6)");
+		return (error);
+	}
+	return (ndifreq.ifindex == ifindex);
+}
+
+static void
+nd6_status(int s)
+{
+	struct in6_ndireq nd;
+	struct rt_msghdr *rtm;
+	size_t needed;
+	char *buf, *next;
+	int mib[6], ntry;
+	int s6;
+	int error;
+	int isinet6, isdefif;
+
+	/* Check if the interface has at least one IPv6 address. */
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_INET6;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = if_nametoindex(ifr.ifr_name);
+
+	/* Try to prevent a race between two sysctls. */
+	ntry = 0;
+	do {
+		error = sysctl(mib, 6, NULL, &needed, NULL, 0);
+		if (error) {
+			warn("sysctl(NET_RT_IFLIST)/estimate");
+			return;
+		}
+		buf = malloc(needed);
+		if (buf == NULL) {
+			warn("malloc for sysctl(NET_RT_IFLIST) failed");
+			return;
+		}
+		if ((error = sysctl(mib, 6, buf, &needed, NULL, 0)) < 0) {
+			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+				warn("sysctl(NET_RT_IFLIST)/get");
+				free(buf);
+				return;
+			}
+			free(buf);
+			buf = NULL;
+		}
+	} while (buf == NULL);
+	
+	isinet6 = 0;
+	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)next;
+
+		if (rtm->rtm_version != RTM_VERSION)
+			continue;
+		if (rtm->rtm_type == RTM_NEWADDR) {
+			isinet6 = 1;
+			break;
+		}
+	}
+	free(buf);
+	if (!isinet6)
+		return;
+
+	memset(&nd, 0, sizeof(nd));
+	strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+		warn("socket(AF_INET6, SOCK_DGRAM)");
+		return;
+	}
+	error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
+	if (error) {
+		warn("ioctl(SIOCGIFINFO_IN6)");
+		close(s6);
+		return;
+	}
+	isdefif = isnd6defif(s6);
+	close(s6);
+	if (nd.ndi.flags == 0 && !isdefif)
+		return;
+	printb("\tnd6 options",
+	    (unsigned int)(nd.ndi.flags | (isdefif << 15)), ND6BITS);
+	putchar('\n');
+}
+
+static struct afswtch af_nd6 = {
+	.af_name	= "nd6",
+	.af_af		= AF_LOCAL,
+	.af_other_status= nd6_status,
+};
+
+static __constructor void
+nd6_ctor(void)
+{
+	af_register(&af_nd6);
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifbridge.c b/freebsd-userspace/commands/sbin/ifconfig/ifbridge.c
new file mode 100644
index 0000000..049a0e7
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifbridge.c
@@ -0,0 +1,767 @@
+/*-
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed for the NetBSD Project by
+ *	Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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 <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#ifdef __rtems__
+#include <freebsd/net/if_bridgevar.h>
+#else
+#include <net/if_bridgevar.h>
+#endif
+#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"
+
+#ifdef __rtems__
+#include <freebsd/sys/sockio.h>
+#endif
+
+#define PV2ID(pv, epri, eaddr)  do {		\
+		epri     = pv >> 48;		\
+		eaddr[0] = pv >> 40;		\
+		eaddr[1] = pv >> 32;		\
+		eaddr[2] = pv >> 24;		\
+		eaddr[3] = pv >> 16;		\
+		eaddr[4] = pv >> 8;		\
+		eaddr[5] = pv >> 0;		\
+} while (0)
+
+static const char *stpstates[] = {
+	"disabled",
+	"listening",
+	"learning",
+	"forwarding",
+	"blocking",
+	"discarding"
+};
+static const char *stpproto[] = {
+	"stp",
+	"-",
+	"rstp"
+};
+static const char *stproles[] = {
+	"disabled",
+	"root",
+	"designated",
+	"alternate",
+	"backup"
+};
+
+static int
+get_val(const char *cp, u_long *valp)
+{
+	char *endptr;
+	u_long val;
+
+	errno = 0;
+	val = strtoul(cp, &endptr, 0);
+	if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
+		return (-1);
+
+	*valp = val;
+	return (0);
+}
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+	struct ifdrv ifd;
+
+	memset(&ifd, 0, sizeof(ifd));
+
+	strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+	ifd.ifd_cmd = op;
+	ifd.ifd_len = argsize;
+	ifd.ifd_data = arg;
+
+	return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static void
+do_bridgeflag(int sock, const char *ifs, int flag, int set)
+{
+	struct ifbreq req;
+
+	strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
+
+	if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
+		err(1, "unable to get bridge flags");
+
+	if (set)
+		req.ifbr_ifsflags |= flag;
+	else
+		req.ifbr_ifsflags &= ~flag;
+
+	if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
+		err(1, "unable to set bridge flags");
+}
+
+static void
+bridge_interfaces(int s, const char *prefix)
+{
+	struct ifbifconf bifc;
+	struct ifbreq *req;
+	char *inbuf = NULL, *ninbuf;
+	char *p, *pad;
+	int i, len = 8192;
+
+	pad = strdup(prefix);
+	if (pad == NULL)
+		err(1, "strdup");
+	/* replace the prefix with whitespace */
+	for (p = pad; *p != '\0'; p++) {
+		if(isprint(*p))
+			*p = ' ';
+	}
+
+	for (;;) {
+		ninbuf = realloc(inbuf, len);
+		if (ninbuf == NULL)
+			err(1, "unable to allocate interface buffer");
+		bifc.ifbic_len = len;
+		bifc.ifbic_buf = inbuf = ninbuf;
+		if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
+			err(1, "unable to get interface list");
+		if ((bifc.ifbic_len + sizeof(*req)) < len)
+			break;
+		len *= 2;
+	}
+
+	for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
+		req = bifc.ifbic_req + i;
+		printf("%s%s ", prefix, req->ifbr_ifsname);
+		printb("flags", req->ifbr_ifsflags, IFBIFBITS);
+		printf("\n");
+
+		printf("%s", pad);
+		printf("ifmaxaddr %u", req->ifbr_addrmax);
+		printf(" port %u priority %u", req->ifbr_portno,
+		    req->ifbr_priority);
+		printf(" path cost %u", req->ifbr_path_cost);
+
+		if (req->ifbr_ifsflags & IFBIF_STP) {
+			if (req->ifbr_proto <
+			    sizeof(stpproto) / sizeof(stpproto[0]))
+				printf(" proto %s", stpproto[req->ifbr_proto]);
+			else
+				printf(" <unknown proto %d>",
+				    req->ifbr_proto);
+
+			printf("\n%s", pad);
+			if (req->ifbr_role <
+			    sizeof(stproles) / sizeof(stproles[0]))
+				printf("role %s", stproles[req->ifbr_role]);
+			else
+				printf("<unknown role %d>",
+				    req->ifbr_role);
+			if (req->ifbr_state <
+			    sizeof(stpstates) / sizeof(stpstates[0]))
+				printf(" state %s", stpstates[req->ifbr_state]);
+			else
+				printf(" <unknown state %d>",
+				    req->ifbr_state);
+		}
+		printf("\n");
+	}
+
+	free(inbuf);
+}
+
+static void
+bridge_addresses(int s, const char *prefix)
+{
+	struct ifbaconf ifbac;
+	struct ifbareq *ifba;
+	char *inbuf = NULL, *ninbuf;
+	int i, len = 8192;
+	struct ether_addr ea;
+
+	for (;;) {
+		ninbuf = realloc(inbuf, len);
+		if (ninbuf == NULL)
+			err(1, "unable to allocate address buffer");
+		ifbac.ifbac_len = len;
+		ifbac.ifbac_buf = inbuf = ninbuf;
+		if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
+			err(1, "unable to get address cache");
+		if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
+			break;
+		len *= 2;
+	}
+
+	for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
+		ifba = ifbac.ifbac_req + i;
+		memcpy(ea.octet, ifba->ifba_dst,
+		    sizeof(ea.octet));
+		printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
+		    ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
+		printb("flags", ifba->ifba_flags, IFBAFBITS);
+		printf("\n");
+	}
+
+	free(inbuf);
+}
+
+static void
+bridge_status(int s)
+{
+	struct ifbropreq ifbp;
+	struct ifbrparam param;
+	u_int16_t pri;
+	u_int8_t ht, fd, ma, hc, pro;
+	u_int8_t lladdr[ETHER_ADDR_LEN];
+	u_int16_t bprio;
+	u_int32_t csize, ctime;
+
+	if (do_cmd(s, BRDGGCACHE, &param, sizeof(param), 0) < 0)
+		return;
+	csize = param.ifbrp_csize;
+	if (do_cmd(s, BRDGGTO, &param, sizeof(param), 0) < 0)
+		return;
+	ctime = param.ifbrp_ctime;
+	if (do_cmd(s, BRDGPARAM, &ifbp, sizeof(ifbp), 0) < 0)
+		return;
+	pri = ifbp.ifbop_priority;
+	pro = ifbp.ifbop_protocol;
+	ht = ifbp.ifbop_hellotime;
+	fd = ifbp.ifbop_fwddelay;
+	hc = ifbp.ifbop_holdcount;
+	ma = ifbp.ifbop_maxage;
+
+	PV2ID(ifbp.ifbop_bridgeid, bprio, lladdr);
+	printf("\tid %s priority %u hellotime %u fwddelay %u\n",
+	    ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd);
+	printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
+	    ma, hc, stpproto[pro], csize, ctime);
+
+	PV2ID(ifbp.ifbop_designated_root, bprio, lladdr);
+	printf("\troot id %s priority %d ifcost %u port %u\n",
+	    ether_ntoa((struct ether_addr *)lladdr), bprio,
+	    ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
+
+	bridge_interfaces(s, "\tmember: ");
+
+	return;
+
+}
+
+static void
+setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbreq req;
+
+	memset(&req, 0, sizeof(req));
+	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+	if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGADD %s",  val);
+}
+
+static void
+setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbreq req;
+
+	memset(&req, 0, sizeof(req));
+	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+	if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGDEL %s",  val);
+}
+
+static void
+setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
+}
+
+static void
+unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
+}
+
+static void
+setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_LEARNING,  1);
+}
+
+static void
+unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_LEARNING,  0);
+}
+
+static void
+setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_STICKY,  1);
+}
+
+static void
+unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_STICKY,  0);
+}
+
+static void
+setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbreq req;
+
+	memset(&req, 0, sizeof(req));
+	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+	if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGADDS %s",  val);
+}
+
+static void
+unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbreq req;
+
+	memset(&req, 0, sizeof(req));
+	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+	if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGDELS %s",  val);
+}
+
+static void
+setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_STP, 1);
+}
+
+static void
+unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_STP, 0);
+}
+
+static void
+setbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1);
+}
+
+static void
+unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0);
+}
+
+static void
+setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1);
+}
+
+static void
+unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0);
+}
+
+static void
+setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1);
+}
+
+static void
+unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0);
+}
+
+static void
+setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1);
+}
+
+static void
+unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0);
+}
+
+static void
+setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbreq req;
+
+	memset(&req, 0, sizeof(req));
+	req.ifbr_ifsflags = IFBF_FLUSHDYN;
+	if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbreq req;
+
+	memset(&req, 0, sizeof(req));
+	req.ifbr_ifsflags = IFBF_FLUSHALL;
+	if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_static(const char *val, const char *mac, int s,
+    const struct afswtch *afp)
+{
+	struct ifbareq req;
+	struct ether_addr *ea;
+
+	memset(&req, 0, sizeof(req));
+	strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
+
+	ea = ether_aton(mac);
+	if (ea == NULL)
+		errx(1, "%s: invalid address: %s", val, mac);
+
+	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+	req.ifba_flags = IFBAF_STATIC;
+	req.ifba_vlan = 1; /* XXX allow user to specify */
+
+	if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGSADDR %s",  val);
+}
+
+static void
+setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifbareq req;
+	struct ether_addr *ea;
+
+	memset(&req, 0, sizeof(req));
+
+	ea = ether_aton(val);
+	if (ea == NULL)
+		errx(1, "invalid address: %s",  val);
+
+	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+
+	if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGDADDR %s",  val);
+}
+
+static void
+setbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	bridge_addresses(s, "");
+}
+
+static void
+setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_csize = val & 0xffffffff;
+
+	if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSCACHE %s",  arg);
+}
+
+static void
+setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_hellotime = val & 0xff;
+
+	if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSHT %s",  arg);
+}
+
+static void
+setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_fwddelay = val & 0xff;
+
+	if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSFD %s",  arg);
+}
+
+static void
+setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_maxage = val & 0xff;
+
+	if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSMA %s",  arg);
+}
+
+static void
+setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_prio = val & 0xffff;
+
+	if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSPRI %s",  arg);
+}
+
+static void
+setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+
+	if (strcasecmp(arg, "stp") == 0) {
+		param.ifbrp_proto = 0;
+	} else if (strcasecmp(arg, "rstp") == 0) {
+		param.ifbrp_proto = 2;
+	} else {
+		errx(1, "unknown stp protocol");
+	}
+
+	if (do_cmd(s, BRDGSPROTO, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSPROTO %s",  arg);
+}
+
+static void
+setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_txhc = val & 0xff;
+
+	if (do_cmd(s, BRDGSTXHC, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSTXHC %s",  arg);
+}
+
+static void
+setbridge_ifpriority(const char *ifn, const char *pri, int s,
+    const struct afswtch *afp)
+{
+	struct ifbreq req;
+	u_long val;
+
+	memset(&req, 0, sizeof(req));
+
+	if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
+		errx(1, "invalid value: %s",  pri);
+
+	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+	req.ifbr_priority = val & 0xff;
+
+	if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGSIFPRIO %s",  pri);
+}
+
+static void
+setbridge_ifpathcost(const char *ifn, const char *cost, int s,
+    const struct afswtch *afp)
+{
+	struct ifbreq req;
+	u_long val;
+
+	memset(&req, 0, sizeof(req));
+
+	if (get_val(cost, &val) < 0)
+		errx(1, "invalid value: %s",  cost);
+
+	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+	req.ifbr_path_cost = val;
+
+	if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGSIFCOST %s",  cost);
+}
+
+static void
+setbridge_ifmaxaddr(const char *ifn, const char *arg, int s,
+    const struct afswtch *afp)
+{
+	struct ifbreq req;
+	u_long val;
+
+	memset(&req, 0, sizeof(req));
+
+	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+	req.ifbr_addrmax = val & 0xffffffff;
+
+	if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
+		err(1, "BRDGSIFAMAX %s",  arg);
+}
+
+static void
+setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_ctime = val & 0xffffffff;
+
+	if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSTO %s",  arg);
+}
+
+static void
+setbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_PRIVATE, 1);
+}
+
+static void
+unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_PRIVATE, 0);
+}
+
+static struct cmd bridge_cmds[] = {
+	DEF_CMD_ARG("addm",		setbridge_add),
+	DEF_CMD_ARG("deletem",		setbridge_delete),
+	DEF_CMD_ARG("discover",		setbridge_discover),
+	DEF_CMD_ARG("-discover",	unsetbridge_discover),
+	DEF_CMD_ARG("learn",		setbridge_learn),
+	DEF_CMD_ARG("-learn",		unsetbridge_learn),
+	DEF_CMD_ARG("sticky",		setbridge_sticky),
+	DEF_CMD_ARG("-sticky",		unsetbridge_sticky),
+	DEF_CMD_ARG("span",		setbridge_span),
+	DEF_CMD_ARG("-span",		unsetbridge_span),
+	DEF_CMD_ARG("stp",		setbridge_stp),
+	DEF_CMD_ARG("-stp",		unsetbridge_stp),
+	DEF_CMD_ARG("edge",		setbridge_edge),
+	DEF_CMD_ARG("-edge",		unsetbridge_edge),
+	DEF_CMD_ARG("autoedge",		setbridge_autoedge),
+	DEF_CMD_ARG("-autoedge",	unsetbridge_autoedge),
+	DEF_CMD_ARG("ptp",		setbridge_ptp),
+	DEF_CMD_ARG("-ptp",		unsetbridge_ptp),
+	DEF_CMD_ARG("autoptp",		setbridge_autoptp),
+	DEF_CMD_ARG("-autoptp",		unsetbridge_autoptp),
+	DEF_CMD("flush", 0,		setbridge_flush),
+	DEF_CMD("flushall", 0,		setbridge_flushall),
+	DEF_CMD_ARG2("static",		setbridge_static),
+	DEF_CMD_ARG("deladdr",		setbridge_deladdr),
+	DEF_CMD("addr",	 1,		setbridge_addr),
+	DEF_CMD_ARG("maxaddr",		setbridge_maxaddr),
+	DEF_CMD_ARG("hellotime",	setbridge_hellotime),
+	DEF_CMD_ARG("fwddelay",		setbridge_fwddelay),
+	DEF_CMD_ARG("maxage",		setbridge_maxage),
+	DEF_CMD_ARG("priority",		setbridge_priority),
+	DEF_CMD_ARG("proto",		setbridge_protocol),
+	DEF_CMD_ARG("holdcnt",		setbridge_holdcount),
+	DEF_CMD_ARG2("ifpriority",	setbridge_ifpriority),
+	DEF_CMD_ARG2("ifpathcost",	setbridge_ifpathcost),
+	DEF_CMD_ARG2("ifmaxaddr",	setbridge_ifmaxaddr),
+	DEF_CMD_ARG("timeout",		setbridge_timeout),
+	DEF_CMD_ARG("private",		setbridge_private),
+	DEF_CMD_ARG("-private",		unsetbridge_private),
+};
+static struct afswtch af_bridge = {
+	.af_name	= "af_bridge",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = bridge_status,
+};
+
+static __constructor void
+bridge_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(bridge_cmds);  i++)
+		cmd_register(&bridge_cmds[i]);
+	af_register(&af_bridge);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifcarp.c b/freebsd-userspace/commands/sbin/ifconfig/ifcarp.c
new file mode 100644
index 0000000..6c8c5a1
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifcarp.c
@@ -0,0 +1,204 @@
+/*	$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>
+#ifdef __rtems__
+#include <freebsd/netinet/ip_carp.h>
+#else
+#include <netinet/ip_carp.h>
+#endif
+#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");
+
+	memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key));
+	/* 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 --git a/freebsd-userspace/commands/sbin/ifconfig/ifclone.c b/freebsd-userspace/commands/sbin/ifconfig/ifclone.c
new file mode 100644
index 0000000..3dc5a37
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifclone.c
@@ -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/queue.h>
+#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"
+
+#ifdef __rtems__
+#include <freebsd/sys/sockio.h>
+#endif
+
+static void
+list_cloners(void)
+{
+	struct if_clonereq ifcr;
+	char *cp, *buf;
+	int idx;
+	int s;
+
+	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (s == -1)
+		err(1, "socket(AF_LOCAL,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);
+}
+
+struct clone_defcb {
+	char ifprefix[IFNAMSIZ];
+	clone_callback_func *clone_cb;
+	SLIST_ENTRY(clone_defcb) next;
+};
+
+static SLIST_HEAD(, clone_defcb) clone_defcbh =
+   SLIST_HEAD_INITIALIZER(clone_defcbh);
+
+void
+clone_setdefcallback(const char *ifprefix, clone_callback_func *p)
+{
+	struct clone_defcb *dcp;
+
+	dcp = malloc(sizeof(*dcp));
+	strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1);
+	dcp->clone_cb = p;
+	SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
+}
+
+/*
+ * Do the actual clone operation.  Any parameters must have been
+ * setup by now.  If a callback has been setup to do the work
+ * then defer to it; otherwise do a simple create operation with
+ * no parameters.
+ */
+static void
+ifclonecreate(int s, void *arg)
+{
+	struct ifreq ifr;
+	struct clone_defcb *dcp;
+	clone_callback_func *clone_cb = NULL;
+
+	memset(&ifr, 0, sizeof(ifr));
+	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+	if (clone_cb == NULL) {
+		/* Try to find a default callback */
+		SLIST_FOREACH(dcp, &clone_defcbh, next) {
+			if (strncmp(dcp->ifprefix, ifr.ifr_name,
+			    strlen(dcp->ifprefix)) == 0) {
+				clone_cb = dcp->clone_cb;
+				break;
+			}
+		}
+	}
+	if (clone_cb == NULL) {
+		/* NB: no parameters */
+		if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
+			err(1, "SIOCIFCREATE2");
+	} else {
+		clone_cb(s, &ifr);
+	}
+
+	/*
+	 * If we get a different name back than we put in, print it.
+	 */
+	if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
+		strlcpy(name, ifr.ifr_name, sizeof(name));
+		printf("%s\n", name);
+	}
+}
+
+static
+DECL_CMD_FUNC(clone_create, arg, d)
+{
+	callback_register(ifclonecreate, NULL);
+}
+
+static
+DECL_CMD_FUNC(clone_destroy, arg, d)
+{
+	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+		err(1, "SIOCIFDESTROY");
+}
+
+static struct cmd clone_cmds[] = {
+	DEF_CLONE_CMD("create",	0,	clone_create),
+	DEF_CMD("destroy",	0,	clone_destroy),
+	DEF_CLONE_CMD("plumb",	0,	clone_create),
+	DEF_CMD("unplumb",	0,	clone_destroy),
+};
+
+static void
+clone_Copt_cb(const char *optarg __unused)
+{
+	list_cloners();
+	exit(0);
+}
+static struct option clone_Copt = { .opt = "C", .opt_usage = "[-C]", .cb = clone_Copt_cb };
+
+static __constructor void
+clone_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(clone_cmds);  i++)
+		cmd_register(&clone_cmds[i]);
+	opt_register(&clone_Copt);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifconfig.8 b/freebsd-userspace/commands/sbin/ifconfig/ifconfig.8
new file mode 100644
index 0000000..eaab8fa
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifconfig.8
@@ -0,0 +1,2555 @@
+.\" Copyright (c) 1983, 1991, 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.
+.\"
+.\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
+.\" $FreeBSD$
+.\"
+.Dd May 14, 2010
+.Dt IFCONFIG 8
+.Os
+.Sh NAME
+.Nm ifconfig
+.Nd configure network interface parameters
+.Sh SYNOPSIS
+.Nm
+.Op Fl L
+.Op Fl k
+.Op Fl m
+.Op Fl n
+.Ar interface
+.Op Cm create
+.Op Ar address_family
+.Oo
+.Ar address
+.Op Ar dest_address
+.Oc
+.Op Ar parameters
+.Nm
+.Ar interface
+.Cm destroy
+.Nm
+.Fl a
+.Op Fl L
+.Op Fl d
+.Op Fl m
+.Op Fl u
+.Op Fl v
+.Op Ar address_family
+.Nm
+.Fl l
+.Op Fl d
+.Op Fl u
+.Op Ar address_family
+.Nm
+.Op Fl L
+.Op Fl d
+.Op Fl k
+.Op Fl m
+.Op Fl u
+.Op Fl v
+.Op Fl C
+.Nm
+.Op Fl g Ar groupname
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to assign an address
+to a network interface and/or configure
+network interface parameters.
+The
+.Nm
+utility must be used at boot time to define the network address
+of each interface present on a machine; it may also be used at
+a later time to redefine an interface's address
+or other operating parameters.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Ar address
+For the
+.Tn DARPA Ns -Internet
+family,
+the address is either a host name present in the host name data
+base,
+.Xr hosts 5 ,
+or a
+.Tn DARPA
+Internet address expressed in the Internet standard
+.Dq dot notation .
+.Pp
+It is also possible to use the CIDR notation (also known as the
+slash notation) to include the netmask.
+That is, one can specify an address like
+.Li 192.168.0.1/16 .
+.Pp
+For the
+.Dq inet6
+family, it is also possible to specify the prefix length using the slash
+notation, like
+.Li ::1/128 .
+See the
+.Cm prefixlen
+parameter below for more information.
+.\" For the Xerox Network Systems(tm) family,
+.\" addresses are
+.\" .Ar net:a.b.c.d.e.f ,
+.\" where
+.\" .Ar net
+.\" is the assigned network number (in decimal),
+.\" and each of the six bytes of the host number,
+.\" .Ar a
+.\" through
+.\" .Ar f ,
+.\" are specified in hexadecimal.
+.\" The host number may be omitted on IEEE 802 protocol
+.\" (Ethernet, FDDI, and Token Ring) interfaces,
+.\" which use the hardware physical address,
+.\" and on interfaces other than the first.
+.\" For the
+.\" .Tn ISO
+.\" family, addresses are specified as a long hexadecimal string,
+.\" as in the Xerox family.
+.\" However, two consecutive dots imply a zero
+.\" byte, and the dots are optional, if the user wishes to (carefully)
+.\" count out long strings of digits in network byte order.
+.Pp
+The link-level
+.Pq Dq link
+address
+is specified as a series of colon-separated hex digits.
+This can be used to
+e.g.\& set a new MAC address on an ethernet interface, though the
+mechanism used is not ethernet-specific.
+If the interface is already
+up when this option is used, it will be briefly brought down and
+then brought back up again in order to ensure that the receive
+filter in the underlying ethernet hardware is properly reprogrammed.
+.It Ar address_family
+Specify the
+address family
+which affects interpretation of the remaining parameters.
+Since an interface can receive transmissions in differing protocols
+with different naming schemes, specifying the address family is recommended.
+The address or protocol families currently
+supported are
+.Dq inet ,
+.Dq inet6 ,
+.Dq atalk ,
+.Dq ipx ,
+.\" .Dq iso ,
+and
+.Dq link .
+.\" and
+.\" .Dq ns .
+The default is
+.Dq inet .
+.Dq ether
+and
+.Dq lladdr
+are synonyms for
+.Dq link .
+.It Ar dest_address
+Specify the address of the correspondent on the other end
+of a point to point link.
+.It Ar interface
+This
+parameter is a string of the form
+.Dq name unit ,
+for example,
+.Dq Li ed0 .
+.It Ar groupname
+List the interfaces in the given group.
+.El
+.Pp
+The following parameters may be set with
+.Nm :
+.Bl -tag -width indent
+.It Cm add
+Another name for the
+.Cm alias
+parameter.
+Introduced for compatibility
+with
+.Bsx .
+.It Cm alias
+Establish an additional network address for this interface.
+This is sometimes useful when changing network numbers, and
+one wishes to accept packets addressed to the old interface.
+If the address is on the same subnet as the first network address
+for this interface, a non-conflicting netmask must be given.
+Usually
+.Li 0xffffffff
+is most appropriate.
+.It Fl alias
+Remove the network address specified.
+This would be used if you incorrectly specified an alias, or it
+was no longer needed.
+If you have incorrectly set an NS address having the side effect
+of specifying the host portion, removing all NS addresses will
+allow you to respecify the host portion.
+.It Cm anycast
+(Inet6 only.)
+Specify that the address configured is an anycast address.
+Based on the current specification,
+only routers may configure anycast addresses.
+Anycast address will not be used as source address of any of outgoing
+IPv6 packets.
+.It Cm arp
+Enable the use of the Address Resolution Protocol
+.Pq Xr arp 4
+in mapping
+between network level addresses and link level addresses (default).
+This is currently implemented for mapping between
+.Tn DARPA
+Internet
+addresses and
+.Tn IEEE
+802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses).
+.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
+network.
+The default broadcast address is the address with a host part of all 1's.
+.It Cm debug
+Enable driver dependent debugging code; usually, this turns on
+extra console error logging.
+.It Fl debug
+Disable driver dependent debugging code.
+.It Cm promisc
+Put interface into permanently promiscuous mode.
+.It Fl promisc
+Disable permanently promiscuous mode.
+.It Cm delete
+Another name for the
+.Fl alias
+parameter.
+.It Cm description Ar value , Cm descr Ar value
+Specify a description of the interface.
+This can be used to label interfaces in situations where they may
+otherwise be difficult to distinguish.
+.It Cm -description , Cm -descr
+Clear the interface description.
+.It Cm down
+Mark an interface
+.Dq down .
+When an interface is marked
+.Dq down ,
+the system will not attempt to
+transmit messages through that interface.
+If possible, the interface will be reset to disable reception as well.
+This action does not automatically disable routes using the interface.
+.It Cm group Ar group-name
+Assign the interface to a
+.Dq group .
+Any interface can be in multiple groups.
+.Pp
+Cloned interfaces are members of their interface family group by default.
+For example, a PPP interface such as
+.Em ppp0
+is a member of the PPP interface family group,
+.Em ppp .
+.\" The interface(s) the default route(s) point to are members of the
+.\" .Em egress
+.\" interface group.
+.It Cm -group Ar group-name
+Remove the interface from the given
+.Dq group .
+.It Cm eui64
+(Inet6 only.)
+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 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
+.Ar type .
+Some interfaces support the mutually exclusive use of one of several
+different physical media connectors.
+For example, a 10Mbit/s Ethernet
+interface might support the use of either
+.Tn AUI
+or twisted pair connectors.
+Setting the media type to
+.Cm 10base5/AUI
+would change the currently active connector to the AUI port.
+Setting it to
+.Cm 10baseT/UTP
+would activate twisted pair.
+Refer to the interfaces' driver
+specific documentation or man page for a complete list of the
+available types.
+.It Cm mediaopt Ar opts
+If the driver supports the media selection system, set the specified
+media options on the interface.
+The
+.Ar opts
+argument
+is a comma delimited list of options to apply to the interface.
+Refer to the interfaces' driver specific man page for a complete
+list of available options.
+.It Fl mediaopt Ar opts
+If the driver supports the media selection system, disable the
+specified media options on the interface.
+.It Cm mode Ar mode
+If the driver supports the media selection system, set the specified
+operating mode on the interface to
+.Ar mode .
+For IEEE 802.11 wireless interfaces that support multiple operating modes
+this directive is used to select between 802.11a
+.Pq Cm 11a ,
+802.11b
+.Pq Cm 11b ,
+and 802.11g
+.Pq Cm 11g
+operating modes.
+.It Cm inst Ar minst , Cm instance Ar minst
+Set the media instance to
+.Ar minst .
+This is useful for devices which have multiple physical layer interfaces
+.Pq PHYs .
+.It Cm name Ar name
+Set the interface name to
+.Ar name .
+.It Cm rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+enable receive (or transmit) checksum offloading on the interface.
+Some drivers may not be able to enable these flags independently
+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 , 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 tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, enable TSO on the interface.
+Some drivers may not be able to support TSO for
+.Xr ip 4
+and
+.Xr ip6 4
+packets, so they may enable only one of them.
+.It Fl tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, disable TSO on the interface.
+It will always disable TSO for
+.Xr ip 4
+and
+.Xr ip6 4 .
+.It Cm lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, enable LRO on the interface.
+.It Fl lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, disable LRO on the interface.
+.It Cm wol , wol_ucast , wol_mcast , wol_magic
+Enable Wake On Lan (WOL) support, if available.
+WOL is a facility whereby a machine in a low power state may be woken
+in response to a received packet.
+There are three types of packets that may wake a system:
+ucast (directed solely to the machine's mac address),
+mcast (directed to a broadcast or multicast address),
+or
+magic (unicast or multicast frames with a ``magic contents'').
+Not all devices support WOL, those that do indicate the mechanisms
+they support in their capabilities.
+.Cm wol
+is a synonym for enabling all available WOL mechanisms.
+To disable WOL use
+.Fl wol .
+.It Cm vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso
+If the driver offers user-configurable VLAN support, enable
+reception of extended frames, tag processing in hardware,
+frame filtering in hardware, or TSO on VLAN,
+respectively.
+Note that this must be issued on a physical interface associated with
+.Xr vlan 4 ,
+not on a
+.Xr vlan 4
+interface itself.
+.It Fl vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso
+If the driver offers user-configurable VLAN support, disable
+reception of extended frames, tag processing in hardware,
+frame filtering in hardware, or TSO on VLAN,
+respectively.
+.It Cm vnet Ar jail
+Move the interface to the
+.Xr jail 8 ,
+specified by name or JID.
+If the jail has a virtual network stack, the interface will disappear
+from the current environment and become visible to the jail.
+.It Fl vnet Ar jail
+Reclaim the interface from the
+.Xr jail 8 ,
+specified by name or JID.
+If the jail has a virtual network stack, the interface will disappear
+from the jail, and become visible to the current network environment.
+.It Cm polling
+Turn on
+.Xr polling 4
+feature and disable interrupts on the interface, if driver supports
+this mode.
+.It Fl polling
+Turn off
+.Xr polling 4
+feature and enable interrupt mode on the interface.
+.It Cm create
+Create the specified network pseudo-device.
+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 unless the interface is renamed or destroyed
+in the same
+.Nm
+invocation.
+.It Cm destroy
+Destroy the specified network pseudo-device.
+.It Cm plumb
+Another name for the
+.Cm create
+parameter.
+Included for
+.Tn Solaris
+compatibility.
+.It Cm unplumb
+Another name for the
+.Cm destroy
+parameter.
+Included for
+.Tn Solaris
+compatibility.
+.It Cm metric Ar n
+Set the routing metric of the interface to
+.Ar n ,
+default 0.
+The routing metric is used by the routing protocol
+.Pq Xr routed 8 .
+Higher metrics have the effect of making a route
+less favorable; metrics are counted as additional hops
+to the destination network or host.
+.It Cm mtu Ar n
+Set the maximum transmission unit of the interface to
+.Ar n ,
+default is interface specific.
+The MTU is used to limit the size of packets that are transmitted on an
+interface.
+Not all interfaces support setting the MTU, and some interfaces have
+range restrictions.
+.It Cm netmask Ar mask
+.\" (Inet and ISO.)
+(Inet only.)
+Specify how much of the address to reserve for subdividing
+networks into sub-networks.
+The mask includes the network part of the local address
+and the subnet part, which is taken from the host field of the address.
+The mask can be specified as a single hexadecimal number
+with a leading
+.Ql 0x ,
+with a dot-notation Internet address,
+or with a pseudo-network name listed in the network table
+.Xr networks 5 .
+The mask contains 1's for the bit positions in the 32-bit address
+which are to be used for the network and subnet parts,
+and 0's for the host part.
+The mask should contain at least the standard network portion,
+and the subnet field should be contiguous with the network
+portion.
+.Pp
+The netmask can also be specified in CIDR notation after the address.
+See the
+.Ar address
+option above for more information.
+.It Cm prefixlen Ar len
+(Inet6 only.)
+Specify that
+.Ar len
+bits are reserved for subdividing networks into sub-networks.
+The
+.Ar len
+must be integer, and for syntactical reason it must be between 0 to 128.
+It is almost always 64 under the current IPv6 assignment rule.
+If the parameter is omitted, 64 is used.
+.Pp
+The prefix can also be specified using the slash notation after the address.
+See the
+.Ar address
+option above for more information.
+.\" see
+.\" Xr eon 5 .
+.\" .It Cm nsellength Ar n
+.\" .Pf ( Tn ISO
+.\" only)
+.\" This specifies a trailing number of bytes for a received
+.\" .Tn NSAP
+.\" used for local identification, the remaining leading part of which is
+.\" taken to be the
+.\" .Tn NET
+.\" (Network Entity Title).
+.\" The default value is 1, which is conformant to US
+.\" .Tn GOSIP .
+.\" When an ISO address is set in an ifconfig command,
+.\" it is really the
+.\" .Tn NSAP
+.\" which is being specified.
+.\" For example, in
+.\" .Tn US GOSIP ,
+.\" 20 hex digits should be
+.\" specified in the
+.\" .Tn ISO NSAP
+.\" to be assigned to the interface.
+.\" There is some evidence that a number different from 1 may be useful
+.\" for
+.\" .Tn AFI
+.\" 37 type addresses.
+.It Cm range Ar netrange
+Under appletalk, set the interface to respond to a
+.Ar netrange
+of the form
+.Ar startnet Ns - Ns Ar endnet .
+Appletalk uses this scheme instead of
+netmasks though
+.Fx
+implements it internally as a set of netmasks.
+.It Cm remove
+Another name for the
+.Fl alias
+parameter.
+Introduced for compatibility
+with
+.Bsx .
+.It Cm phase
+The argument following this specifies the version (phase) of the
+Appletalk network attached to the interface.
+Values of 1 or 2 are permitted.
+.Sm off
+.It Cm link Op Cm 0 No - Cm 2
+.Sm on
+Enable special processing of the link level of the interface.
+These three options are interface specific in actual effect, however,
+they are in general used to select special modes of operation.
+An example
+of this is to enable SLIP compression, or to select the connector type
+for some Ethernet cards.
+Refer to the man page for the specific driver
+for more information.
+.Sm off
+.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 up
+Mark an interface
+.Dq up .
+This may be used to enable an interface after an
+.Dq Nm Cm down .
+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.
+.El
+.Pp
+The following parameters are for ICMPv6 Neightbor Discovery Protocol:
+.Bl -tag -width indent
+.It Cm accept_rtadv
+Set a flag to enable accepting ICMPv6 Router Advertisement messages.
+.It Cm -accept_rtadv
+Clear a flag
+.Cm accept_rtadv .
+.It Cm defaultif
+Set the specified interface as the default route when there is no
+default router.
+.It Cm -defaultif
+Clear a flag
+.Cm defaultif .
+.It Cm ifdisabled
+Set a flag to disable all of IPv6 network communications on the
+specified interface.
+.It Cm -ifdisabled
+Clear a flag
+.Cm ifdisabled .
+.It Cm nud
+Set a flag to enable Neighbor Unreachability Detection.
+.It Cm -nud
+Clear a flag
+.Cm nud .
+.It Cm prefer_source
+Set a flag to prefer addesses on the interface as candidates of the
+source address for outgoing packets.
+.It Cm -prefer_source
+Clear a flag
+.Cm prefer_source .
+.El
+.Pp
+The following parameters are specific to cloning
+IEEE 802.11 wireless interfaces with the
+.Cm create
+request:
+.Bl -tag -width indent
+.It Cm wlandev Ar device
+Use
+.Ar device
+as the parent for the cloned device.
+.It Cm wlanmode Ar mode
+Specify the operating mode for this cloned device.
+.Ar mode
+is one of
+.Cm sta ,
+.Cm ahdemo 
+(or
+.Cm adhoc-demo ),
+.Cm ibss ,
+(or
+.Cm adhoc ),
+.Cm ap ,
+(or
+.Cm hostap ),
+.Cm wds ,
+.Cm tdma ,
+.Cm mesh ,
+and
+.Cm monitor .
+The operating mode of a cloned interface cannot be changed.
+The
+.Cm tdma
+mode is actually implemented as an
+.Cm adhoc-demo
+interface with special properties.
+.It Cm wlanbssid Ar bssid
+The 802.11 mac address to use for the bssid.
+This must be specified at create time for a legacy
+.Cm wds
+device.
+.It Cm wlanaddr Ar address
+The local mac address.
+If this is not specified then a mac address will automatically be assigned
+to the cloned device.
+Typically this address is the same as the address of the parent device
+but if the
+.Cm bssid
+parameter is specified then the driver will craft a unique address for
+the device (if supported).
+.It Cm wdslegacy
+Mark a
+.Cm wds
+device as operating in ``legacy mode''.
+Legacy 
+.Cm wds
+devices have a fixed peer relationship and do not, for example, roam
+if their peer stops communicating.
+For completeness a Dynamic WDS (DWDS) interface may marked as
+.Fl wdslegacy .
+.It Cm bssid
+Request a unique local mac address for the cloned device.
+This is only possible if the device supports multiple mac addresses.
+To force use of the parent's mac address use
+.Fl bssid .
+.It Cm beacons
+Mark the cloned interface as depending on hardware support to
+track received beacons.
+To have beacons tracked in software use
+.Fl beacons .
+For 
+.Cm hostap
+mode 
+.Fl beacons
+can also be used to indicate no beacons should
+be transmitted; this can be useful when creating a WDS configuration but
+.Cm wds
+interfaces can only be created as companions to an access point.
+.El
+.Pp
+The following parameters are specific to IEEE 802.11 wireless interfaces
+cloned with a
+.Cm create
+operation:
+.Bl -tag -width indent
+.It Cm ampdu
+Enable sending and receiving AMPDU frames when using 802.11n (default).
+The 802.11n specification states a compliant station must be capable
+of receiving AMPDU frames but transmision is optional.
+Use
+.Fl ampdu
+to disable all use of AMPDU with 802.11n.
+For testing and/or to work around interoperability problems one can use
+.Cm ampdutx
+and
+.Cm ampdurx
+to control use of AMPDU in one direction.
+.It Cm ampdudensity Ar density
+Set the AMPDU density parameter used when operating with 802.11n.
+This parameter controls the inter-packet gap for AMPDU frames.
+The sending device normally controls this setting but a receiving station
+may request wider gaps.
+Legal values for
+.Ar density
+are 0, .25, .5, 1, 2, 4, 8, and 16 (microseconds).
+A value of
+.Cm -
+is treated the same as 0.
+.It Cm ampdulimit Ar limit
+Set the limit on packet size for receiving AMPDU frames when operating
+with 802.11n.
+Legal values for
+.Ar limit
+are 8192, 16384, 32768, and 65536 but one can also specify
+just the unique prefix: 8, 16, 32, 64.
+Note the sender may limit the size of AMPDU frames to be less
+than the maximum specified by the receiving station.
+.It Cm amsdu
+Enable sending and receiving AMSDU frames when using 802.11n.
+By default AMSDU is received but not transmitted.
+Use
+.Fl amsdu
+to disable all use of AMSDU with 802.11n.
+For testing and/or to work around interoperability problems one can use
+.Cm amsdutx
+and
+.Cm amsdurx
+to control use of AMSDU in one direction.
+.It Cm amsdulimit Ar limit
+Set the limit on packet size for sending and receiving AMSDU frames
+when operating with 802.11n.
+Legal values for
+.Ar limit
+are 7935 and 3839 (bytes).
+Note the sender may limit the size of AMSDU frames to be less
+than the maximum specified by the receiving station.
+Note also that devices are not required to support the 7935 limit,
+only 3839 is required by the specification and the larger value
+may require more memory to be dedicated to support functionality
+that is rarely used.
+.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
+Set the desired authentication mode in infrastructure mode.
+Not all adapters support all modes.
+The set of
+valid modes is
+.Cm none , open , shared
+(shared key),
+.Cm 8021x
+(IEEE 802.1x),
+and
+.Cm wpa
+(IEEE WPA/WPA2/802.11i).
+The
+.Cm 8021x
+and
+.Cm wpa
+modes are only useful when using an authentication service
+(a supplicant for client operation or an authenticator when
+operating as an access point).
+Modes are case insensitive.
+.It Cm bgscan
+Enable background scanning when operating as a station.
+Background scanning is a technique whereby a station associated to
+an access point will temporarily leave the channel to scan for
+neighboring stations.
+This allows a station to maintain a cache of nearby access points
+so that roaming between access points can be done without
+a lengthy scan operation.
+Background scanning is done only when a station is not busy and
+any outbound traffic will cancel a scan operation.
+Background scanning should never cause packets to be lost though
+there may be some small latency if outbound traffic interrupts a
+scan operation.
+By default background scanning is enabled if the device is capable.
+To disable background scanning, use
+.Fl bgscan .
+Background scanning is controlled by the
+.Cm bgscanidle
+and
+.Cm bgscanintvl
+parameters.
+Background scanning must be enabled for roaming; this is an artifact
+of the current implementation and may not be required in the future.
+.It Cm bgscanidle Ar idletime
+Set the minimum time a station must be idle (not transmitting or
+receiving frames) before a background scan is initiated.
+The
+.Ar idletime
+parameter is specified in milliseconds.
+By default a station must be idle at least 250 milliseconds before
+a background scan is initiated.
+The idle time may not be set to less than 100 milliseconds.
+.It Cm bgscanintvl Ar interval
+Set the interval at which background scanning is attempted.
+The
+.Ar interval
+parameter is specified in seconds.
+By default a background scan is considered every 300 seconds (5 minutes).
+The 
+.Ar interval
+may not be set to less than 15 seconds.
+.It Cm bintval Ar interval
+Set the interval at which beacon frames are sent when operating in
+ad-hoc or ap mode.
+The
+.Ar interval
+parameter is specified in TU's (1024 usecs).
+By default beacon frames are transmitted every 100 TU's.
+.It Cm bmissthreshold Ar count
+Set the number of consecutive missed beacons at which the station
+will attempt to roam (i.e., search for a new access point).
+The
+.Ar count
+parameter must be in the range 1 to 255; though the
+upper bound may be reduced according to device capabilities.
+The default threshold is 7 consecutive missed beacons; but
+this may be overridden by the device driver.
+Another name for the
+.Cm bmissthreshold
+parameter is
+.Cm bmiss .
+.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
+.Cm any , none ,
+or
+.Cm -
+for the address.
+This option is useful when more than one access point uses the same SSID.
+Another name for the
+.Cm bssid
+parameter is
+.Cm ap .
+.It Cm burst
+Enable packet bursting.
+Packet bursting is a transmission technique whereby the wireless
+medium is acquired once to send multiple frames and the interframe
+spacing is reduced.
+This technique can significantly increase throughput by reducing
+transmission overhead.
+Packet bursting is supported by the 802.11e QoS specification
+and some devices that do not support QoS may still be capable.
+By default packet bursting is enabled if a device is capable
+of doing it.
+To disable packet bursting, use
+.Fl burst .
+.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
+.Li any ,
+or
+.Cm -
+will clear any desired channel and, if the device is marked up,
+force a scan for a channel to operate on.
+Alternatively the frequency, in megahertz, may be specified
+instead of the channel number.
+.Pp
+When there are several ways to use a channel the channel
+number/frequency may be appended with attributes to clarify.
+For example, if a device is capable of operating on channel 6
+with 802.11n and 802.11g then one can specify that g-only use
+should be used by specifying ``6:g''.
+Similarly the channel width can be specified by appending it
+with ``/''; e.g. ``6/40'' specifies a 40MHz wide channel,
+These attributes can be combined as in: ``6:ht/40''.
+The full set of flags specified following a `:'' are:
+.Cm a
+(802.11a),
+.Cm b
+(802.11b),
+.Cm d
+(Atheros Dynamic Turbo mode),
+.Cm g
+(802.11g),
+.Cm h
+or
+.Cm n
+(802.11n aka HT),
+.Cm s
+(Atheros Static Turbo mode),
+and
+.Cm t
+(Atheros Dynamic Turbo mode, or appended to ``st'' and ``dt'').
+The full set of channel widths following a '/' are:
+.Cm 5 
+(5MHz aka quarter-rate channel),
+.Cm 10 
+(10MHz aka half-rate channel),
+.Cm 20 
+(20MHz mostly for use in specifying ht20),
+and
+.Cm 40 
+(40MHz mostly for use in specifying ht40),
+In addition,
+a 40MHz HT channel specification may include the location
+of the extension channel by appending ``+'' or ``-'' for above and below,
+respectively; e.g. ``2437:ht/40+'' specifies 40MHz wide HT operation 
+with the center channel at frequency 2437 and the extension channel above.
+.It Cm country Ar name
+Set the country code to use in calculating the regulatory constraints
+for operation.
+In particular the set of available channels, how the wireless device
+will operation on the channels, and the maximum transmit power that
+can be used on a channel are defined by this setting.
+Country/Region codes are specified as a 2-character abbreviation
+defined by ISO 3166 or using a longer, but possibly ambiguous, spelling;
+e.g. "ES" and "Spain".
+The set of country codes are taken from /etc/regdomain.xml and can also
+be viewed with the ``list countries'' request.
+Note that not all devices support changing the country code from a default
+setting; typically stored in EEPROM.
+See also
+.Cm regdomain ,
+.Cm indoor ,
+.Cm outdoor ,
+and
+.Cm anywhere .
+.It Cm dfs
+Enable Dynamic Frequency Selection (DFS) as specified in 802.11h.
+DFS embodies several facilities including detection of overlapping
+radar signals, dynamic transmit power control, and channel selection
+according to a least-congested criteria.
+DFS support is mandatory for some 5Ghz frequencies in certain
+locales (e.g. ETSI).
+By default DFS is enabled according to the regulatory definitions
+specified in /etc/regdomain.xml and the curent country code, regdomain,
+and channel.
+Note the underlying device (and driver) must support radar detection
+for full DFS support to work.
+To be fully compliant with the local regulatory agency frequencies that
+require DFS should not be used unless it is fully supported.
+Use
+.Fl dfs
+to disable this functionality for testing.
+.It Cm dotd
+Enable support for the 802.11d specification (default).
+When this support is enabled in station mode, beacon frames that advertise
+a country code different than the currently configured country code will
+cause an event to be dispatched to user applications.
+This event can be used by the station to adopt that country code and
+operate according to the associated regulatory constraints.
+When operating as an access point with 802.11d enabled the beacon and
+probe response frames transmitted will advertise the current regulatory
+domain settings.
+To disable 802.11d use
+.Fl dotd .
+.It Cm doth
+Enable 802.11h support including spectrum management.
+When 802.11h is enabled beacon and probe response frames will have
+the SpectrumMgt bit set in the capabilities field and
+country and power constraint information elements will be present.
+802.11h support also includes handling Channel Switch Announcements (CSA)
+which are a mechanism to coordinate channel changes by an access point.
+By default 802.11h is enabled if the device is capable.
+To disable 802.11h use
+.Fl doth .
+.It Cm deftxkey Ar index
+Set the default key to use for transmission.
+Typically this is only set when using WEP encryption.
+Note that you must set a default transmit key
+for the system to know which key to use in encrypting outbound traffic.
+The
+.Cm weptxkey
+is an alias for this request; it is provided for backwards compatibility.
+.It Cm dtimperiod Ar period
+Set the
+DTIM
+period for transmitting buffered multicast data frames when
+operating in ap mode.
+The
+.Ar period
+specifies the number of beacon intervals between DTIM
+and must be in the range 1 to 15.
+By default DTIM is 1 (i.e., DTIM occurs at each beacon).
+.It Cm dturbo
+Enable the use of Atheros Dynamic Turbo mode when communicating with
+another Dynamic Turbo-capable station.
+Dynamic Turbo mode is an Atheros-specific mechanism by which
+stations switch between normal 802.11 operation and a ``boosted''
+mode in which a 40MHz wide channel is used for communication.
+Stations using Dynamic Turbo mode operate boosted only when the
+channel is free of non-dturbo stations; when a non-dturbo station
+is identified on the channel all stations will automatically drop
+back to normal operation.
+By default, Dynamic Turbo mode is not enabled, even if the device is capable.
+Note that turbo mode (dynamic or static) is only allowed on some
+channels depending on the regulatory constraints; use the
+.Cm list chan
+command to identify the channels where turbo mode may be used.
+To disable Dynamic Turbo mode use
+.Fl dturbo .
+.It Cm dwds
+Enable Dynamic WDS (DWDS) support.
+DWDS is a facility by which 4-address traffic can be carried between
+stations operating in infrastructure mode.
+A station first associates to an access point and authenticates using
+normal procedures (e.g. WPA).
+Then 4-address frames are passed to carry traffic for stations
+operating on either side of the wireless link.
+DWDS extends the normal WDS mechanism by leveraging existing security
+protocols and eliminating static binding.
+.Pp
+When DWDS is enabled on an access point 4-address frames received from
+an authorized station will generate a ``DWDS discovery'' event to user
+applications.
+This event should be used to create a WDS interface that is bound
+to the remote station (and usually plumbed into a bridge).
+Once the WDS interface is up and running 4-address traffic then logically
+flows through that interface.
+.Pp
+When DWDS is enabled on a station, traffic with a destination address
+different from the peer station are encapsulated in a 4-address frame
+and transmitted to the peer.
+All 4-address traffic uses the security information of the stations
+(e.g. cryptographic keys).
+A station is associated using 802.11n facilities may transport
+4-address traffic using these same mechanisms; this depends on available
+resources and capabilities of the device.
+The DWDS implementation guards against layer 2 routing loops of
+multicast traffic.
+.It Cm ff
+Enable the use of Atheros Fast Frames when communicating with
+another Fast Frames-capable station.
+Fast Frames are an encapsulation technique by which two 802.3
+frames are transmitted in a single 802.11 frame.
+This can noticeably improve throughput but requires that the
+receiving station understand how to decapsulate the frame.
+Fast frame use is negotiated using the Atheros 802.11 vendor-specific
+protocol extension so enabling use is safe when communicating with
+non-Atheros devices.
+By default, use of fast frames is enabled if the device is capable.
+To explicitly disable fast frames, use
+.Fl ff .
+.It Cm fragthreshold Ar length
+Set the threshold for which transmitted frames are broken into fragments.
+The
+.Ar length
+argument is the frame size in bytes and must be in the range 256 to 2346.
+Setting
+.Ar length
+to
+.Li 2346 ,
+.Cm any ,
+or
+.Cm -
+disables transmit fragmentation.
+Not all adapters honor the fragmentation threshold.
+.It Cm hidessid
+When operating as an access point, do not broadcast the SSID
+in beacon frames or respond to probe request frames unless
+they are directed to the ap (i.e., they include the ap's SSID).
+By default, the SSID is included in beacon frames and
+undirected probe request frames are answered.
+To re-enable the broadcast of the SSID etc., use
+.Fl hidessid .
+.It Cm ht
+Enable use of High Throughput (HT) when using 802.11n (default).
+The 802.11n specification includes mechanisms for operation
+on 20MHz and 40MHz wide channels using different signalling mechanisms
+than specified in 802.11b, 802.11g, and 802.11a.
+Stations negotiate use of these facilities, termed HT20 and HT40,
+when they associate.
+To disable all use of 802.11n use
+.Fl ht .
+To disable use of HT20 (e.g. to force only HT40 use) use
+.Fl ht20 .
+To disable use of HT40 use
+.Fl ht40 .
+.Pp
+HT configuration is used to ``auto promote'' operation
+when several choices are available.
+For example, if a station associates to an 11n-capable access point
+it controls whether the station uses legacy operation, HT20, or HT40.
+When an 11n-capable device is setup as an access point and
+Auto Channel Selection is used to locate a channel to operate on,
+HT configuration controls whether legacy, HT20, or HT40 operation is setup
+on the selected channel.
+If a fixed channel is specified for a station then HT configuration can
+be given as part of the channel specification; e.g. 6:ht/20 to setup
+HT20 operation on channel 6.
+.It Cm htcompat
+Enable use of compatibility support for pre-802.11n devices (default).
+The 802.11n protocol specification went through several incompatible iterations.
+Some vendors implemented 11n support to older specifications that
+will not interoperate with a purely 11n-compliant station.
+In particular the information elements included in management frames
+for old devices are different.
+When compatibility support is enabled both standard and compatible data
+will be provided.
+Stations that associate using the compatiblity mechanisms are flagged
+in ``list sta''.
+To disable compatiblity support use
+.Fl htcompat .
+.It Cm htprotmode Ar technique
+For interfaces operating in 802.11n, use the specified
+.Ar technique
+for protecting HT frames in a mixed legacy/HT network.
+The set of valid techniques is
+.Cm off ,
+and
+.Cm rts
+(RTS/CTS, default).
+Technique names are case insensitive.
+.It Cm inact
+Enable inactivity processing for stations associated to an
+access point (default).
+When operating as an access point the 802.11 layer monitors
+the activity of each associated station.
+When a station is inactive for 5 minutes it will send several
+``probe frames'' to see if the station is still present.
+If no response is received then the station is deauthenticated.
+Applications that prefer to handle this work can disable this
+facility by using
+.Fl inact .
+.It Cm indoor
+Set the location to use in calculating regulatory constraints.
+The location is also advertised in beacon and probe response frames
+when 802.11d is enabled with
+.Cm dotd .
+See also
+.Cm outdoor ,
+.Cm anywhere ,
+.Cm country ,
+and
+.Cm regdomain .
+.It Cm list active
+Display the list of channels available for use taking into account
+any restrictions set with the
+.Cm chanlist
+directive.
+See the description of
+.Cm list chan
+for more information.
+.It Cm list caps
+Display the adaptor's capabilities, including the operating
+modes supported.
+.It Cm list chan
+Display the list of channels available for use.
+Channels are shown with their IEEE channel number, equivalent
+frequency, and usage modes.
+Channels identified as
+.Ql 11g
+are also usable in
+.Ql 11b
+mode.
+Channels identified as
+.Ql 11a Turbo
+may be used only for Atheros' Static Turbo mode
+(specified with
+. Cm mediaopt turbo ) .
+Channels marked with a
+.Ql *
+have a regulatory constraint that they be passively scanned.
+This means a station is not permitted to transmit on the channel until
+it identifies the channel is being used for 802.11 communication;
+typically by hearing a beacon frame from an access point operating
+on the channel.
+.Cm list freq
+is another way of requesting this information.
+By default a compacted list of channels is displayed; if the
+.Fl v
+option is specified then all channels are shown.
+.It Cm list countries
+Display the set of country codes and regulatory domains that can be
+used in regulatory configuration.
+.It Cm list mac
+Display the current MAC Access Control List state.
+Each address is prefixed with a character that indicates the
+current policy applied to it:
+.Ql +
+indicates the address is allowed access,
+.Ql -
+indicates the address is denied access,
+.Ql *
+indicates the address is present but the current policy open
+(so the ACL is not consulted).
+.It Cm list mesh
+Displays the mesh routing table, used for forwarding packets on a mesh
+network.
+.It Cm list regdomain
+Display the current regulatory settings including the available channels
+and transmit power caps.
+.It Cm list roam
+Display the parameters that govern roaming operation.
+.It Cm list txparam
+Display the parameters that govern transmit operation.
+.It Cm list txpower
+Display the transmit power caps for each channel.
+.It Cm list scan
+Display the access points and/or ad-hoc neighbors
+located in the vicinity.
+This information may be updated automatically by the adapter
+with a
+.Cm scan
+request or through background scanning.
+Depending on the capabilities of the stations the following
+flags can be included in the output:
+.Bl -tag -width 3n
+.It Li A
+Authorized.
+Indicates that the station is permitted to send/receive data frames.
+.It Li E
+Extended Rate Phy (ERP).
+Indicates that the station is operating in an 802.11g network
+using extended transmit rates.
+.It Li H
+High Throughput (HT).
+Indicates that the station is using HT transmit rates.
+If a `+' follows immediately after then the station associated
+using deprecated mechanisms supported only when
+.Cm htcompat
+is enabled.
+.It Li P
+Power Save.
+Indicates that the station is operating in power save mode.
+.It Li Q
+Quality of Service (QoS).
+Indicates that the station is using QoS encapsulation for
+data frame.
+QoS encapsulation is enabled only when WME mode is enabled.
+.It Li S
+Short Preamble.
+Indicates that the station is doing short preamble to optionally
+improve throughput performance with 802.11g and 802.11b.
+.It Li T
+Transitional Security Network (TSN).
+Indicates that the station associated using TSN; see also
+.Cm tsn
+below.
+.It Li W
+Wi-Fi Protected Setup (WPS).
+Indicates that the station associated using WPS.
+.El
+.Pp
+By default interesting information elements captured from the neighboring
+stations are displayed at the end of each row.
+Possible elements include:
+.Cm WME
+(station supports WME),
+.Cm WPA
+(station supports WPA),
+.Cm WPS
+(station supports WPS),
+.Cm RSN
+(station supports 802.11i/RSN),
+.Cm HTCAP
+(station supports 802.11n/HT communication),
+.Cm ATH
+(station supports Atheros protocol extensions),
+.Cm VEN
+(station supports unknown vendor-specific extensions).
+If the
+.Fl v
+flag is used all the information elements and their
+contents will be shown.
+Specifying the
+.Fl v
+flag also enables display of long SSIDs.
+The
+.Cm list ap
+command is another way of requesting this information.
+.It Cm list sta
+When operating as an access point display the stations that are
+currently associated.
+When operating in ad-hoc mode display stations identified as
+neighbors in the IBSS.
+When operating in mesh mode display stations identified as
+neighbors in the MBSS.
+When operating in station mode display the access point.
+Capabilities advertised by the stations are described under
+the
+.Cm scan
+request.
+Depending on the capabilities of the stations the following
+flags can be included in the output:
+.Bl -tag -width 3n
+.It Li A
+Authorized.
+Indicates that the station is permitted to send/receive data frames.
+.It Li E
+Extended Rate Phy (ERP).
+Indicates that the station is operating in an 802.11g network
+using extended transmit rates.
+.It Li H
+High Throughput (HT).
+Indicates that the station is using HT transmit rates.
+If a `+' follows immediately after then the station associated
+using deprecated mechanisms supported only when
+.Cm htcompat
+is enabled.
+.It Li P
+Power Save.
+Indicates that the station is operating in power save mode.
+.It Li Q
+Quality of Service (QoS).
+Indicates that the station is using QoS encapsulation for
+data frame.
+QoS encapsulation is enabled only when WME mode is enabled.
+.It Li S
+Short Preamble.
+Indicates that the station is doing short preamble to optionally
+improve throughput performance with 802.11g and 802.11b.
+.It Li T
+Transitional Security Network (TSN).
+Indicates that the station associated using TSN; see also
+.Cm tsn
+below.
+.It Li W
+Wi-Fi Protected Setup (WPS).
+Indicates that the station associated using WPS.
+.El
+.Pp
+By default information elements received from associated stations
+are displayed in a short form; the
+.Fl v
+flag causes this information to be displayed symbolically.
+.It Cm list wme
+Display the current channel parameters to use when operating in WME mode.
+If the
+.Fl v
+option is specified then both channel and BSS parameters are displayed
+for each AC (first channel, then BSS).
+When WME mode is enabled for an adaptor this information will be
+displayed with the regular status; this command is mostly useful
+for examining parameters when WME mode is disabled.
+See the description of the
+.Cm wme
+directive for information on the various parameters.
+.It Cm maxretry Ar count
+Set the maximum number of tries to use in sending unicast frames.
+The default setting is 6 but drivers may override this with a value
+they choose.
+.It Cm mcastrate Ar rate
+Set the rate for transmitting multicast/broadcast frames.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
+This rate should be valid for the current operating conditions;
+if an invalid rate is specified drivers are free to chose an
+appropriate rate.
+.It Cm mgtrate Ar rate
+Set the rate for transmitting management and/or control frames.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
+.It Cm outdoor
+Set the location to use in calculating regulatory constraints.
+The location is also advertised in beacon and probe response frames
+when 802.11d is enabled with
+.Cm dotd .
+See also
+.Cm anywhere ,
+.Cm country ,
+.Cm indoor ,
+and
+.Cm regdomain .
+.It Cm powersave
+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.
+Not all devices support power save operation as a client.
+The 802.11 specification requires that all access points support
+power save but some drivers do not.
+Use
+.Fl powersave
+to disable powersave operation when operating as a client.
+.It Cm powersavesleep Ar sleep
+Set the desired max powersave sleep time in TU's (1024 usecs).
+By default the max powersave sleep time is 100 TU's.
+.It Cm protmode Ar technique
+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
+.Cm off , cts
+(CTS to self),
+and
+.Cm rtscts
+(RTS/CTS).
+Technique names are case insensitive.
+Not all devices support
+.Cm cts
+as a protection technique.
+.It Cm pureg
+When operating as an access point in 802.11g mode allow only
+11g-capable stations to associate (11b-only stations are not
+permitted to associate).
+To allow both 11g and 11b-only stations to associate, use
+.Fl pureg .
+.It Cm puren
+When operating as an access point in 802.11n mode allow only
+HT-capable stations to associate (legacy stations are not
+permitted to associate).
+To allow both HT and legacy stations to associate, use
+.Fl puren .
+.It Cm regdomain Ar sku
+Set the regulatory domain to use in calculating the regulatory constraints
+for operation.
+In particular the set of available channels, how the wireless device
+will operation on the channels, and the maximum transmit power that
+can be used on a channel are defined by this setting.
+Regdomain codes (SKU's) are taken from /etc/regdomain.xml and can also
+be viewed with the ``list countries'' request.
+Note that not all devices support changing the regdomain from a default
+setting; typically stored in EEPROM.
+See also
+.Cm country ,
+.Cm indoor ,
+.Cm outdoor ,
+and
+.Cm anywhere .
+.It Cm rifs
+Enable use of Reduced InterFrame Spacing (RIFS) when operating in 802.11n
+on an HT channel.
+Note that RIFS must be supported by both the station and access point
+for it to be used.
+To disable RIFS use
+.Fl rifs .
+.It Cm roam:rate Ar rate
+Set the threshold for controlling roaming when operating in a BSS.
+The
+.Ar rate
+parameter specifies the transmit rate in megabits
+at which roaming should be considered.
+If the current transmit rate drops below this setting and background scanning
+is enabled, then the system will check if a more desirable access point is
+available and switch over to it.
+The current scan cache contents are used if they are considered
+valid according to the
+.Cm scanvalid
+parameter; otherwise a background scan operation is triggered before
+any selection occurs.
+Each channel type has a separate rate threshold; the default values are:
+12 Mb/s (11a), 2 Mb/s (11b), 2 Mb/s (11g), MCS 1 (11na, 11ng).
+.It Cm roam:rssi Ar rssi
+Set the threshold for controlling roaming when operating in a BSS.
+The
+.Ar rssi
+parameter specifies the receive signal strength in dBm units
+at which roaming should be considered.
+If the current rssi drops below this setting and background scanning
+is enabled, then the system will check if a more desirable access point is
+available and switch over to it.
+The current scan cache contents are used if they are considered
+valid according to the
+.Cm scanvalid
+parameter; otherwise a background scan operation is triggered before
+any selection occurs.
+Each channel type has a separate rssi threshold; the default values are
+all 7 dBm.
+.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
+.Cm device
+(leave it to the hardware device to decide),
+.Cm auto
+(handle either in the device or the operating system\[em]as appropriate),
+.Cm 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 used by applications such as
+.Xr wpa_supplicant 8
+that want to control the selection of an access point.
+.It Cm rtsthreshold Ar length
+Set the threshold for which
+transmitted frames are preceded by transmission of an
+RTS
+control frame.
+The
+.Ar length
+argument
+is the frame size in bytes and must be in the range 1 to 2346.
+Setting
+.Ar length
+to
+.Li 2346 ,
+.Cm any ,
+or
+.Cm -
+disables transmission of RTS frames.
+Not all adapters support setting the RTS threshold.
+.It Cm scan
+Initiate a scan of neighboring stations, wait for it to complete, and
+display all stations found.
+Only the super-user can initiate a scan.
+See
+.Cm list scan
+for information on the display.
+By default a background scan is done; otherwise a foreground
+scan is done and the station may roam to a different access point.
+The
+.Cm list scan
+request can be used to show recent scan results without
+initiating a new scan.
+.It Cm scanvalid Ar threshold
+Set the maximum time the scan cache contents are considered valid;
+i.e. will be used without first triggering a scan operation to
+refresh the data.
+The
+.Ar threshold
+parameter is specified in seconds and defaults to 60 seconds.
+The minimum setting for
+.Ar threshold
+is 10 seconds.
+One should take care setting this threshold; if it is set too low
+then attempts to roam to another access point may trigger unnecessary
+background scan operations.
+.It Cm shortgi
+Enable use of Short Guard Interval when operating in 802.11n
+on an HT channel.
+NB: this currently enables Short GI on both HT40 and HT20 channels.
+To disable Short GI use
+.Fl shortgi .
+.It Cm smps
+Enable use of Static Spatial Multiplexing Power Save (SMPS)
+when operating in 802.11n.
+A station operating with Static SMPS maintains only a single
+receive chain active (this can significantly reduce power consumption).
+To disable SMPS use
+.Fl smps .
+.It Cm smpsdyn
+Enable use of Dynamic Spatial Multiplexing Power Save (SMPS)
+when operating in 802.11n.
+A station operating with Dynamic SMPS maintains only a single
+receive chain active but switches to multiple receive chains when it
+receives an RTS frame (this can significantly reduce power consumption).
+Note that stations cannot distinguish between RTS/CTS intended to
+enable multiple receive chains and those used for other purposes.
+To disable SMPS use
+.Fl smps .
+.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 preceded by
+.Ql 0x .
+Additionally, the SSID may be cleared by setting it to
+.Ql - .
+.It Cm tdmaslot Ar slot
+When operating with TDMA, use the specified
+.Ar slot
+configuration.
+The
+.Ar slot
+is a number between 0 and the maximum number of slots in the BSS.
+Note that a station configured as slot 0 is a master and
+will broadcast beacon frames advertising the BSS;
+stations configured to use other slots will always
+scan to locate a master before they ever transmit.
+By default
+.Cm tdmaslot
+is set to 1.
+.It Cm tdmaslotcnt Ar cnt
+When operating with TDMA, setup a BSS with
+.Ar cnt
+slots.
+The slot count may be at most 8.
+The current implementation is only tested with two stations
+(i.e. point to point applications).
+This setting is only meaningful when a station is configured as slot 0;
+other stations adopt this setting from the BSS they join.
+By default
+.Cm tdmaslotcnt
+is set to 2.
+.It Cm tdmaslotlen Ar len
+When operating with TDMA, setup a BSS such that each station has a slot
+.Ar len
+microseconds long.
+The slot length must be at least 150 microseconds (1/8 TU)
+and no more than 65 milliseconds.
+Note that setting too small a slot length may result in poor channel
+bandwidth utilization due to factors such as timer granularity and
+guard time.
+This setting is only meaningful when a station is configured as slot 0;
+other stations adopt this setting from the BSS they join.
+By default
+.Cm tdmaslotlen
+is set to 10 milliseconds.
+.It Cm tdmabintval Ar intval
+When operating with TDMA, setup a BSS such that beacons are transmitted every
+.Ar intval
+superframes to synchronize the TDMA slot timing.
+A superframe is defined as the number of slots times the slot length; e.g.
+a BSS with two slots of 10 milliseconds has a 20 millisecond superframe.
+The beacon interval may not be zero.
+A lower setting of
+.Cm tdmabintval
+causes the timers to be resynchronized more often; this can be help if
+significant timer drift is observed.
+By default
+.Cm tdmabintval
+is set to 5.
+.It Cm tsn
+When operating as an access point with WPA/802.11i allow legacy
+stations to associate using static key WEP and open authentication.
+To disallow legacy station use of WEP, use
+.Fl tsn .
+.It Cm txpower Ar power
+Set the power used to transmit frames.
+The
+.Ar power
+argument is specified in .5 dBm units.
+Out of range values are truncated.
+Typically only a few discreet power settings are available and
+the driver will use the setting closest to the specified value.
+Not all adapters support changing the transmit power.
+.It Cm ucastrate Ar rate
+Set a fixed rate for transmitting unicast frames.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
+This rate should be valid for the current operating conditions;
+if an invalid rate is specified drivers are free to chose an
+appropriate rate.
+.It Cm wepmode Ar mode
+Set the desired WEP mode.
+Not all adapters support all modes.
+The set of valid modes is
+.Cm off , on ,
+and
+.Cm mixed .
+The
+.Cm mixed
+mode explicitly tells the adaptor to allow association with access
+points which allow both encrypted and unencrypted traffic.
+On these adapters,
+.Cm on
+means that the access point must only allow encrypted connections.
+On other adapters,
+.Cm on
+is generally another name for
+.Cm mixed .
+Modes are case insensitive.
+.It Cm weptxkey Ar index
+Set the WEP key to be used for transmission.
+This is the same as setting the default transmission key with
+.Cm deftxkey .
+.It Cm wepkey Ar key Ns | Ns Ar index : Ns Ar key
+Set the selected WEP key.
+If an
+.Ar index
+is not given, key 1 is set.
+A WEP key will be either 5 or 13
+characters (40 or 104 bits) depending of the local network and the
+capabilities of the adaptor.
+It may be specified either as a plain
+string or as a string of hexadecimal digits preceded by
+.Ql 0x .
+For maximum portability, hex keys are recommended;
+the mapping of text keys to WEP encryption is usually driver-specific.
+In particular, the
+.Tn Windows
+drivers do this mapping differently to
+.Fx .
+A key may be cleared by setting it to
+.Ql - .
+If WEP is supported then there are at least four keys.
+Some adapters support more than four keys.
+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.
+.Pp
+Note that you must set a default transmit key with
+.Cm deftxkey
+for the system to know which key to use in encrypting outbound traffic.
+.It Cm wme
+Enable Wireless Multimedia 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 .
+Another name for this parameter is
+.Cm wmm .
+.Pp
+The following parameters are meaningful only when WME support is in use.
+Parameters are specified per-AC (Access Category) and
+split into those that are used by a station when acting
+as an access point and those for client stations in the BSS.
+The latter are received from the access point and may not be changed
+(at the station).
+The following Access Categories are recognized:
+.Pp
+.Bl -tag -width ".Cm AC_BK" -compact
+.It Cm AC_BE
+(or
+.Cm BE )
+best effort delivery,
+.It Cm AC_BK
+(or
+.Cm BK )
+background traffic,
+.It Cm AC_VI
+(or
+.Cm VI )
+video traffic,
+.It Cm AC_VO
+(or
+.Cm VO )
+voice traffic.
+.El
+.Pp
+AC parameters are case-insensitive.
+Traffic classification is done in the operating system using the
+vlan priority associated with data frames or the
+ToS (Type of Service) indication in IP-encapsulated frames.
+If neither information is present, traffic is assigned to the
+Best Effort (BE) category.
+.Bl -tag -width indent
+.It Cm ack Ar ac
+Set the ACK policy for QoS transmissions by the local station;
+this controls whether or not data frames transmitted by a station
+require an ACK response from the receiving station.
+To disable waiting for an ACK use
+.Fl ack .
+This parameter is applied only to the local station.
+.It Cm acm Ar ac
+Enable the Admission Control Mandatory (ACM) mechanism
+for transmissions by the local station.
+To disable the ACM use
+.Fl acm .
+On stations in a BSS this parameter is read-only and indicates
+the setting received from the access point.
+NB: ACM is not supported right now.
+.It Cm aifs Ar ac Ar count
+Set the Arbitration Inter Frame Spacing (AIFS)
+channel access parameter to use for transmissions
+by the local station.
+On stations in a BSS this parameter is read-only and indicates
+the setting received from the access point.
+.It Cm cwmin Ar ac Ar count
+Set the CWmin channel access parameter to use for transmissions
+by the local station.
+On stations in a BSS this parameter is read-only and indicates
+the setting received from the access point.
+.It Cm cwmax Ar ac Ar count
+Set the CWmax channel access parameter to use for transmissions
+by the local station.
+On stations in a BSS this parameter is read-only and indicates
+the setting received from the access point.
+.It Cm txoplimit Ar ac Ar limit
+Set the Transmission Opportunity Limit channel access parameter
+to use for transmissions by the local station.
+This parameter defines an interval of time when a WME station
+has the right to initiate transmissions onto the wireless medium.
+On stations in a BSS this parameter is read-only and indicates
+the setting received from the access point.
+.It Cm bss:aifs Ar ac Ar count
+Set the AIFS channel access parameter to send to stations in a BSS.
+This parameter is meaningful only when operating in ap mode.
+.It Cm bss:cwmin Ar ac Ar count
+Set the CWmin channel access parameter to send to stations in a BSS.
+This parameter is meaningful only when operating in ap mode.
+.It Cm bss:cwmax Ar ac Ar count
+Set the CWmax channel access parameter to send to stations in a BSS.
+This parameter is meaningful only when operating in ap mode.
+.It Cm bss:txoplimit Ar ac Ar limit
+Set the TxOpLimit channel access parameter to send to stations in a BSS.
+This parameter is meaningful only when operating in ap mode.
+.El
+.It Cm wps
+Enable Wireless Privacy Subscriber support.
+Note that WPS support requires a WPS-capable supplicant.
+To disable this function use
+.Fl wps .
+.El
+.Pp
+The following parameters support an optional access control list
+feature available with some adapters when operating in ap mode; see
+.Xr wlan_acl 4 .
+This facility allows an access point to accept/deny association
+requests based on the MAC address of the station.
+Note that this feature does not significantly enhance security
+as MAC address spoofing is easy to do.
+.Bl -tag -width indent
+.It Cm mac:add Ar address
+Add the specified MAC address to the database.
+Depending on the policy setting association requests from the
+specified station will be allowed or denied.
+.It Cm mac:allow
+Set the ACL policy to permit association only by
+stations registered in the database.
+.It Cm mac:del Ar address
+Delete the specified MAC address from the database.
+.It Cm mac:deny
+Set the ACL policy to deny association only by
+stations registered in the database.
+.It Cm mac:kick Ar address
+Force the specified station to be deauthenticated.
+This typically is done to block a station after updating the
+address database.
+.It Cm mac:open
+Set the ACL policy to allow all stations to associate.
+.It Cm mac:flush
+Delete all entries in the database.
+.It Cm mac:radius
+Set the ACL policy to permit association only by
+stations approved by a RADIUS server.
+Note that this feature requires the
+.Xr hostapd 8
+program be configured to do the right thing
+as it handles the RADIUS processing
+(and marks stations as authorized).
+.El
+.Pp
+The following parameters are related to a wireless interface operating in mesh
+mode:
+.Bl -tag -width indent
+.It Cm meshid Ar meshid
+Set the desired Mesh Identifier.
+The Mesh ID is a string up to 32 characters in length.
+A mesh interface must have a Mesh Identifier specified
+to reach an operational state.
+.It Cm meshttl Ar ttl
+Set the desired ``time to live'' for mesh forwarded packets;
+this is the number of hops a packet may be forwarded before
+it is discarded.
+The default setting for
+.Cm meshttl
+is 31.
+.It Cm meshpeering
+Enable or disable peering with neighbor mesh stations.
+Stations must peer before any data packets can be exchanged.
+By default
+.Cm meshpeering
+is enabled.
+.It Cm meshforward
+Enable or disable forwarding packets by a mesh interface.
+By default
+.Cm meshforward
+is enabled.
+.It Cm meshmetric Ar protocol
+Set the specified
+.Ar protocol
+as the link metric protocol used on a mesh network.
+The default protocol is called
+.Ar AIRTIME .
+The mesh interface will restart after changing this setting.
+.It Cm meshpath Ar protocol
+Set the specified
+.Ar protocol
+as the path selection protocol used on a mesh network.
+The only available protocol at the moment is called
+.Ar HWMP
+(Hybrid Wireless Mesh Protocol).
+The mesh interface will restart after changing this setting.
+.It Cm hwmprootmode Ar mode
+Stations on a mesh network can operate as ``root nodes.''
+Root nodes try to find paths to all mesh nodes and advertise themselves
+regularly.
+When there is a root mesh node on a network, other mesh nodes can setup
+paths between themselves faster because they can use the root node
+to find the destination.
+This path may not be the best, but on-demand
+routing will eventually find the best path.
+The following modes are recognized:
+.Pp
+.Bl -tag -width ".Cm PROACTIVE" -compact
+.It Cm DISABLED
+Disable root mode.
+.It Cm NORMAL
+Send broadcast path requests every two seconds.
+Nodes on the mesh without a path to this root mesh station with try to
+discover a path to us.
+.It Cm PROACTIVE
+Send broadcast path requests every two seconds and every node must reply with
+with a path reply even if it already has a path to this root mesh station,
+.It Cm RANN
+Send broadcast root annoucement (RANN) frames.
+Nodes on the mesh without a path to this root mesh station with try to
+discover a path to us.
+.El
+By default
+.Cm hwmprootmode 
+is set to
+.Ar DISABLED .
+.It Cm hwmpmaxhops Ar cnt
+Set the maximum number of hops allowed in an HMWP path to
+.Ar cnt .
+The default setting for
+.Cm hwmpmaxhops
+is 31.
+.El
+.Pp
+The following parameters are 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 stationname Ar name
+Set the name of this station.
+The station name is not part of the IEEE 802.11
+protocol though some interfaces 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.
+One can also use
+.Cm station
+for
+.Bsx
+compatibility.
+.It Cm wep
+Another way of saying
+.Cm wepmode on .
+Included for
+.Bsx
+compatibility.
+.It Fl wep
+Another way of saying
+.Cm wepmode off .
+Included for
+.Bsx
+compatibility.
+.It Cm nwkey key
+Another way of saying:
+.Dq Li "wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-" .
+Included for
+.Nx
+compatibility.
+.It Cm nwkey Xo
+.Sm off
+.Ar n : k1 , k2 , k3 , k4
+.Sm on
+.Xc
+Another way of saying
+.Dq Li "wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4" .
+Included for
+.Nx
+compatibility.
+.It Fl nwkey
+Another way of saying
+.Cm wepmode off .
+Included for
+.Nx
+compatibility.
+.El
+.Pp
+The following parameters are specific to bridge interfaces:
+.Bl -tag -width indent
+.It Cm addm Ar interface
+Add the interface named by
+.Ar interface
+as a member of the bridge.
+The interface is put into promiscuous mode
+so that it can receive every packet sent on the network.
+.It Cm deletem Ar interface
+Remove the interface named by
+.Ar interface
+from the bridge.
+Promiscuous mode is disabled on the interface when
+it is removed from the bridge.
+.It Cm maxaddr Ar size
+Set the size of the bridge address cache to
+.Ar size .
+The default is 100 entries.
+.It Cm timeout Ar seconds
+Set the timeout of address cache entries to
+.Ar seconds
+seconds.
+If
+.Ar seconds
+is zero, then address cache entries will not be expired.
+The default is 240 seconds.
+.It Cm addr
+Display the addresses that have been learned by the bridge.
+.It Cm static Ar interface-name Ar address
+Add a static entry into the address cache pointing to
+.Ar interface-name .
+Static entries are never aged out of the cache or re-placed, even if the
+address is seen on a different interface.
+.It Cm deladdr Ar address
+Delete
+.Ar address
+from the address cache.
+.It Cm flush
+Delete all dynamically-learned addresses from the address cache.
+.It Cm flushall
+Delete all addresses, including static addresses, from the address cache.
+.It Cm discover Ar interface
+Mark an interface as a
+.Dq discovering
+interface.
+When the bridge has no address cache entry
+(either dynamic or static)
+for the destination address of a packet,
+the bridge will forward the packet to all
+member interfaces marked as
+.Dq discovering .
+This is the default for all interfaces added to a bridge.
+.It Cm -discover Ar interface
+Clear the
+.Dq discovering
+attribute on a member interface.
+For packets without the
+.Dq discovering
+attribute, the only packets forwarded on the interface are broadcast
+or multicast packets and packets for which the destination address
+is known to be on the interface's segment.
+.It Cm learn Ar interface
+Mark an interface as a
+.Dq learning
+interface.
+When a packet arrives on such an interface, the source
+address of the packet is entered into the address cache as being a
+destination address on the interface's segment.
+This is the default for all interfaces added to a bridge.
+.It Cm -learn Ar interface
+Clear the
+.Dq learning
+attribute on a member interface.
+.It Cm sticky Ar interface
+Mark an interface as a
+.Dq sticky
+interface.
+Dynamically learned address entries are treated at static once entered into
+the cache.
+Sticky entries are never aged out of the cache or replaced, even if the
+address is seen on a different interface.
+.It Cm -sticky Ar interface
+Clear the
+.Dq sticky
+attribute on a member interface.
+.It Cm private Ar interface
+Mark an interface as a
+.Dq private
+interface.
+A private interface does not forward any traffic to any other port that is also
+a private interface.
+.It Cm -private Ar interface
+Clear the
+.Dq private
+attribute on a member interface.
+.It Cm span Ar interface
+Add the interface named by
+.Ar interface
+as a span port on the bridge.
+Span ports transmit a copy of every frame received by the bridge.
+This is most useful for snooping a bridged network passively on
+another host connected to one of the span ports of the bridge.
+.It Cm -span Ar interface
+Delete the interface named by
+.Ar interface
+from the list of span ports of the bridge.
+.It Cm stp Ar interface
+Enable Spanning Tree protocol on
+.Ar interface .
+The
+.Xr if_bridge 4
+driver has support for the IEEE 802.1D Spanning Tree protocol (STP).
+Spanning Tree is used to detect and remove loops in a network topology.
+.It Cm -stp Ar interface
+Disable Spanning Tree protocol on
+.Ar interface .
+This is the default for all interfaces added to a bridge.
+.It Cm edge Ar interface
+Set
+.Ar interface
+as an edge port.
+An edge port connects directly to end stations cannot create bridging
+loops in the network, this allows it to transition straight to forwarding.
+.It Cm -edge Ar interface
+Disable edge status on
+.Ar interface .
+.It Cm autoedge Ar interface
+Allow
+.Ar interface
+to automatically detect edge status.
+This is the default for all interfaces added to a bridge.
+.It Cm -autoedge Ar interface
+Disable automatic edge status on
+.Ar interface .
+.It Cm ptp Ar interface
+Set the
+.Ar interface
+as a point to point link.
+This is required for straight transitions to forwarding and
+should be enabled on a direct link to another RSTP capable switch.
+.It Cm -ptp Ar interface
+Disable point to point link status on
+.Ar interface .
+This should be disabled for a half duplex link and for an interface
+connected to a shared network segment,
+like a hub or a wireless network.
+.It Cm autoptp Ar interface
+Automatically detect the point to point status on
+.Ar interface
+by checking the full duplex link status.
+This is the default for interfaces added to the bridge.
+.It Cm -autoptp Ar interface
+Disable automatic point to point link detection on
+.Ar interface .
+.It Cm maxage Ar seconds
+Set the time that a Spanning Tree protocol configuration is valid.
+The default is 20 seconds.
+The minimum is 6 seconds and the maximum is 40 seconds.
+.It Cm fwddelay Ar seconds
+Set the time that must pass before an interface begins forwarding
+packets when Spanning Tree is enabled.
+The default is 15 seconds.
+The minimum is 4 seconds and the maximum is 30 seconds.
+.It Cm hellotime Ar seconds
+Set the time between broadcasting of Spanning Tree protocol
+configuration messages.
+The hello time may only be changed when operating in legacy stp mode.
+The default is 2 seconds.
+The minimum is 1 second and the maximum is 2 seconds.
+.It Cm priority Ar value
+Set the bridge priority for Spanning Tree.
+The default is 32768.
+The minimum is 0 and the maximum is 61440.
+.It Cm proto Ar value
+Set the Spanning Tree protocol.
+The default is rstp.
+The available options are stp and rstp.
+.It Cm holdcnt Ar value
+Set the transmit hold count for Spanning Tree.
+This is the number of packets transmitted before being rate limited.
+The default is 6.
+The minimum is 1 and the maximum is 10.
+.It Cm ifpriority Ar interface Ar value
+Set the Spanning Tree priority of
+.Ar interface
+to
+.Ar value .
+The default is 128.
+The minimum is 0 and the maximum is 240.
+.It Cm ifpathcost Ar interface Ar value
+Set the Spanning Tree path cost of
+.Ar interface
+to
+.Ar value .
+The default is calculated from the link speed.
+To change a previously selected path cost back to automatic, set the
+cost to 0.
+The minimum is 1 and the maximum is 200000000.
+.It Cm ifmaxaddr Ar interface Ar size
+Set the maximum number of hosts allowed from an interface, packets with unknown
+source addresses are dropped until an existing host cache entry expires or is
+removed.
+Set to 0 to disable.
+.El
+.Pp
+The following parameters are specific to lagg interfaces:
+.Bl -tag -width indent
+.It Cm laggport Ar interface
+Add the interface named by
+.Ar interface
+as a port of the aggregation interface.
+.It Cm -laggport Ar interface
+Remove the interface named by
+.Ar interface
+from the aggregation interface.
+.It Cm laggproto Ar proto
+Set the aggregation protocol.
+The default is failover.
+The available options are failover, fec, lacp, loadbalance, roundrobin and
+none.
+.El
+.Pp
+The following parameters are specific to IP tunnel interfaces,
+.Xr gif 4 :
+.Bl -tag -width indent
+.It Cm tunnel Ar src_addr dest_addr
+Configure the physical source and destination address for IP tunnel
+interfaces.
+The arguments
+.Ar src_addr
+and
+.Ar dest_addr
+are interpreted as the outer source/destination for the encapsulating
+IPv4/IPv6 header.
+.It Fl tunnel
+Unconfigure the physical source and destination address for IP tunnel
+interfaces previously configured with
+.Cm tunnel .
+.It Cm deletetunnel
+Another name for the
+.Fl tunnel
+parameter.
+.It Cm accept_rev_ethip_ver
+Set a flag to acccept both correct EtherIP packets and ones
+with reversed version field.  Enabled by default.
+This is for backward compatibility with
+.Fx 6.1 ,
+6.2, 6.3, 7.0, and 7.1.
+.It Cm -accept_rev_ethip_ver
+Clear a flag
+.Cm accept_rev_ethip_ver .
+.It Cm send_rev_ethip_ver
+Set a flag to send EtherIP packets with reversed version
+field intentionally.  Disabled by default.
+This is for backward compatibility with
+.Fx 6.1 ,
+6.2, 6.3, 7.0, and 7.1.
+.It Cm -send_rev_ethip_ver
+Clear a flag
+.Cm send_rev_ethip_ver .
+.El
+.Pp
+The following parameters are specific to GRE tunnel interfaces,
+.Xr gre 4 :
+.Bl -tag -width indent
+.It Cm grekey Ar key
+Configure the GRE key to be used for outgoing packets.
+Note that
+.Xr gre 4 will always accept GRE packets with invalid or absent keys.
+This command will result in a four byte MTU reduction on the interface.
+.El
+.Pp
+The following parameters are specific to
+.Xr pfsync 4
+interfaces:
+.Bl -tag -width indent
+.It Cm maxupd Ar n
+Set the maximum number of updates for a single state which
+can be collapsed into one.
+This is an 8-bit number; the default value is 128.
+.El
+.Pp
+The following parameters are specific to
+.Xr vlan 4
+interfaces:
+.Bl -tag -width indent
+.It Cm vlan Ar vlan_tag
+Set the VLAN tag value to
+.Ar vlan_tag .
+This value is a 16-bit number which is used to create an 802.1Q
+VLAN header for packets sent from the
+.Xr vlan 4
+interface.
+Note that
+.Cm vlan
+and
+.Cm vlandev
+must both be set at the same time.
+.It Cm vlandev Ar iface
+Associate the physical interface
+.Ar iface
+with a
+.Xr vlan 4
+interface.
+Packets transmitted through the
+.Xr vlan 4
+interface will be
+diverted to the specified physical interface
+.Ar iface
+with 802.1Q VLAN encapsulation.
+Packets with 802.1Q encapsulation received
+by the parent interface with the correct VLAN tag will be diverted to
+the associated
+.Xr vlan 4
+pseudo-interface.
+The
+.Xr vlan 4
+interface is assigned a
+copy of the parent interface's flags and the parent's ethernet address.
+The
+.Cm vlandev
+and
+.Cm vlan
+must both be set at the same time.
+If the
+.Xr vlan 4
+interface already has
+a physical interface associated with it, this command will fail.
+To
+change the association to another physical interface, the existing
+association must be cleared first.
+.Pp
+Note: if the hardware tagging capability
+is set on the parent interface, the
+.Xr vlan 4
+pseudo
+interface's behavior changes:
+the
+.Xr vlan 4
+interface recognizes that the
+parent interface supports insertion and extraction of VLAN tags on its
+own (usually in firmware) and that it should pass packets to and from
+the parent unaltered.
+.It Fl vlandev Op Ar iface
+If the driver is a
+.Xr vlan 4
+pseudo device, disassociate the parent interface from it.
+This breaks the link between the
+.Xr vlan 4
+interface and its parent,
+clears its VLAN tag, flags and its link address and shuts the interface down.
+The
+.Ar iface
+argument is useless and hence deprecated.
+.El
+.Pp
+The following parameters are specific to
+.Xr carp 4
+interfaces:
+.Bl -tag -width indent
+.It Cm advbase Ar seconds
+Specifies the base of the advertisement interval in seconds.
+The acceptable values are 1 to 255.
+The default value is 1.
+.\" The default value is
+.\" .Dv CARP_DFLTINTV .
+.It Cm advskew Ar interval
+Specifies the skew to add to the base advertisement interval to
+make one host advertise slower than another host.
+It is specified in 1/256 of seconds.
+The acceptable values are 1 to 254.
+The default value is 0.
+.It Cm pass Ar phrase
+Set the authentication key to
+.Ar phrase .
+.It Cm vhid Ar n
+Set the virtual host ID.
+This is a required setting.
+Acceptable values are 1 to 255.
+.El
+.Pp
+The
+.Nm
+utility displays the current configuration for a network interface
+when no optional parameters are supplied.
+If a protocol family is specified,
+.Nm
+will report only the details specific to that protocol family.
+.Pp
+If the
+.Fl m
+flag is passed before an interface name,
+.Nm
+will display the capability list and all
+of the supported media for the specified interface.
+If
+.Fl L
+flag is supplied, address lifetime is displayed for IPv6 addresses,
+as time offset string.
+.Pp
+Optionally, the
+.Fl a
+flag may be used instead of an interface name.
+This flag instructs
+.Nm
+to display information about all interfaces in the system.
+The
+.Fl d
+flag limits this to interfaces that are down, and
+.Fl u
+limits this to interfaces that are up.
+When no arguments are given,
+.Fl a
+is implied.
+.Pp
+The
+.Fl l
+flag may be used to list all available interfaces on the system, with
+no other additional information.
+Use of this flag is mutually exclusive
+with all other flags and commands, except for
+.Fl d
+(only list interfaces that are down)
+and
+.Fl u
+(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.
+Use of this flag is mutually exclusive with all other flags and commands.
+.Pp
+The
+.Fl k
+flag causes keying information for the interface, if available, to be
+printed.
+For example, the values of 802.11 WEP keys will be printed, if accessible to
+the current user.
+This information is not printed by default, as it may be considered
+sensitive.
+.Pp 
+If the network interface driver is not present in the kernel then
+.Nm
+will attempt to load it.
+The
+.Fl n
+flag disables this behavior.
+.Pp
+Only the super-user may modify the configuration of a network interface.
+.Sh NOTES
+The media selection system is relatively new and only some drivers support
+it (or have need for it).
+.Sh EXAMPLES
+Assign the IPv4 address
+.Li 192.0.2.10 ,
+with a network mask of
+.Li 255.255.255.0 ,
+to the interface
+.Li fxp0 :
+.Dl # ifconfig fxp0 inet 192.0.2.10 netmask 255.255.255.0
+.Pp
+Add the IPv4 address
+.Li 192.0.2.45 ,
+with the CIDR network prefix
+.Li /28 ,
+to the interface
+.Li ed0 ,
+using
+.Cm add
+as a synonym for the canonical form of the option
+.Cm alias :
+.Dl # ifconfig ed0 inet 192.0.2.45/28 add
+.Pp
+Remove the IPv4 address
+.Li 192.0.2.45
+from the interface
+.Li ed0 :
+.Dl # ifconfig ed0 inet 192.0.2.45 -alias
+.Pp
+Add the IPv6 address
+.Li 2001:DB8:DBDB::123/48
+to the interface
+.Li em0 :
+.Dl # ifconfig em0 inet6 2001:db8:bdbd::123 prefixlen 48 alias
+Note that lower case hexadecimal IPv6 addresses are acceptable.
+.Pp
+Remove the IPv6 address added in the above example,
+using the
+.Li /
+character as shorthand for the network prefix,
+and using
+.Cm delete
+as a synonym for the canonical form of the option
+.Fl alias :
+.Dl # ifconfig em0 inet6 2001:db8:bdbd::123/48 delete
+.Pp
+Configure the interface
+.Li xl0 ,
+to use 100baseTX, full duplex Ethernet media options:
+.Dl # ifconfig xl0 media 100baseTX mediaopt full-duplex
+.Pp
+Label the em0 interface as an uplink:
+.Pp
+.Dl # ifconfig em0 description \&"Uplink to Gigabit Switch 2\&"
+.Pp
+Create the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 create
+.Pp
+Destroy the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 destroy
+.Sh DIAGNOSTICS
+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 SEE ALSO
+.Xr netstat 1 ,
+.Xr carp 4 ,
+.Xr gif 4 ,
+.Xr netintro 4 ,
+.Xr pfsync 4 ,
+.Xr polling 4 ,
+.Xr vlan 4 ,
+.\" .Xr eon 5 ,
+.Xr rc 8 ,
+.Xr routed 8 ,
+.Xr jail 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.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 odd.
+Do this at your own risk.
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifconfig.c b/freebsd-userspace/commands/sbin/ifconfig/ifconfig.c
new file mode 100644
index 0000000..f0c77d1
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifconfig.c
@@ -0,0 +1,1185 @@
+/*
+ * 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 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/time.h>
+#ifdef __rtems__
+#include <freebsd/sys/module.h>
+#include <freebsd/sys/linker.h>
+#else
+#include <sys/module.h>
+#include <sys/linker.h>
+#endif
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#ifdef __rtems__
+#include <freebsd/net/if_var.h>
+#else
+#include <net/if_var.h>
+#endif
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+/* IP */
+#include <netinet/in.h>
+#ifdef __rtems__
+#include <freebsd/netinet/in_var.h>
+#else
+#include <netinet/in_var.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ifaddrs.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifndef __rtems__
+#include <jail.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+/*
+ * 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;
+
+char	name[IFNAMSIZ];
+char	*descr = NULL;
+size_t	descrlen = 64;
+int	setaddr;
+int	setmask;
+int	doalias;
+int	clearaddr;
+int	newaddr = 1;
+int	verbose;
+int	noload;
+
+int	supmedia = 0;
+int	printkeys = 0;		/* Print keying material for interfaces. */
+
+static	int ifconfig(int argc, char *const *argv, int iscreate,
+		const struct afswtch *afp);
+static	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+		struct ifaddrs *ifa);
+static	void tunnel_status(int s);
+static	void usage(void);
+
+static struct afswtch *af_getbyname(const char *name);
+static struct afswtch *af_getbyfamily(int af);
+static void af_other_status(int);
+
+static struct option *opts = NULL;
+
+void
+opt_register(struct option *p)
+{
+	p->next = opts;
+	opts = p;
+}
+
+static void
+usage(void)
+{
+	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 *argv[])
+{
+	int c, all, namesonly, downonly, uponly;
+	const struct afswtch *afp = NULL;
+	int ifindex;
+	struct ifaddrs *ifap, *ifa;
+	struct ifreq paifr;
+	const struct sockaddr_dl *sdl;
+	char options[1024], *cp;
+	const char *ifname;
+	struct option *p;
+	size_t iflen;
+
+	all = downonly = uponly = namesonly = noload = verbose = 0;
+
+	/* Parse leading line options */
+	strlcpy(options, "adklmnuv", 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++;
+			break;
+		case 'd':	/* restrict scan to "down" interfaces */
+			downonly++;
+			break;
+		case 'k':
+			printkeys++;
+			break;
+		case 'l':	/* scan interface names only */
+			namesonly++;
+			break;
+		case 'm':	/* show media choices in status */
+			supmedia = 1;
+			break;
+		case 'n':	/* suppress module loading */
+			noload++;
+			break;
+		case 'u':	/* restrict scan to "up" interfaces */
+			uponly++;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		default:
+			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;
+
+	/* -l cannot be used with -a or -m */
+	if (namesonly && (all || supmedia))
+		usage();
+
+	/* nonsense.. */
+	if (uponly && downonly)
+		usage();
+
+	/* no arguments is equivalent to '-a' */
+	if (!namesonly && argc < 1)
+		all = 1;
+
+	/* -a and -l allow an address family arg to limit the output */
+	if (all || namesonly) {
+		if (argc > 1)
+			usage();
+
+		ifname = NULL;
+		ifindex = 0;
+		if (argc == 1) {
+			afp = af_getbyname(*argv);
+			if (afp == NULL)
+				usage();
+			if (afp->af_name != NULL)
+				argc--, argv++;
+			/* leave with afp non-zero */
+		}
+	} else {
+		/* not listing, need an argument */
+		if (argc < 1)
+			usage();
+
+		ifname = *argv;
+		argc--, argv++;
+
+		/* check and maybe load support for this interface */
+		ifmaybeload(ifname);
+
+		ifindex = if_nametoindex(ifname);
+		if (ifindex == 0) {
+			/*
+			 * NOTE:  We must special-case the `create' command
+			 * right here as we would otherwise fail when trying
+			 * to find the interface.
+			 */
+			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
+			    strcmp(argv[0], "plumb") == 0)) {
+				iflen = strlcpy(name, ifname, sizeof(name));
+				if (iflen >= sizeof(name))
+					errx(1, "%s: cloning name too long",
+					    ifname);
+				ifconfig(argc, argv, 1, NULL);
+				exit(0);
+			}
+			/*
+			 * NOTE:  We have to special-case the `-vnet' command
+			 * right here as we would otherwise fail when trying
+			 * to find the interface as it lives in another vnet.
+			 */
+			if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) {
+				iflen = strlcpy(name, ifname, sizeof(name));
+				if (iflen >= sizeof(name))
+					errx(1, "%s: interface name too long",
+					    ifname);
+				ifconfig(argc, argv, 0, NULL);
+				exit(0);
+			}
+			errx(1, "interface %s does not exist", ifname);
+		}
+	}
+
+	/* Check for address family */
+	if (argc > 0) {
+		afp = af_getbyname(*argv);
+		if (afp != NULL)
+			argc--, argv++;
+	}
+
+	if (getifaddrs(&ifap) != 0)
+		err(EXIT_FAILURE, "getifaddrs");
+	cp = NULL;
+	ifindex = 0;
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		memset(&paifr, 0, sizeof(paifr));
+		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
+		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
+			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
+			    ifa->ifa_addr->sa_len);
+		}
+
+		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
+			continue;
+		if (ifa->ifa_addr->sa_family == AF_LINK)
+			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
+		else
+			sdl = NULL;
+		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
+			continue;
+		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
+		if (iflen >= sizeof(name)) {
+			warnx("%s: interface name too long, skipping",
+			    ifa->ifa_name);
+			continue;
+		}
+		cp = ifa->ifa_name;
+
+		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
+			continue;
+		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
+			continue;
+		ifindex++;
+		/*
+		 * Are we just listing the interfaces?
+		 */
+		if (namesonly) {
+			if (ifindex > 1)
+				printf(" ");
+			fputs(name, stdout);
+			continue;
+		}
+
+		if (argc > 0)
+			ifconfig(argc, argv, 0, afp);
+		else
+			status(afp, sdl, ifa);
+	}
+	if (namesonly)
+		printf("\n");
+	freeifaddrs(ifap);
+
+	exit(0);
+}
+
+static struct afswtch *afs = NULL;
+
+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, int iscreate)
+{
+#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) {
+			if (iscreate) {
+				if (p->c_iscloneop)
+					return p;
+			} else {
+				if (!p->c_iscloneop)
+					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, int iscreate, const struct afswtch *uafp)
+{
+	const struct afswtch *afp, *nafp;
+	const struct cmd *p;
+	struct callback *cb;
+	int s;
+
+	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+	afp = uafp != NULL ? uafp : af_getbyname("inet");
+top:
+	ifr.ifr_addr.sa_family =
+		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
+		AF_LOCAL : afp->af_af;
+
+	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
+	    (uafp != NULL || errno != EPROTONOSUPPORT ||
+	     (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
+		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
+
+	while (argc > 0) {
+		p = cmd_lookup(*argv, iscreate);
+		if (iscreate && p == NULL) {
+			/*
+			 * Push the clone create callback so the new
+			 * device is created and can be used for any
+			 * remaining arguments.
+			 */
+			cb = callbacks;
+			if (cb == NULL)
+				errx(1, "internal error, no callback");
+			callbacks = cb->cb_next;
+			cb->cb_func(s, cb->cb_arg);
+			iscreate = 0;
+			/*
+			 * Handle any address family spec that
+			 * immediately follows and potentially
+			 * recreate the socket.
+			 */
+			nafp = af_getbyname(*argv);
+			if (nafp != NULL) {
+				argc--, argv++;
+				if (nafp != afp) {
+					close(s);
+					afp = nafp;
+					goto top;
+				}
+			}
+			/*
+			 * Look for a normal parameter.
+			 */
+			continue;
+		}
+		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_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_u.c_func2(argv[1], argv[2], s, afp);
+				argc -= 2, argv += 2;
+			} else
+				p->c_u.c_func(*argv, p->c_parameter, s, afp);
+		}
+		argc--, argv++;
+	}
+
+	/*
+	 * Do any post argument processing required by the address family.
+	 */
+	if (afp->af_postproc != NULL)
+		afp->af_postproc(s, afp);
+	/*
+	 * 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);
+	/*
+	 * 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 = 0;
+		}
+	}
+	if (clearaddr) {
+		int ret;
+		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
+		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
+		if (ret < 0) {
+			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
+				/* means no previous address for interface */
+			} else
+				Perror("ioctl (SIOCDIFADDR)");
+		}
+	}
+	if (newaddr) {
+		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
+			warnx("interface %s cannot change %s addresses!",
+			      name, afp->af_name);
+			newaddr = 0;
+		}
+	}
+	if (newaddr && (setaddr || setmask)) {
+		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
+			Perror("ioctl (SIOCAIFADDR)");
+	}
+
+	close(s);
+	return(0);
+}
+
+/*ARGSUSED*/
+static void
+setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
+{
+	if (afp->af_getaddr == NULL)
+		return;
+	/*
+	 * Delay the ioctl to set the interface addr until flags are all set.
+	 * The address interpretation may depend on the flags,
+	 * and the flags may change when the address is set.
+	 */
+	setaddr++;
+	if (doalias == 0 && afp->af_af != AF_LINK)
+		clearaddr = 1;
+	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
+}
+
+static void
+settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
+{
+	struct addrinfo *srcres, *dstres;
+	int ecode;
+
+	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",
+		    gai_strerror(ecode));
+
+	if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)  
+		errx(1, "error in parsing address string: %s",
+		    gai_strerror(ecode));
+
+	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
+		errx(1,
+		    "source and destination address families do not match");
+
+	afp->af_settunnel(s, srcres, dstres);
+
+	freeaddrinfo(srcres);
+	freeaddrinfo(dstres);
+}
+
+/* ARGSUSED */
+static void
+deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
+{
+
+	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
+		err(1, "SIOCDIFPHYADDR");
+}
+
+static void
+setifvnet(const char *jname, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+	struct ifreq my_ifr;
+
+	memcpy(&my_ifr, &ifr, sizeof(my_ifr));
+	my_ifr.ifr_jid = jail_getid(jname);
+#ifndef __rtems__
+	if (my_ifr.ifr_jid < 0)
+		errx(1, "%s", jail_errmsg);
+#endif
+	if (ioctl(s, SIOCSIFVNET, &my_ifr) < 0)
+		err(1, "SIOCSIFVNET");
+}
+
+static void
+setifrvnet(const char *jname, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+	struct ifreq my_ifr;
+
+	memcpy(&my_ifr, &ifr, sizeof(my_ifr));
+	my_ifr.ifr_jid = jail_getid(jname);
+#ifndef __rtems__
+	if (my_ifr.ifr_jid < 0)
+		errx(1, "%s", jail_errmsg);
+#endif
+	if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0)
+		err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name);
+}
+
+static void
+setifnetmask(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+	if (afp->af_getaddr != NULL) {
+		setmask++;
+		afp->af_getaddr(addr, MASK);
+	}
+}
+
+static void
+setifbroadaddr(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+	if (afp->af_getaddr != NULL)
+		afp->af_getaddr(addr, DSTADDR);
+}
+
+static void
+setifipdst(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+	const struct afswtch *inet;
+
+	inet = af_getbyname("inet");
+	if (inet == NULL)
+		return;
+	inet->af_getaddr(addr, DSTADDR);
+	clearaddr = 0;
+	newaddr = 0;
+}
+
+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),
+			      (caddr_t)rqtosa(af_ridreq),
+			      rqtosa(af_addreq)->sa_len);
+	doalias = param;
+	if (param < 0) {
+		clearaddr = 1;
+		newaddr = 0;
+	} else
+		clearaddr = 0;
+#undef rqtosa
+}
+
+/*ARGSUSED*/
+static void
+setifdstaddr(const char *addr, int param __unused, int s, 
+    const struct afswtch *afp)
+{
+	if (afp->af_getaddr != NULL)
+		afp->af_getaddr(addr, DSTADDR);
+}
+
+/*
+ * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
+ * of the ifreq structure, which may confuse other parts of ifconfig.
+ * Make a private copy so we can avoid that.
+ */
+static void
+setifflags(const char *vname, int value, int s, const struct afswtch *afp)
+{
+	struct ifreq		my_ifr;
+	int flags;
+
+	memset(&my_ifr, 0, sizeof(my_ifr));
+	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
+
+ 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
+ 		Perror("ioctl (SIOCGIFFLAGS)");
+ 		exit(1);
+ 	}
+	flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16);
+
+	if (value < 0) {
+		value = -value;
+		flags &= ~value;
+	} else
+		flags |= value;
+	my_ifr.ifr_flags = flags & 0xffff;
+	my_ifr.ifr_flagshigh = flags >> 16;
+	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
+		Perror(vname);
+}
+
+void
+setifcap(const char *vname, int value, int s, const struct afswtch *afp)
+{
+	int flags;
+
+ 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
+ 		Perror("ioctl (SIOCGIFCAP)");
+ 		exit(1);
+ 	}
+	flags = ifr.ifr_curcap;
+	if (value < 0) {
+		value = -value;
+		flags &= ~value;
+	} else
+		flags |= value;
+	flags &= ifr.ifr_reqcap;
+	ifr.ifr_reqcap = flags;
+	if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
+		Perror(vname);
+}
+
+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);
+	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
+		warn("ioctl (set metric)");
+}
+
+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);
+	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
+		warn("ioctl (set mtu)");
+}
+
+static void
+setifname(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	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)");
+		free(newname);
+		return;
+	}
+	strlcpy(name, newname, sizeof(name));
+	free(newname);
+}
+
+/* ARGSUSED */
+static void
+setifdescr(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	char *newdescr;
+
+	ifr.ifr_buffer.length = strlen(val) + 1;
+	if (ifr.ifr_buffer.length == 1) {
+		ifr.ifr_buffer.buffer = newdescr = NULL;
+		ifr.ifr_buffer.length = 0;
+	} else {
+		newdescr = strdup(val);
+		ifr.ifr_buffer.buffer = newdescr;
+		if (newdescr == NULL) {
+			warn("no memory to set ifdescr");
+			return;
+		}
+	}
+
+	if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0)
+		warn("ioctl (set descr)");
+
+	free(newdescr);
+}
+
+/* ARGSUSED */
+static void
+unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
+{
+
+	setifdescr("", 0, s, 0);
+}
+
+#define	IFFBITS \
+"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
+"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
+"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
+
+#define	IFCAPBITS \
+"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
+"\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
+"\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE"
+
+/*
+ * Print the status of the interface.  If an address family was
+ * specified, show only it; otherwise, show them all.
+ */
+static void
+status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+	struct ifaddrs *ifa)
+{
+	struct ifaddrs *ift;
+	int allfamilies, s;
+	struct ifstat ifs;
+
+	if (afp == NULL) {
+		allfamilies = 1;
+		ifr.ifr_addr.sa_family = AF_LOCAL;
+	} else {
+		allfamilies = 0;
+		ifr.ifr_addr.sa_family =
+		    afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
+	}
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+	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", ifa->ifa_flags, IFFBITS);
+	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
+		printf(" metric %d", ifr.ifr_metric);
+	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
+		printf(" mtu %d", ifr.ifr_mtu);
+	putchar('\n');
+
+	for (;;) {
+		if ((descr = reallocf(descr, descrlen)) != NULL) {
+			ifr.ifr_buffer.buffer = descr;
+			ifr.ifr_buffer.length = descrlen;
+			if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) {
+				if (ifr.ifr_buffer.buffer == descr) {
+					if (strlen(descr) > 0)
+						printf("\tdescription: %s\n",
+						    descr);
+				} else if (ifr.ifr_buffer.length > descrlen) {
+					descrlen = ifr.ifr_buffer.length;
+					continue;
+				}
+			}
+		} else
+			warn("unable to allocate memory for interface"
+			    "description");
+		break;
+	}
+
+	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
+		if (ifr.ifr_curcap != 0) {
+			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
+			putchar('\n');
+		}
+		if (supmedia && ifr.ifr_reqcap != 0) {
+			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
+			putchar('\n');
+		}
+	}
+
+	tunnel_status(s);
+
+	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
+		if (ift->ifa_addr == NULL)
+			continue;
+		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
+			continue;
+		if (allfamilies) {
+			const struct afswtch *p;
+			p = af_getbyfamily(ift->ifa_addr->sa_family);
+			if (p != NULL && p->af_status != NULL)
+				p->af_status(s, ift);
+		} else if (afp->af_af == ift->ifa_addr->sa_family)
+			afp->af_status(s, ift);
+	}
+#if 0
+	if (allfamilies || afp->af_af == AF_LINK) {
+		const struct afswtch *lafp;
+
+		/*
+		 * 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.
+		 */
+		lafp = af_getbyname("lladdr");
+		if (lafp != NULL) {
+			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
+			lafp->af_status(s, &info);
+		}
+	}
+#endif
+	if (allfamilies)
+		af_other_status(s);
+	else if (afp->af_other_status != NULL)
+		afp->af_other_status(s);
+
+	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
+		printf("%s", ifs.ascii);
+
+	close(s);
+	return;
+}
+
+static void
+tunnel_status(int s)
+{
+	af_all_tunnel_status(s);
+}
+
+void
+Perror(const char *cmd)
+{
+	switch (errno) {
+
+	case ENXIO:
+		errx(1, "%s: no such interface", cmd);
+		break;
+
+	case EPERM:
+		errx(1, "%s: permission denied", cmd);
+		break;
+
+	default:
+		err(1, "%s", cmd);
+	}
+}
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+void
+printb(const char *s, unsigned v, const char *bits)
+{
+	int i, any = 0;
+	char c;
+
+	if (bits && *bits == 8)
+		printf("%s=%o", s, v);
+	else
+		printf("%s=%x", s, v);
+	bits++;
+	if (bits) {
+		putchar('<');
+		while ((i = *bits++) != '\0') {
+			if (v & (1 << (i-1))) {
+				if (any)
+					putchar(',');
+				any = 1;
+				for (; (c = *bits) > 32; bits++)
+					putchar(c);
+			} else
+				for (; *bits > 32; bits++)
+					;
+		}
+		putchar('>');
+	}
+}
+
+void
+ifmaybeload(const char *name)
+{
+#define MOD_PREFIX_LEN		3	/* "if_" */
+	struct module_stat mstat;
+	int fileid, modid;
+	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
+	const char *cp;
+
+	/* loading suppressed by the user */
+	if (noload)
+		return;
+
+	/* trim the interface number off the end */
+	strlcpy(ifname, name, sizeof(ifname));
+	for (dp = ifname; *dp != 0; dp++)
+		if (isdigit(*dp)) {
+			*dp = 0;
+			break;
+		}
+
+	/* turn interface and unit into module name */
+	strcpy(ifkind, "if_");
+	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
+	    sizeof(ifkind) - MOD_PREFIX_LEN);
+
+	/* scan files in kernel */
+	mstat.version = sizeof(struct module_stat);
+	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+		/* scan modules in file */
+		for (modid = kldfirstmod(fileid); modid > 0;
+		     modid = modfnext(modid)) {
+			if (modstat(modid, &mstat) < 0)
+				continue;
+			/* strip bus name if present */
+			if ((cp = strchr(mstat.name, '/')) != NULL) {
+				cp++;
+			} else {
+				cp = mstat.name;
+			}
+			/* already loaded? */
+			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
+			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
+				return;
+		}
+	}
+
+	/* not present, we should try to load it */
+	kldload(ifkind);
+}
+
+static struct cmd basic_cmds[] = {
+	DEF_CMD("up",		IFF_UP,		setifflags),
+	DEF_CMD("down",		-IFF_UP,	setifflags),
+	DEF_CMD("arp",		-IFF_NOARP,	setifflags),
+	DEF_CMD("-arp",		IFF_NOARP,	setifflags),
+	DEF_CMD("debug",	IFF_DEBUG,	setifflags),
+	DEF_CMD("-debug",	-IFF_DEBUG,	setifflags),
+	DEF_CMD_ARG("description",		setifdescr),
+	DEF_CMD_ARG("descr",			setifdescr),
+	DEF_CMD("-description",	0,		unsetifdescr),
+	DEF_CMD("-descr",	0,		unsetifdescr),
+	DEF_CMD("promisc",	IFF_PPROMISC,	setifflags),
+	DEF_CMD("-promisc",	-IFF_PPROMISC,	setifflags),
+	DEF_CMD("add",		IFF_UP,		notealias),
+	DEF_CMD("alias",	IFF_UP,		notealias),
+	DEF_CMD("-alias",	-IFF_UP,	notealias),
+	DEF_CMD("delete",	-IFF_UP,	notealias),
+	DEF_CMD("remove",	-IFF_UP,	notealias),
+#ifdef notdef
+#define	EN_SWABIPS	0x1000
+	DEF_CMD("swabips",	EN_SWABIPS,	setifflags),
+	DEF_CMD("-swabips",	-EN_SWABIPS,	setifflags),
+#endif
+	DEF_CMD_ARG("netmask",			setifnetmask),
+	DEF_CMD_ARG("metric",			setifmetric),
+	DEF_CMD_ARG("broadcast",		setifbroadaddr),
+	DEF_CMD_ARG("ipdst",			setifipdst),
+	DEF_CMD_ARG2("tunnel",			settunnel),
+	DEF_CMD("-tunnel", 0,			deletetunnel),
+	DEF_CMD("deletetunnel", 0,		deletetunnel),
+	DEF_CMD_ARG("vnet",			setifvnet),
+	DEF_CMD_ARG("-vnet",			setifrvnet),
+	DEF_CMD("link0",	IFF_LINK0,	setifflags),
+	DEF_CMD("-link0",	-IFF_LINK0,	setifflags),
+	DEF_CMD("link1",	IFF_LINK1,	setifflags),
+	DEF_CMD("-link1",	-IFF_LINK1,	setifflags),
+	DEF_CMD("link2",	IFF_LINK2,	setifflags),
+	DEF_CMD("-link2",	-IFF_LINK2,	setifflags),
+	DEF_CMD("monitor",	IFF_MONITOR,	setifflags),
+	DEF_CMD("-monitor",	-IFF_MONITOR,	setifflags),
+	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
+	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
+	DEF_CMD("rxcsum",	IFCAP_RXCSUM,	setifcap),
+	DEF_CMD("-rxcsum",	-IFCAP_RXCSUM,	setifcap),
+	DEF_CMD("txcsum",	IFCAP_TXCSUM,	setifcap),
+	DEF_CMD("-txcsum",	-IFCAP_TXCSUM,	setifcap),
+	DEF_CMD("netcons",	IFCAP_NETCONS,	setifcap),
+	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
+	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
+	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
+	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
+	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
+	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
+	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
+	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
+	DEF_CMD("-wol",		-IFCAP_WOL,	setifcap),
+	DEF_CMD("wol_ucast",	IFCAP_WOL_UCAST,	setifcap),
+	DEF_CMD("-wol_ucast",	-IFCAP_WOL_UCAST,	setifcap),
+	DEF_CMD("wol_mcast",	IFCAP_WOL_MCAST,	setifcap),
+	DEF_CMD("-wol_mcast",	-IFCAP_WOL_MCAST,	setifcap),
+	DEF_CMD("wol_magic",	IFCAP_WOL_MAGIC,	setifcap),
+	DEF_CMD("-wol_magic",	-IFCAP_WOL_MAGIC,	setifcap),
+	DEF_CMD("normal",	-IFF_LINK0,	setifflags),
+	DEF_CMD("compress",	IFF_LINK0,	setifflags),
+	DEF_CMD("noicmp",	IFF_LINK1,	setifflags),
+	DEF_CMD_ARG("mtu",			setifmtu),
+	DEF_CMD_ARG("name",			setifname),
+};
+
+static __constructor void
+ifconfig_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(basic_cmds);  i++)
+		cmd_register(&basic_cmds[i]);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifconfig.h b/freebsd-userspace/commands/sbin/ifconfig/ifconfig.h
new file mode 100644
index 0000000..a624f60
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifconfig.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1997 Peter Wemm.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the FreeBSD Project
+ *	by Peter Wemm.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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 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.
+ *
+ * so there!
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __rtems__
+#include <freebsd/sys/sockio.h>
+#endif
+
+#define	__constructor	__attribute__((constructor))
+
+struct afswtch;
+struct cmd;
+
+typedef	void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
+typedef	void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp);
+
+struct cmd {
+	const char *c_name;
+	int	c_parameter;
+#define	NEXTARG		0xffffff	/* has following arg */
+#define	NEXTARG2	0xfffffe	/* has 2 following args */
+#define	OPTARG		0xfffffd	/* has optional following arg */
+	union {
+		c_func	*c_func;
+		c_func2	*c_func2;
+	} c_u;
+	int	c_iscloneop;
+	struct cmd *c_next;
+};
+void	cmd_register(struct cmd *);
+
+typedef	void callback_func(int s, void *);
+void	callback_register(callback_func *, void *);
+
+/*
+ * Macros for declaring command functions and initializing entries.
+ */
+#define	DECL_CMD_FUNC(name, cmd, arg) \
+	void name(const char *cmd, int arg, int s, const struct afswtch *afp)
+#define	DECL_CMD_FUNC2(name, arg1, arg2) \
+	void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp)
+
+#define	DEF_CMD(name, param, func)	{ name, param, { .c_func = func }, 0, NULL }
+#define	DEF_CMD_ARG(name, func)		{ name, NEXTARG, { .c_func = func }, 0, NULL }
+#define	DEF_CMD_OPTARG(name, func)	{ name, OPTARG, { .c_func = func }, 0, NULL }
+#define	DEF_CMD_ARG2(name, func)	{ name, NEXTARG2, { .c_func2 = func }, 0, NULL }
+#define	DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1, NULL }
+#define	DEF_CLONE_CMD_ARG(name, func)	{ name, NEXTARG, { .c_func = func }, 1, NULL }
+
+struct ifaddrs;
+struct addrinfo;
+
+enum {
+	RIDADDR,
+	ADDR,
+	MASK,
+	DSTADDR,
+};
+
+struct afswtch {
+	const char	*af_name;	/* as given on cmd line, e.g. "inet" */
+	short		af_af;		/* AF_* */
+	/*
+	 * Status is handled one of two ways; if there is an
+	 * address associated with the interface then the
+	 * associated address family af_status method is invoked
+	 * with the appropriate addressin info.  Otherwise, if
+	 * all possible info is to be displayed and af_other_status
+	 * is defined then it is invoked after all address status
+	 * is presented.
+	 */
+	void		(*af_status)(int, const struct ifaddrs *);
+	void		(*af_other_status)(int);
+					/* parse address method */
+	void		(*af_getaddr)(const char *, int);
+					/* parse prefix method (IPv6) */
+	void		(*af_getprefix)(const char *, int);
+	void		(*af_postproc)(int s, const struct afswtch *);
+	u_long		af_difaddr;	/* set dst if address ioctl */
+	u_long		af_aifaddr;	/* set if address ioctl */
+	void		*af_ridreq;	/* */
+	void		*af_addreq;	/* */
+	struct afswtch	*af_next;
+
+	/* XXX doesn't fit model */
+	void		(*af_status_tunnel)(int);
+	void		(*af_settunnel)(int s, struct addrinfo *srcres,
+				struct addrinfo *dstres);
+};
+void	af_register(struct afswtch *);
+
+struct option {
+	const char *opt;
+	const char *opt_usage;
+	void	(*cb)(const char *arg);
+	struct option *next;
+};
+void	opt_register(struct option *);
+
+extern	struct ifreq ifr;
+extern	char name[IFNAMSIZ];	/* name of interface */
+extern	int allmedia;
+extern	int supmedia;
+extern	int printkeys;
+extern	int newaddr;
+extern	int verbose;
+
+void	setifcap(const char *, int value, int s, const struct afswtch *);
+
+void	Perror(const char *cmd);
+void	printb(const char *s, unsigned value, const char *bits);
+
+void	ifmaybeload(const char *name);
+
+typedef void clone_callback_func(int, struct ifreq *);
+void	clone_setdefcallback(const char *, clone_callback_func *);
+
+/*
+ * XXX expose this so modules that neeed to know of any pending
+ * operations on ifmedia can avoid cmd line ordering confusion.
+ */
+struct ifmediareq *ifmedia_getstate(int s);
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifgif.c b/freebsd-userspace/commands/sbin/ifconfig/ifgif.c
new file mode 100644
index 0000000..d23b384
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifgif.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 2009 Hiroki Sato.  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.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif
+
+#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>
+#ifdef __rtems__
+#include <freebsd/net/if_gif.h>
+#else
+#include <net/if_gif.h>
+#endif
+#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 void	gif_status(int);
+
+static struct {
+	const char	*label;
+	u_int		mask;
+} gif_opts[] = {
+	{ "ACCEPT_REV_ETHIP_VER",	GIF_ACCEPT_REVETHIP	},
+	{ "SEND_REV_ETHIP_VER",		GIF_SEND_REVETHIP	},
+};
+
+static void
+gif_status(int s)
+{
+	int opts;
+	int nopts = 0;
+	size_t i;
+
+	ifr.ifr_data = (caddr_t)&opts;
+	if (ioctl(s, GIFGOPTS, &ifr) == -1)
+		return;
+	if (opts == 0)
+		return;
+
+	printf("\toptions=%d<", opts);
+	for (i=0; i < sizeof(gif_opts)/sizeof(gif_opts[0]); i++) {
+		if (opts & gif_opts[i].mask) {
+			if (nopts++)
+				printf(",");
+			printf("%s", gif_opts[i].label);
+		}
+	}
+	printf(">\n");
+}
+
+static void
+setgifopts(const char *val,
+	int d, int s, const struct afswtch *afp)
+{
+	int opts;
+
+	ifr.ifr_data = (caddr_t)&opts;
+	if (ioctl(s, GIFGOPTS, &ifr) == -1) {
+		warn("ioctl(GIFGOPTS)");
+		return;
+	}
+
+	if (d < 0)
+		opts &= ~(-d);
+	else
+		opts |= d;
+
+	if (ioctl(s, GIFSOPTS, &ifr) == -1) {
+		warn("ioctl(GIFSOPTS)");
+		return;
+	}
+}
+
+static struct cmd gif_cmds[] = {
+	DEF_CMD("accept_rev_ethip_ver",	GIF_ACCEPT_REVETHIP,	setgifopts),
+	DEF_CMD("-accept_rev_ethip_ver",-GIF_ACCEPT_REVETHIP,	setgifopts),
+	DEF_CMD("send_rev_ethip_ver",	GIF_SEND_REVETHIP,	setgifopts),
+	DEF_CMD("-send_rev_ethip_ver",	-GIF_SEND_REVETHIP,	setgifopts),
+};
+
+static struct afswtch af_gif = {
+	.af_name	= "af_gif",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = gif_status,
+};
+
+static __constructor void
+gif_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(gif_cmds); i++)
+		cmd_register(&gif_cmds[i]);
+	af_register(&af_gif);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifgre.c b/freebsd-userspace/commands/sbin/ifconfig/ifgre.c
new file mode 100644
index 0000000..58d5bcf
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifgre.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2008 Andrew Thompson. 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.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif
+
+#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>
+#ifdef __rtems__
+#include <freebsd/net/if_gre.h>
+#else
+#include <net/if_gre.h>
+#endif
+#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	void gre_status(int s);
+
+static void
+gre_status(int s)
+{
+	int grekey = 0;
+
+	ifr.ifr_data = (caddr_t)&grekey;
+	if (ioctl(s, GREGKEY, &ifr) == 0)
+		if (grekey != 0)
+			printf("\tgrekey: %d\n", grekey);
+}
+
+static void
+setifgrekey(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+	uint32_t grekey = atol(val);
+
+	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+	ifr.ifr_data = (caddr_t)&grekey;
+	if (ioctl(s, GRESKEY, (caddr_t)&ifr) < 0)
+		warn("ioctl (set grekey)");
+}
+
+static struct cmd gre_cmds[] = {
+	DEF_CMD_ARG("grekey",			setifgrekey),
+};
+static struct afswtch af_gre = {
+	.af_name	= "af_gre",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = gre_status,
+};
+
+static __constructor void
+gre_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(gre_cmds);  i++)
+		cmd_register(&gre_cmds[i]);
+	af_register(&af_gre);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifgroup.c b/freebsd-userspace/commands/sbin/ifconfig/ifgroup.c
new file mode 100644
index 0000000..9eaac3b
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifgroup.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 2006 Max Laier. 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 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 AUTHOR 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 <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+/* ARGSUSED */
+static void
+setifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
+{
+	struct ifgroupreq ifgr;
+
+	memset(&ifgr, 0, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
+
+	if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
+		errx(1, "setifgroup: group names may not end in a digit");
+
+	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
+		errx(1, "setifgroup: group name too long");
+	if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1)
+		err(1," SIOCAIFGROUP");
+}
+
+/* ARGSUSED */
+static void
+unsetifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
+{
+	struct ifgroupreq ifgr;
+
+	memset(&ifgr, 0, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
+
+	if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
+		errx(1, "unsetifgroup: group names may not end in a digit");
+
+	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
+		errx(1, "unsetifgroup: group name too long");
+	if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
+		err(1, "SIOCDIFGROUP");
+}
+
+static void
+getifgroups(int s)
+{
+	int			 len, cnt;
+	struct ifgroupreq	 ifgr;
+	struct ifg_req		*ifg;
+
+	if (!verbose)
+		return;
+
+	memset(&ifgr, 0, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
+
+	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
+		if (errno == EINVAL || errno == ENOTTY)
+			return;
+		else
+			err(1, "SIOCGIFGROUP");
+	}
+
+	len = ifgr.ifgr_len;
+	ifgr.ifgr_groups =
+	    (struct ifg_req *)calloc(len / sizeof(struct ifg_req),
+	    sizeof(struct ifg_req));
+	if (ifgr.ifgr_groups == NULL)
+		err(1, "getifgroups");
+	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
+		err(1, "SIOCGIFGROUP");
+
+	cnt = 0;
+	ifg = ifgr.ifgr_groups;
+	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
+		len -= sizeof(struct ifg_req);
+		if (strcmp(ifg->ifgrq_group, "all")) {
+			if (cnt == 0)
+				printf("\tgroups: ");
+			cnt++;
+			printf("%s ", ifg->ifgrq_group);
+		}
+	}
+	if (cnt)
+		printf("\n");
+}
+
+static void
+printgroup(const char *groupname)
+{
+	struct ifgroupreq	 ifgr;
+	struct ifg_req		*ifg;
+	int			 len, cnt = 0;
+	int			 s;
+
+	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (s == -1)
+		err(1, "socket(AF_LOCAL,SOCK_DGRAM)");
+	bzero(&ifgr, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
+	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
+		if (errno == EINVAL || errno == ENOTTY ||
+		    errno == ENOENT)
+			exit(0);
+		else
+			err(1, "SIOCGIFGMEMB");
+	}
+
+	len = ifgr.ifgr_len;
+	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
+		err(1, "printgroup");
+	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
+		err(1, "SIOCGIFGMEMB");
+
+	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
+	    ifg++) {
+		len -= sizeof(struct ifg_req);
+		printf("%s\n", ifg->ifgrq_member);
+		cnt++;
+	}
+	free(ifgr.ifgr_groups);
+
+	exit(0);
+}
+
+static struct cmd group_cmds[] = {
+	DEF_CMD_ARG("group",	setifgroup),
+	DEF_CMD_ARG("-group",	unsetifgroup),
+};
+static struct afswtch af_group = {
+	.af_name	= "af_group",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = getifgroups,
+};
+static struct option group_gopt = { "g:", "[-g groupname]", printgroup };
+
+static __constructor void
+group_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(group_cmds);  i++)
+		cmd_register(&group_cmds[i]);
+	af_register(&af_group);
+	opt_register(&group_gopt);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifieee80211.c b/freebsd-userspace/commands/sbin/ifconfig/ifieee80211.c
new file mode 100644
index 0000000..57713ca
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifieee80211.c
@@ -0,0 +1,5295 @@
+/*
+ * Copyright 2001 The Aerospace Corporation.  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.
+ * 3. The name of The Aerospace Corporation may not be used to endorse or
+ *    promote products derived from this software.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``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 AEROSPACE CORPORATION 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.
+ *
+ * $FreeBSD$
+ */
+
+/*-
+ * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#ifdef __rtems__
+#include <freebsd/net/if_media.h>
+#else
+#include <net/if_media.h>
+#endif
+#include <net/route.h>
+
+#ifdef __rtems__
+#include <freebsd/net80211/ieee80211_ioctl.h>
+#include <freebsd/net80211/ieee80211_freebsd.h>
+#include <freebsd/net80211/ieee80211_superg.h>
+#include <freebsd/net80211/ieee80211_tdma.h>
+#include <freebsd/net80211/ieee80211_mesh.h>
+#else
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_freebsd.h>
+#include <net80211/ieee80211_superg.h>
+#include <net80211/ieee80211_tdma.h>
+#include <net80211/ieee80211_mesh.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>		/* NB: for offsetof */
+
+#include "ifconfig.h"
+#include "regdomain.h"
+
+#ifndef IEEE80211_FIXED_RATE_NONE
+#define	IEEE80211_FIXED_RATE_NONE	0xff
+#endif
+
+/* XXX need these publicly defined or similar */
+#ifndef IEEE80211_NODE_AUTH
+#define	IEEE80211_NODE_AUTH	0x000001	/* authorized for data */
+#define	IEEE80211_NODE_QOS	0x000002	/* QoS enabled */
+#define	IEEE80211_NODE_ERP	0x000004	/* ERP enabled */
+#define	IEEE80211_NODE_PWR_MGT	0x000010	/* power save mode enabled */
+#define	IEEE80211_NODE_AREF	0x000020	/* authentication ref held */
+#define	IEEE80211_NODE_HT	0x000040	/* HT enabled */
+#define	IEEE80211_NODE_HTCOMPAT	0x000080	/* HT setup w/ vendor OUI's */
+#define	IEEE80211_NODE_WPS	0x000100	/* WPS association */
+#define	IEEE80211_NODE_TSN	0x000200	/* TSN association */
+#define	IEEE80211_NODE_AMPDU_RX	0x000400	/* AMPDU rx enabled */
+#define	IEEE80211_NODE_AMPDU_TX	0x000800	/* AMPDU tx enabled */
+#define	IEEE80211_NODE_MIMO_PS	0x001000	/* MIMO power save enabled */
+#define	IEEE80211_NODE_MIMO_RTS	0x002000	/* send RTS in MIMO PS */
+#define	IEEE80211_NODE_RIFS	0x004000	/* RIFS enabled */
+#define	IEEE80211_NODE_SGI20	0x008000	/* Short GI in HT20 enabled */
+#define	IEEE80211_NODE_SGI40	0x010000	/* Short GI in HT40 enabled */
+#define	IEEE80211_NODE_ASSOCID	0x020000	/* xmit requires associd */
+#define	IEEE80211_NODE_AMSDU_RX	0x040000	/* AMSDU rx enabled */
+#define	IEEE80211_NODE_AMSDU_TX	0x080000	/* AMSDU tx enabled */
+#endif
+
+#define	MAXCHAN	1536		/* max 1.5K channels */
+
+#define	MAXCOL	78
+static	int col;
+static	char spacer;
+
+static void LINE_INIT(char c);
+static void LINE_BREAK(void);
+static void LINE_CHECK(const char *fmt, ...);
+
+static const char *modename[IEEE80211_MODE_MAX] = {
+	[IEEE80211_MODE_AUTO]	  = "auto",
+	[IEEE80211_MODE_11A]	  = "11a",
+	[IEEE80211_MODE_11B]	  = "11b",
+	[IEEE80211_MODE_11G]	  = "11g",
+	[IEEE80211_MODE_FH]	  = "fh",
+	[IEEE80211_MODE_TURBO_A]  = "turboA",
+	[IEEE80211_MODE_TURBO_G]  = "turboG",
+	[IEEE80211_MODE_STURBO_A] = "sturbo",
+	[IEEE80211_MODE_11NA]	  = "11na",
+	[IEEE80211_MODE_11NG]	  = "11ng",
+	[IEEE80211_MODE_HALF]	  = "half",
+	[IEEE80211_MODE_QUARTER]  = "quarter"
+};
+
+static void set80211(int s, int type, int val, int len, void *data);
+static int get80211(int s, int type, void *data, int len);
+static int get80211len(int s, int type, void *data, int len, int *plen);
+static int get80211val(int s, int type, int *val);
+static const char *get_string(const char *val, const char *sep,
+    u_int8_t *buf, int *lenp);
+static void print_string(const u_int8_t *buf, int len);
+static void print_regdomain(const struct ieee80211_regdomain *, int);
+static void print_channels(int, const struct ieee80211req_chaninfo *,
+    int allchans, int verbose);
+static void regdomain_makechannels(struct ieee80211_regdomain_req *,
+    const struct ieee80211_devcaps_req *);
+static const char *mesh_linkstate_string(uint8_t state);
+
+static struct ieee80211req_chaninfo *chaninfo;
+static struct ieee80211_regdomain regdomain;
+static int gotregdomain = 0;
+static struct ieee80211_roamparams_req roamparams;
+static int gotroam = 0;
+static struct ieee80211_txparams_req txparams;
+static int gottxparams = 0;
+static struct ieee80211_channel curchan;
+static int gotcurchan = 0;
+static struct ifmediareq *ifmr;
+static int htconf = 0;
+static	int gothtconf = 0;
+
+static void
+gethtconf(int s)
+{
+	if (gothtconf)
+		return;
+	if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0)
+		warn("unable to get HT configuration information");
+	gothtconf = 1;
+}
+
+/*
+ * Collect channel info from the kernel.  We use this (mostly)
+ * to handle mapping between frequency and IEEE channel number.
+ */
+static void
+getchaninfo(int s)
+{
+	if (chaninfo != NULL)
+		return;
+	chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
+	if (chaninfo == NULL)
+		errx(1, "no space for channel list");
+	if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo,
+	    IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
+		err(1, "unable to get channel information");
+	ifmr = ifmedia_getstate(s);
+	gethtconf(s);
+}
+
+static struct regdata *
+getregdata(void)
+{
+	static struct regdata *rdp = NULL;
+	if (rdp == NULL) {
+		rdp = lib80211_alloc_regdata();
+		if (rdp == NULL)
+			errx(-1, "missing or corrupted regdomain database");
+	}
+	return rdp;
+}
+
+/*
+ * Given the channel at index i with attributes from,
+ * check if there is a channel with attributes to in
+ * the channel table.  With suitable attributes this
+ * allows the caller to look for promotion; e.g. from
+ * 11b > 11g.
+ */
+static int
+canpromote(int i, int from, int to)
+{
+	const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
+	int j;
+
+	if ((fc->ic_flags & from) != from)
+		return i;
+	/* NB: quick check exploiting ordering of chans w/ same frequency */
+	if (i+1 < chaninfo->ic_nchans &&
+	    chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
+	    (chaninfo->ic_chans[i+1].ic_flags & to) == to)
+		return i+1;
+	/* brute force search in case channel list is not ordered */
+	for (j = 0; j < chaninfo->ic_nchans; j++) {
+		const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
+		if (j != i &&
+		    tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
+		return j;
+	}
+	return i;
+}
+
+/*
+ * Handle channel promotion.  When a channel is specified with
+ * only a frequency we want to promote it to the ``best'' channel
+ * available.  The channel list has separate entries for 11b, 11g,
+ * 11a, and 11n[ga] channels so specifying a frequency w/o any
+ * attributes requires we upgrade, e.g. from 11b -> 11g.  This
+ * gets complicated when the channel is specified on the same
+ * command line with a media request that constrains the available
+ * channe list (e.g. mode 11a); we want to honor that to avoid
+ * confusing behaviour.
+ */
+static int
+promote(int i)
+{
+	/*
+	 * Query the current mode of the interface in case it's
+	 * constrained (e.g. to 11a).  We must do this carefully
+	 * as there may be a pending ifmedia request in which case
+	 * asking the kernel will give us the wrong answer.  This
+	 * is an unfortunate side-effect of the way ifconfig is
+	 * structure for modularity (yech).
+	 *
+	 * NB: ifmr is actually setup in getchaninfo (above); we
+	 *     assume it's called coincident with to this call so
+	 *     we have a ``current setting''; otherwise we must pass
+	 *     the socket descriptor down to here so we can make
+	 *     the ifmedia_getstate call ourselves.
+	 */
+	int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
+
+	/* when ambiguous promote to ``best'' */
+	/* NB: we abitrarily pick HT40+ over HT40- */
+	if (chanmode != IFM_IEEE80211_11B)
+		i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
+	if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
+		i = canpromote(i, IEEE80211_CHAN_G,
+			IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
+		if (htconf & 2) {
+			i = canpromote(i, IEEE80211_CHAN_G,
+				IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
+			i = canpromote(i, IEEE80211_CHAN_G,
+				IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
+		}
+	}
+	if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
+		i = canpromote(i, IEEE80211_CHAN_A,
+			IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+		if (htconf & 2) {
+			i = canpromote(i, IEEE80211_CHAN_A,
+				IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+			i = canpromote(i, IEEE80211_CHAN_A,
+				IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+		}
+	}
+	return i;
+}
+
+static void
+mapfreq(struct ieee80211_channel *chan, int freq, int flags)
+{
+	int i;
+
+	for (i = 0; i < chaninfo->ic_nchans; i++) {
+		const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
+
+		if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
+			if (flags == 0) {
+				/* when ambiguous promote to ``best'' */
+				c = &chaninfo->ic_chans[promote(i)];
+			}
+			*chan = *c;
+			return;
+		}
+	}
+	errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
+}
+
+static void
+mapchan(struct ieee80211_channel *chan, int ieee, int flags)
+{
+	int i;
+
+	for (i = 0; i < chaninfo->ic_nchans; i++) {
+		const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
+
+		if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
+			if (flags == 0) {
+				/* when ambiguous promote to ``best'' */
+				c = &chaninfo->ic_chans[promote(i)];
+			}
+			*chan = *c;
+			return;
+		}
+	}
+	errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
+}
+
+static const struct ieee80211_channel *
+getcurchan(int s)
+{
+	if (gotcurchan)
+		return &curchan;
+	if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
+		int val;
+		/* fall back to legacy ioctl */
+		if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
+			err(-1, "cannot figure out current channel");
+		getchaninfo(s);
+		mapchan(&curchan, val, 0);
+	}
+	gotcurchan = 1;
+	return &curchan;
+}
+
+static enum ieee80211_phymode
+chan2mode(const struct ieee80211_channel *c)
+{
+	if (IEEE80211_IS_CHAN_HTA(c))
+		return IEEE80211_MODE_11NA;
+	if (IEEE80211_IS_CHAN_HTG(c))
+		return IEEE80211_MODE_11NG;
+	if (IEEE80211_IS_CHAN_108A(c))
+		return IEEE80211_MODE_TURBO_A;
+	if (IEEE80211_IS_CHAN_108G(c))
+		return IEEE80211_MODE_TURBO_G;
+	if (IEEE80211_IS_CHAN_ST(c))
+		return IEEE80211_MODE_STURBO_A;
+	if (IEEE80211_IS_CHAN_FHSS(c))
+		return IEEE80211_MODE_FH;
+	if (IEEE80211_IS_CHAN_HALF(c))
+		return IEEE80211_MODE_HALF;
+	if (IEEE80211_IS_CHAN_QUARTER(c))
+		return IEEE80211_MODE_QUARTER;
+	if (IEEE80211_IS_CHAN_A(c))
+		return IEEE80211_MODE_11A;
+	if (IEEE80211_IS_CHAN_ANYG(c))
+		return IEEE80211_MODE_11G;
+	if (IEEE80211_IS_CHAN_B(c))
+		return IEEE80211_MODE_11B;
+	return IEEE80211_MODE_AUTO;
+}
+
+static void
+getroam(int s)
+{
+	if (gotroam)
+		return;
+	if (get80211(s, IEEE80211_IOC_ROAM,
+	    &roamparams, sizeof(roamparams)) < 0)
+		err(1, "unable to get roaming parameters");
+	gotroam = 1;
+}
+
+static void
+setroam_cb(int s, void *arg)
+{
+	struct ieee80211_roamparams_req *roam = arg;
+	set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam);
+}
+
+static void
+gettxparams(int s)
+{
+	if (gottxparams)
+		return;
+	if (get80211(s, IEEE80211_IOC_TXPARAMS,
+	    &txparams, sizeof(txparams)) < 0)
+		err(1, "unable to get transmit parameters");
+	gottxparams = 1;
+}
+
+static void
+settxparams_cb(int s, void *arg)
+{
+	struct ieee80211_txparams_req *txp = arg;
+	set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp);
+}
+
+static void
+getregdomain(int s)
+{
+	if (gotregdomain)
+		return;
+	if (get80211(s, IEEE80211_IOC_REGDOMAIN,
+	    &regdomain, sizeof(regdomain)) < 0)
+		err(1, "unable to get regulatory domain info");
+	gotregdomain = 1;
+}
+
+static void
+getdevcaps(int s, struct ieee80211_devcaps_req *dc)
+{
+	if (get80211(s, IEEE80211_IOC_DEVCAPS, dc,
+	    IEEE80211_DEVCAPS_SPACE(dc)) < 0)
+		err(1, "unable to get device capabilities");
+}
+
+static void
+setregdomain_cb(int s, void *arg)
+{
+	struct ieee80211_regdomain_req *req;
+	struct ieee80211_regdomain *rd = arg;
+	struct ieee80211_devcaps_req *dc;
+	struct regdata *rdp = getregdata();
+
+	if (rd->country != NO_COUNTRY) {
+		const struct country *cc;
+		/*
+		 * Check current country seting to make sure it's
+		 * compatible with the new regdomain.  If not, then
+		 * override it with any default country for this
+		 * SKU.  If we cannot arrange a match, then abort.
+		 */
+		cc = lib80211_country_findbycc(rdp, rd->country);
+		if (cc == NULL)
+			errx(1, "unknown ISO country code %d", rd->country);
+		if (cc->rd->sku != rd->regdomain) {
+			const struct regdomain *rp;
+			/*
+			 * Check if country is incompatible with regdomain.
+			 * To enable multiple regdomains for a country code
+			 * we permit a mismatch between the regdomain and
+			 * the country's associated regdomain when the
+			 * regdomain is setup w/o a default country.  For
+			 * example, US is bound to the FCC regdomain but
+			 * we allow US to be combined with FCC3 because FCC3
+			 * has not default country.  This allows bogus
+			 * combinations like FCC3+DK which are resolved when
+			 * constructing the channel list by deferring to the
+			 * regdomain to construct the channel list.
+			 */
+			rp = lib80211_regdomain_findbysku(rdp, rd->regdomain);
+			if (rp == NULL)
+				errx(1, "country %s (%s) is not usable with "
+				    "regdomain %d", cc->isoname, cc->name,
+				    rd->regdomain);
+			else if (rp->cc != NULL && rp->cc != cc)
+				errx(1, "country %s (%s) is not usable with "
+				   "regdomain %s", cc->isoname, cc->name,
+				   rp->name);
+		}
+	}
+	/*
+	 * Fetch the device capabilities and calculate the
+	 * full set of netbands for which we request a new
+	 * channel list be constructed.  Once that's done we
+	 * push the regdomain info + channel list to the kernel.
+	 */
+	dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
+	if (dc == NULL)
+		errx(1, "no space for device capabilities");
+	dc->dc_chaninfo.ic_nchans = MAXCHAN;
+	getdevcaps(s, dc);
+#if 0
+	if (verbose) {
+		printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
+		printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
+		printf("htcaps    : 0x%x\n", dc->dc_htcaps);
+		memcpy(chaninfo, &dc->dc_chaninfo,
+		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
+		print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
+	}
+#endif
+	req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
+	if (req == NULL)
+		errx(1, "no space for regdomain request");
+	req->rd = *rd;
+	regdomain_makechannels(req, dc);
+	if (verbose) {
+		LINE_INIT(':');
+		print_regdomain(rd, 1/*verbose*/);
+		LINE_BREAK();
+		/* blech, reallocate channel list for new data */
+		if (chaninfo != NULL)
+			free(chaninfo);
+		chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
+		if (chaninfo == NULL)
+			errx(1, "no space for channel list");
+		memcpy(chaninfo, &req->chaninfo,
+		    IEEE80211_CHANINFO_SPACE(&req->chaninfo));
+		print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/);
+	}
+	if (req->chaninfo.ic_nchans == 0)
+		errx(1, "no channels calculated");
+	set80211(s, IEEE80211_IOC_REGDOMAIN, 0,
+	    IEEE80211_REGDOMAIN_SPACE(req), req);
+	free(req);
+	free(dc);
+}
+
+static int
+ieee80211_mhz2ieee(int freq, int flags)
+{
+	struct ieee80211_channel chan;
+	mapfreq(&chan, freq, flags);
+	return chan.ic_ieee;
+}
+
+static int
+isanyarg(const char *arg)
+{
+	return (strncmp(arg, "-", 1) == 0 ||
+	    strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0);
+}
+
+static void
+set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		ssid;
+	int		len;
+	u_int8_t	data[IEEE80211_NWID_LEN];
+
+	ssid = 0;
+	len = strlen(val);
+	if (len > 2 && isdigit((int)val[0]) && val[1] == ':') {
+		ssid = atoi(val)-1;
+		val += 2;
+	}
+
+	bzero(data, sizeof(data));
+	len = sizeof(data);
+	if (get_string(val, NULL, data, &len) == NULL)
+		exit(1);
+
+	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
+}
+
+static void
+set80211meshid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		len;
+	u_int8_t	data[IEEE80211_NWID_LEN];
+
+	memset(data, 0, sizeof(data));
+	len = sizeof(data);
+	if (get_string(val, NULL, data, &len) == NULL)
+		exit(1);
+
+	set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data);
+}	
+
+static void
+set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int			len;
+	u_int8_t		data[33];
+
+	bzero(data, sizeof(data));
+	len = sizeof(data);
+	get_string(val, NULL, data, &len);
+
+	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
+}
+
+/*
+ * Parse a channel specification for attributes/flags.
+ * The syntax is:
+ *	freq/xx		channel width (5,10,20,40,40+,40-)
+ *	freq:mode	channel mode (a,b,g,h,n,t,s,d)
+ *
+ * These can be combined in either order; e.g. 2437:ng/40.
+ * Modes are case insensitive.
+ *
+ * The result is not validated here; it's assumed to be
+ * checked against the channel table fetched from the kernel.
+ */ 
+static int
+getchannelflags(const char *val, int freq)
+{
+#define	_CHAN_HT	0x80000000
+	const char *cp;
+	int flags;
+
+	flags = 0;
+
+	cp = strchr(val, ':');
+	if (cp != NULL) {
+		for (cp++; isalpha((int) *cp); cp++) {
+			/* accept mixed case */
+			int c = *cp;
+			if (isupper(c))
+				c = tolower(c);
+			switch (c) {
+			case 'a':		/* 802.11a */
+				flags |= IEEE80211_CHAN_A;
+				break;
+			case 'b':		/* 802.11b */
+				flags |= IEEE80211_CHAN_B;
+				break;
+			case 'g':		/* 802.11g */
+				flags |= IEEE80211_CHAN_G;
+				break;
+			case 'h':		/* ht = 802.11n */
+			case 'n':		/* 802.11n */
+				flags |= _CHAN_HT;	/* NB: private */
+				break;
+			case 'd':		/* dt = Atheros Dynamic Turbo */
+				flags |= IEEE80211_CHAN_TURBO;
+				break;
+			case 't':		/* ht, dt, st, t */
+				/* dt and unadorned t specify Dynamic Turbo */
+				if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
+					flags |= IEEE80211_CHAN_TURBO;
+				break;
+			case 's':		/* st = Atheros Static Turbo */
+				flags |= IEEE80211_CHAN_STURBO;
+				break;
+			default:
+				errx(-1, "%s: Invalid channel attribute %c\n",
+				    val, *cp);
+			}
+		}
+	}
+	cp = strchr(val, '/');
+	if (cp != NULL) {
+		char *ep;
+		u_long cw = strtoul(cp+1, &ep, 10);
+
+		switch (cw) {
+		case 5:
+			flags |= IEEE80211_CHAN_QUARTER;
+			break;
+		case 10:
+			flags |= IEEE80211_CHAN_HALF;
+			break;
+		case 20:
+			/* NB: this may be removed below */
+			flags |= IEEE80211_CHAN_HT20;
+			break;
+		case 40:
+			if (ep != NULL && *ep == '+')
+				flags |= IEEE80211_CHAN_HT40U;
+			else if (ep != NULL && *ep == '-')
+				flags |= IEEE80211_CHAN_HT40D;
+			break;
+		default:
+			errx(-1, "%s: Invalid channel width\n", val);
+		}
+	}
+	/*
+	 * Cleanup specifications.
+	 */ 
+	if ((flags & _CHAN_HT) == 0) {
+		/*
+		 * If user specified freq/20 or freq/40 quietly remove
+		 * HT cw attributes depending on channel use.  To give
+		 * an explicit 20/40 width for an HT channel you must
+		 * indicate it is an HT channel since all HT channels
+		 * are also usable for legacy operation; e.g. freq:n/40.
+		 */
+		flags &= ~IEEE80211_CHAN_HT;
+	} else {
+		/*
+		 * Remove private indicator that this is an HT channel
+		 * and if no explicit channel width has been given
+		 * provide the default settings.
+		 */
+		flags &= ~_CHAN_HT;
+		if ((flags & IEEE80211_CHAN_HT) == 0) {
+			struct ieee80211_channel chan;
+			/*
+			 * Consult the channel list to see if we can use
+			 * HT40+ or HT40- (if both the map routines choose).
+			 */
+			if (freq > 255)
+				mapfreq(&chan, freq, 0);
+			else
+				mapchan(&chan, freq, 0);
+			flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
+		}
+	}
+	return flags;
+#undef _CHAN_HT
+}
+
+static void
+getchannel(int s, struct ieee80211_channel *chan, const char *val)
+{
+	int v, flags;
+	char *eptr;
+
+	memset(chan, 0, sizeof(*chan));
+	if (isanyarg(val)) {
+		chan->ic_freq = IEEE80211_CHAN_ANY;
+		return;
+	}
+	getchaninfo(s);
+	errno = 0;
+	v = strtol(val, &eptr, 10);
+	if (val[0] == '\0' || val == eptr || errno == ERANGE ||
+	    /* channel may be suffixed with nothing, :flag, or /width */
+	    (eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/'))
+		errx(1, "invalid channel specification%s",
+		    errno == ERANGE ? " (out of range)" : "");
+	flags = getchannelflags(val, v);
+	if (v > 255) {		/* treat as frequency */
+		mapfreq(chan, v, flags);
+	} else {
+		mapchan(chan, v, flags);
+	}
+}
+
+static void
+set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct ieee80211_channel chan;
+
+	getchannel(s, &chan, val);
+	set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
+}
+
+static void
+set80211chanswitch(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct ieee80211_chanswitch_req csr;
+
+	getchannel(s, &csr.csa_chan, val);
+	csr.csa_mode = 1;
+	csr.csa_count = 5;
+	set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr);
+}
+
+static void
+set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if (strcasecmp(val, "none") == 0) {
+		mode = IEEE80211_AUTH_NONE;
+	} else if (strcasecmp(val, "open") == 0) {
+		mode = IEEE80211_AUTH_OPEN;
+	} else if (strcasecmp(val, "shared") == 0) {
+		mode = IEEE80211_AUTH_SHARED;
+	} else if (strcasecmp(val, "8021x") == 0) {
+		mode = IEEE80211_AUTH_8021X;
+	} else if (strcasecmp(val, "wpa") == 0) {
+		mode = IEEE80211_AUTH_WPA;
+	} else {
+		errx(1, "unknown authmode");
+	}
+
+	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
+}
+
+static void
+set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if (strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_POWERSAVE_OFF;
+	} else if (strcasecmp(val, "on") == 0) {
+		mode = IEEE80211_POWERSAVE_ON;
+	} else if (strcasecmp(val, "cam") == 0) {
+		mode = IEEE80211_POWERSAVE_CAM;
+	} else if (strcasecmp(val, "psp") == 0) {
+		mode = IEEE80211_POWERSAVE_PSP;
+	} else if (strcasecmp(val, "psp-cam") == 0) {
+		mode = IEEE80211_POWERSAVE_PSP_CAM;
+	} else {
+		errx(1, "unknown powersavemode");
+	}
+
+	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
+}
+
+static void
+set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	if (d == 0)
+		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
+		    0, NULL);
+	else
+		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
+		    0, NULL);
+}
+
+static void
+set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
+}
+
+static void
+set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if (strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_WEP_OFF;
+	} else if (strcasecmp(val, "on") == 0) {
+		mode = IEEE80211_WEP_ON;
+	} else if (strcasecmp(val, "mixed") == 0) {
+		mode = IEEE80211_WEP_MIXED;
+	} else {
+		errx(1, "unknown wep mode");
+	}
+
+	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
+}
+
+static void
+set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
+}
+
+static int
+isundefarg(const char *arg)
+{
+	return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
+}
+
+static void
+set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	if (isundefarg(val))
+		set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
+	else
+		set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
+}
+
+static void
+set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		key = 0;
+	int		len;
+	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
+
+	if (isdigit((int)val[0]) && val[1] == ':') {
+		key = atoi(val)-1;
+		val += 2;
+	}
+
+	bzero(data, sizeof(data));
+	len = sizeof(data);
+	get_string(val, NULL, data, &len);
+
+	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
+}
+
+/*
+ * This function is purely a NetBSD compatability interface.  The NetBSD
+ * interface is too inflexible, but it's there so we'll support it since
+ * it's not all that hard.
+ */
+static void
+set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		txkey;
+	int		i, len;
+	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
+
+	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
+
+	if (isdigit((int)val[0]) && val[1] == ':') {
+		txkey = val[0]-'0'-1;
+		val += 2;
+
+		for (i = 0; i < 4; i++) {
+			bzero(data, sizeof(data));
+			len = sizeof(data);
+			val = get_string(val, ",", data, &len);
+			if (val == NULL)
+				exit(1);
+
+			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
+		}
+	} else {
+		bzero(data, sizeof(data));
+		len = sizeof(data);
+		get_string(val, NULL, data, &len);
+		txkey = 0;
+
+		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
+
+		bzero(data, sizeof(data));
+		for (i = 1; i < 4; i++)
+			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
+	}
+
+	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
+}
+
+static void
+set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
+		isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
+}
+
+static void
+set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if (strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_PROTMODE_OFF;
+	} else if (strcasecmp(val, "cts") == 0) {
+		mode = IEEE80211_PROTMODE_CTS;
+	} else if (strncasecmp(val, "rtscts", 3) == 0) {
+		mode = IEEE80211_PROTMODE_RTSCTS;
+	} else {
+		errx(1, "unknown protection mode");
+	}
+
+	set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
+}
+
+static void
+set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if (strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_PROTMODE_OFF;
+	} else if (strncasecmp(val, "rts", 3) == 0) {
+		mode = IEEE80211_PROTMODE_RTSCTS;
+	} else {
+		errx(1, "unknown protection mode");
+	}
+
+	set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
+}
+
+static void
+set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	double v = atof(val);
+	int txpow;
+
+	txpow = (int) (2*v);
+	if (txpow != 2*v)
+		errx(-1, "invalid tx power (must be .5 dBm units)");
+	set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
+}
+
+#define	IEEE80211_ROAMING_DEVICE	0
+#define	IEEE80211_ROAMING_AUTO		1
+#define	IEEE80211_ROAMING_MANUAL	2
+
+static void
+set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int mode;
+
+	if (strcasecmp(val, "device") == 0) {
+		mode = IEEE80211_ROAMING_DEVICE;
+	} else if (strcasecmp(val, "auto") == 0) {
+		mode = IEEE80211_ROAMING_AUTO;
+	} else if (strcasecmp(val, "manual") == 0) {
+		mode = IEEE80211_ROAMING_MANUAL;
+	} else {
+		errx(1, "unknown roaming mode");
+	}
+	set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
+}
+
+static void
+set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
+}
+
+static void
+set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
+}
+
+static void
+set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
+}
+
+static void
+set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
+}
+
+static void
+set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
+}
+
+static void
+set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct ieee80211req_chanlist chanlist;
+	char *temp, *cp, *tp;
+
+	temp = malloc(strlen(val) + 1);
+	if (temp == NULL)
+		errx(1, "malloc failed");
+	strcpy(temp, val);
+	memset(&chanlist, 0, sizeof(chanlist));
+	cp = temp;
+	for (;;) {
+		int first, last, f, c;
+
+		tp = strchr(cp, ',');
+		if (tp != NULL)
+			*tp++ = '\0';
+		switch (sscanf(cp, "%u-%u", &first, &last)) {
+		case 1:
+			if (first > IEEE80211_CHAN_MAX)
+				errx(-1, "channel %u out of range, max %u",
+					first, IEEE80211_CHAN_MAX);
+			setbit(chanlist.ic_channels, first);
+			break;
+		case 2:
+			if (first > IEEE80211_CHAN_MAX)
+				errx(-1, "channel %u out of range, max %u",
+					first, IEEE80211_CHAN_MAX);
+			if (last > IEEE80211_CHAN_MAX)
+				errx(-1, "channel %u out of range, max %u",
+					last, IEEE80211_CHAN_MAX);
+			if (first > last)
+				errx(-1, "void channel range, %u > %u",
+					first, last);
+			for (f = first; f <= last; f++)
+				setbit(chanlist.ic_channels, f);
+			break;
+		}
+		if (tp == NULL)
+			break;
+		c = *tp;
+		while (isspace(c))
+			tp++;
+		if (!isdigit(c))
+			break;
+		cp = tp;
+	}
+	set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
+}
+
+static void
+set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+	if (!isanyarg(val)) {
+		char *temp;
+		struct sockaddr_dl sdl;
+
+		temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+		if (temp == NULL)
+			errx(1, "malloc failed");
+		temp[0] = ':';
+		strcpy(temp + 1, val);
+		sdl.sdl_len = sizeof(sdl);
+		link_addr(temp, &sdl);
+		free(temp);
+		if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+			errx(1, "malformed link-level address");
+		set80211(s, IEEE80211_IOC_BSSID, 0,
+			IEEE80211_ADDR_LEN, LLADDR(&sdl));
+	} else {
+		uint8_t zerobssid[IEEE80211_ADDR_LEN];
+		memset(zerobssid, 0, sizeof(zerobssid));
+		set80211(s, IEEE80211_IOC_BSSID, 0,
+			IEEE80211_ADDR_LEN, zerobssid);
+	}
+}
+
+static int
+getac(const char *ac)
+{
+	if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
+		return WME_AC_BE;
+	if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
+		return WME_AC_BK;
+	if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
+		return WME_AC_VI;
+	if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
+		return WME_AC_VO;
+	errx(1, "unknown wme access class %s", ac);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmin, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmax, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211aifs, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211txoplimit, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211acm, ac, d)
+{
+	set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
+}
+static
+DECL_CMD_FUNC(set80211noacm, ac, d)
+{
+	set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ackpolicy, ac, d)
+{
+	set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
+}
+static
+DECL_CMD_FUNC(set80211noackpolicy, ac, d)
+{
+	set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
+		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
+		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bssaifs, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
+		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
+{
+	set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
+		getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211dtimperiod, val, d)
+{
+	set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bintval, val, d)
+{
+	set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
+}
+
+static void
+set80211macmac(int s, int op, const char *val)
+{
+	char *temp;
+	struct sockaddr_dl sdl;
+
+	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+	if (temp == NULL)
+		errx(1, "malloc failed");
+	temp[0] = ':';
+	strcpy(temp + 1, val);
+	sdl.sdl_len = sizeof(sdl);
+	link_addr(temp, &sdl);
+	free(temp);
+	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+		errx(1, "malformed link-level address");
+	set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
+}
+
+static
+DECL_CMD_FUNC(set80211addmac, val, d)
+{
+	set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211delmac, val, d)
+{
+	set80211macmac(s, IEEE80211_IOC_DELMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211kickmac, val, d)
+{
+	char *temp;
+	struct sockaddr_dl sdl;
+	struct ieee80211req_mlme mlme;
+
+	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+	if (temp == NULL)
+		errx(1, "malloc failed");
+	temp[0] = ':';
+	strcpy(temp + 1, val);
+	sdl.sdl_len = sizeof(sdl);
+	link_addr(temp, &sdl);
+	free(temp);
+	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+		errx(1, "malformed link-level address");
+	memset(&mlme, 0, sizeof(mlme));
+	mlme.im_op = IEEE80211_MLME_DEAUTH;
+	mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
+	memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
+	set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
+}
+
+static
+DECL_CMD_FUNC(set80211maccmd, val, d)
+{
+	set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
+}
+
+static void
+set80211meshrtmac(int s, int req, const char *val)
+{
+	char *temp;
+	struct sockaddr_dl sdl;
+
+	temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+	if (temp == NULL)
+		errx(1, "malloc failed");
+	temp[0] = ':';
+	strcpy(temp + 1, val);
+	sdl.sdl_len = sizeof(sdl);
+	link_addr(temp, &sdl);
+	free(temp);
+	if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+		errx(1, "malformed link-level address");
+	set80211(s, IEEE80211_IOC_MESH_RTCMD, req,
+	    IEEE80211_ADDR_LEN, LLADDR(&sdl));
+}
+
+static
+DECL_CMD_FUNC(set80211addmeshrt, val, d)
+{
+	set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val);
+}
+
+static
+DECL_CMD_FUNC(set80211delmeshrt, val, d)
+{
+	set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val);
+}
+
+static
+DECL_CMD_FUNC(set80211meshrtcmd, val, d)
+{
+	set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211hwmprootmode, val, d)
+{
+	int mode;
+
+	if (strcasecmp(val, "normal") == 0)
+		mode = IEEE80211_HWMP_ROOTMODE_NORMAL;
+	else if (strcasecmp(val, "proactive") == 0)
+		mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
+	else if (strcasecmp(val, "rann") == 0)
+		mode = IEEE80211_HWMP_ROOTMODE_RANN;
+	else
+		mode = IEEE80211_HWMP_ROOTMODE_DISABLED;
+	set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211hwmpmaxhops, val, d)
+{
+	set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL);
+}
+
+static void
+set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
+}
+
+static void
+set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bgscanidle, val, d)
+{
+	set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bgscanintvl, val, d)
+{
+	set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211scanvalid, val, d)
+{
+	set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
+}
+
+/*
+ * Parse an optional trailing specification of which netbands
+ * to apply a parameter to.  This is basically the same syntax
+ * as used for channels but you can concatenate to specify
+ * multiple.  For example:
+ *	14:abg		apply to 11a, 11b, and 11g
+ *	6:ht		apply to 11na and 11ng
+ * We don't make a big effort to catch silly things; this is
+ * really a convenience mechanism.
+ */
+static int
+getmodeflags(const char *val)
+{
+	const char *cp;
+	int flags;
+
+	flags = 0;
+
+	cp = strchr(val, ':');
+	if (cp != NULL) {
+		for (cp++; isalpha((int) *cp); cp++) {
+			/* accept mixed case */
+			int c = *cp;
+			if (isupper(c))
+				c = tolower(c);
+			switch (c) {
+			case 'a':		/* 802.11a */
+				flags |= IEEE80211_CHAN_A;
+				break;
+			case 'b':		/* 802.11b */
+				flags |= IEEE80211_CHAN_B;
+				break;
+			case 'g':		/* 802.11g */
+				flags |= IEEE80211_CHAN_G;
+				break;
+			case 'n':		/* 802.11n */
+				flags |= IEEE80211_CHAN_HT;
+				break;
+			case 'd':		/* dt = Atheros Dynamic Turbo */
+				flags |= IEEE80211_CHAN_TURBO;
+				break;
+			case 't':		/* ht, dt, st, t */
+				/* dt and unadorned t specify Dynamic Turbo */
+				if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0)
+					flags |= IEEE80211_CHAN_TURBO;
+				break;
+			case 's':		/* st = Atheros Static Turbo */
+				flags |= IEEE80211_CHAN_STURBO;
+				break;
+			case 'h':		/* 1/2-width channels */
+				flags |= IEEE80211_CHAN_HALF;
+				break;
+			case 'q':		/* 1/4-width channels */
+				flags |= IEEE80211_CHAN_QUARTER;
+				break;
+			default:
+				errx(-1, "%s: Invalid mode attribute %c\n",
+				    val, *cp);
+			}
+		}
+	}
+	return flags;
+}
+
+#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ)
+#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ)
+
+#define	_APPLY(_flags, _base, _param, _v) do {				\
+    if (_flags & IEEE80211_CHAN_HT) {					\
+	    if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
+		    _base.params[IEEE80211_MODE_11NA]._param = _v;	\
+		    _base.params[IEEE80211_MODE_11NG]._param = _v;	\
+	    } else if (_flags & IEEE80211_CHAN_5GHZ)			\
+		    _base.params[IEEE80211_MODE_11NA]._param = _v;	\
+	    else							\
+		    _base.params[IEEE80211_MODE_11NG]._param = _v;	\
+    }									\
+    if (_flags & IEEE80211_CHAN_TURBO) {				\
+	    if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
+		    _base.params[IEEE80211_MODE_TURBO_A]._param = _v;	\
+		    _base.params[IEEE80211_MODE_TURBO_G]._param = _v;	\
+	    } else if (_flags & IEEE80211_CHAN_5GHZ)			\
+		    _base.params[IEEE80211_MODE_TURBO_A]._param = _v;	\
+	    else							\
+		    _base.params[IEEE80211_MODE_TURBO_G]._param = _v;	\
+    }									\
+    if (_flags & IEEE80211_CHAN_STURBO)					\
+	    _base.params[IEEE80211_MODE_STURBO_A]._param = _v;		\
+    if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)		\
+	    _base.params[IEEE80211_MODE_11A]._param = _v;		\
+    if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)		\
+	    _base.params[IEEE80211_MODE_11G]._param = _v;		\
+    if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)		\
+	    _base.params[IEEE80211_MODE_11B]._param = _v;		\
+    if (_flags & IEEE80211_CHAN_HALF)					\
+	    _base.params[IEEE80211_MODE_HALF]._param = _v;		\
+    if (_flags & IEEE80211_CHAN_QUARTER)				\
+	    _base.params[IEEE80211_MODE_QUARTER]._param = _v;		\
+} while (0)
+#define	_APPLY1(_flags, _base, _param, _v) do {				\
+    if (_flags & IEEE80211_CHAN_HT) {					\
+	    if (_flags & IEEE80211_CHAN_5GHZ)				\
+		    _base.params[IEEE80211_MODE_11NA]._param = _v;	\
+	    else							\
+		    _base.params[IEEE80211_MODE_11NG]._param = _v;	\
+    } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)	\
+	    _base.params[IEEE80211_MODE_TURBO_A]._param = _v;		\
+    else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)	\
+	    _base.params[IEEE80211_MODE_TURBO_G]._param = _v;		\
+    else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)		\
+	    _base.params[IEEE80211_MODE_STURBO_A]._param = _v;		\
+    else if (_flags & IEEE80211_CHAN_HALF)				\
+	    _base.params[IEEE80211_MODE_HALF]._param = _v;		\
+    else if (_flags & IEEE80211_CHAN_QUARTER)				\
+	    _base.params[IEEE80211_MODE_QUARTER]._param = _v;		\
+    else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)		\
+	    _base.params[IEEE80211_MODE_11A]._param = _v;		\
+    else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)		\
+	    _base.params[IEEE80211_MODE_11G]._param = _v;		\
+    else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)		\
+	    _base.params[IEEE80211_MODE_11B]._param = _v;		\
+} while (0)
+#define	_APPLY_RATE(_flags, _base, _param, _v) do {			\
+    if (_flags & IEEE80211_CHAN_HT) {					\
+	(_v) = (_v / 2) | IEEE80211_RATE_MCS;				\
+    }									\
+    _APPLY(_flags, _base, _param, _v);					\
+} while (0)
+#define	_APPLY_RATE1(_flags, _base, _param, _v) do {			\
+    if (_flags & IEEE80211_CHAN_HT) {					\
+	(_v) = (_v / 2) | IEEE80211_RATE_MCS;				\
+    }									\
+    _APPLY1(_flags, _base, _param, _v);					\
+} while (0)
+
+static
+DECL_CMD_FUNC(set80211roamrssi, val, d)
+{
+	double v = atof(val);
+	int rssi, flags;
+
+	rssi = (int) (2*v);
+	if (rssi != 2*v)
+		errx(-1, "invalid rssi (must be .5 dBm units)");
+	flags = getmodeflags(val);
+	getroam(s);
+	if (flags == 0) {		/* NB: no flags => current channel */
+		flags = getcurchan(s)->ic_flags;
+		_APPLY1(flags, roamparams, rssi, rssi);
+	} else
+		_APPLY(flags, roamparams, rssi, rssi);
+	callback_register(setroam_cb, &roamparams);
+}
+
+static int
+getrate(const char *val, const char *tag)
+{
+	double v = atof(val);
+	int rate;
+
+	rate = (int) (2*v);
+	if (rate != 2*v)
+		errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag);
+	return rate;		/* NB: returns 2x the specified value */
+}
+
+static
+DECL_CMD_FUNC(set80211roamrate, val, d)
+{
+	int rate, flags;
+
+	rate = getrate(val, "roam");
+	flags = getmodeflags(val);
+	getroam(s);
+	if (flags == 0) {		/* NB: no flags => current channel */
+		flags = getcurchan(s)->ic_flags;
+		_APPLY_RATE1(flags, roamparams, rate, rate);
+	} else
+		_APPLY_RATE(flags, roamparams, rate, rate);
+	callback_register(setroam_cb, &roamparams);
+}
+
+static
+DECL_CMD_FUNC(set80211mcastrate, val, d)
+{
+	int rate, flags;
+
+	rate = getrate(val, "mcast");
+	flags = getmodeflags(val);
+	gettxparams(s);
+	if (flags == 0) {		/* NB: no flags => current channel */
+		flags = getcurchan(s)->ic_flags;
+		_APPLY_RATE1(flags, txparams, mcastrate, rate);
+	} else
+		_APPLY_RATE(flags, txparams, mcastrate, rate);
+	callback_register(settxparams_cb, &txparams);
+}
+
+static
+DECL_CMD_FUNC(set80211mgtrate, val, d)
+{
+	int rate, flags;
+
+	rate = getrate(val, "mgmt");
+	flags = getmodeflags(val);
+	gettxparams(s);
+	if (flags == 0) {		/* NB: no flags => current channel */
+		flags = getcurchan(s)->ic_flags;
+		_APPLY_RATE1(flags, txparams, mgmtrate, rate);
+	} else
+		_APPLY_RATE(flags, txparams, mgmtrate, rate);
+	callback_register(settxparams_cb, &txparams);
+}
+
+static
+DECL_CMD_FUNC(set80211ucastrate, val, d)
+{
+	int flags;
+
+	gettxparams(s);
+	flags = getmodeflags(val);
+	if (isanyarg(val)) {
+		if (flags == 0) {	/* NB: no flags => current channel */
+			flags = getcurchan(s)->ic_flags;
+			_APPLY1(flags, txparams, ucastrate,
+			    IEEE80211_FIXED_RATE_NONE);
+		} else
+			_APPLY(flags, txparams, ucastrate,
+			    IEEE80211_FIXED_RATE_NONE);
+	} else {
+		int rate = getrate(val, "ucast");
+		if (flags == 0) {	/* NB: no flags => current channel */
+			flags = getcurchan(s)->ic_flags;
+			_APPLY_RATE1(flags, txparams, ucastrate, rate);
+		} else
+			_APPLY_RATE(flags, txparams, ucastrate, rate);
+	}
+	callback_register(settxparams_cb, &txparams);
+}
+
+static
+DECL_CMD_FUNC(set80211maxretry, val, d)
+{
+	int v = atoi(val), flags;
+
+	flags = getmodeflags(val);
+	gettxparams(s);
+	if (flags == 0) {		/* NB: no flags => current channel */
+		flags = getcurchan(s)->ic_flags;
+		_APPLY1(flags, txparams, maxretry, v);
+	} else
+		_APPLY(flags, txparams, maxretry, v);
+	callback_register(settxparams_cb, &txparams);
+}
+#undef _APPLY_RATE
+#undef _APPLY
+#undef IEEE80211_CHAN_HTA
+#undef IEEE80211_CHAN_HTG
+
+static
+DECL_CMD_FUNC(set80211fragthreshold, val, d)
+{
+	set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
+		isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bmissthreshold, val, d)
+{
+	set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
+		isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
+}
+
+static void
+set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+}
+
+static void
+set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
+}
+
+static void
+set80211dfs(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_DFS, d, 0, NULL);
+}
+
+static void
+set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_SHORTGI,
+		d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
+		0, NULL);
+}
+
+static void
+set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int ampdu;
+
+	if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
+		errx(-1, "cannot get AMPDU setting");
+	if (d < 0) {
+		d = -d;
+		ampdu &= ~d;
+	} else
+		ampdu |= d;
+	set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ampdulimit, val, d)
+{
+	int v;
+
+	switch (atoi(val)) {
+	case 8:
+	case 8*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
+		break;
+	case 16:
+	case 16*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
+		break;
+	case 32:
+	case 32*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
+		break;
+	case 64:
+	case 64*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+		break;
+	default:
+		errx(-1, "invalid A-MPDU limit %s", val);
+	}
+	set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ampdudensity, val, d)
+{
+	int v;
+
+	if (isanyarg(val) || strcasecmp(val, "na") == 0)
+		v = IEEE80211_HTCAP_MPDUDENSITY_NA;
+	else switch ((int)(atof(val)*4)) {
+	case 0:
+		v = IEEE80211_HTCAP_MPDUDENSITY_NA;
+		break;
+	case 1:
+		v = IEEE80211_HTCAP_MPDUDENSITY_025;
+		break;
+	case 2:
+		v = IEEE80211_HTCAP_MPDUDENSITY_05;
+		break;
+	case 4:
+		v = IEEE80211_HTCAP_MPDUDENSITY_1;
+		break;
+	case 8:
+		v = IEEE80211_HTCAP_MPDUDENSITY_2;
+		break;
+	case 16:
+		v = IEEE80211_HTCAP_MPDUDENSITY_4;
+		break;
+	case 32:
+		v = IEEE80211_HTCAP_MPDUDENSITY_8;
+		break;
+	case 64:
+		v = IEEE80211_HTCAP_MPDUDENSITY_16;
+		break;
+	default:
+		errx(-1, "invalid A-MPDU density %s", val);
+	}
+	set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
+}
+
+static void
+set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int amsdu;
+
+	if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
+		err(-1, "cannot get AMSDU setting");
+	if (d < 0) {
+		d = -d;
+		amsdu &= ~d;
+	} else
+		amsdu |= d;
+	set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211amsdulimit, val, d)
+{
+	set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
+}
+
+static void
+set80211puren(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
+}
+
+static void
+set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
+}
+
+static void
+set80211htconf(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
+	htconf = d;
+}
+
+static void
+set80211dwds(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL);
+}
+
+static void
+set80211inact(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
+}
+
+static void
+set80211tsn(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_TSN, d, 0, NULL);
+}
+
+static void
+set80211dotd(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL);
+}
+
+static void
+set80211smps(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL);
+}
+
+static void
+set80211rifs(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslot, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslotcnt, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslotlen, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmabintval, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshttl, val, d)
+{
+	set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshforward, val, d)
+{
+	set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshpeering, val, d)
+{
+	set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshmetric, val, d)
+{
+	char v[12];
+	
+	memcpy(v, val, sizeof(v));
+	set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
+}
+
+static
+DECL_CMD_FUNC(set80211meshpath, val, d)
+{
+	char v[12];
+	
+	memcpy(v, val, sizeof(v));
+	set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
+}
+
+static int
+regdomain_sort(const void *a, const void *b)
+{
+#define	CHAN_ALL \
+	(IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)
+	const struct ieee80211_channel *ca = a;
+	const struct ieee80211_channel *cb = b;
+
+	return ca->ic_freq == cb->ic_freq ?
+	    (ca->ic_flags & CHAN_ALL) - (cb->ic_flags & CHAN_ALL) :
+	    ca->ic_freq - cb->ic_freq;
+#undef CHAN_ALL
+}
+
+static const struct ieee80211_channel *
+chanlookup(const struct ieee80211_channel chans[], int nchans,
+	int freq, int flags)
+{
+	int i;
+
+	flags &= IEEE80211_CHAN_ALLTURBO;
+	for (i = 0; i < nchans; i++) {
+		const struct ieee80211_channel *c = &chans[i];
+		if (c->ic_freq == freq &&
+		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
+			return c;
+	}
+	return NULL;
+}
+
+static int
+chanfind(const struct ieee80211_channel chans[], int nchans, int flags)
+{
+	int i;
+
+	for (i = 0; i < nchans; i++) {
+		const struct ieee80211_channel *c = &chans[i];
+		if ((c->ic_flags & flags) == flags)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Check channel compatibility.
+ */
+static int
+checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags)
+{
+	flags &= ~REQ_FLAGS;
+	/*
+	 * Check if exact channel is in the calibration table;
+	 * everything below is to deal with channels that we
+	 * want to include but that are not explicitly listed.
+	 */
+	if (flags & IEEE80211_CHAN_HT40) {
+		/* NB: we use an HT40 channel center that matches HT20 */
+		flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20;
+	}
+	if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL)
+		return 1;
+	if (flags & IEEE80211_CHAN_GSM) {
+		/*
+		 * XXX GSM frequency mapping is handled in the kernel
+		 * so we cannot find them in the calibration table;
+		 * just accept the channel and the kernel will reject
+		 * the channel list if it's wrong.
+		 */
+		return 1;
+	}
+	/*
+	 * If this is a 1/2 or 1/4 width channel allow it if a full
+	 * width channel is present for this frequency, and the device
+	 * supports fractional channels on this band.  This is a hack
+	 * that avoids bloating the calibration table; it may be better
+	 * by per-band attributes though (we are effectively calculating
+	 * this attribute by scanning the channel list ourself).
+	 */
+	if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0)
+		return 0;
+	if (chanlookup(avail->ic_chans, avail->ic_nchans, freq,
+	    flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL)
+		return 0;
+	if (flags & IEEE80211_CHAN_HALF) {
+		return chanfind(avail->ic_chans, avail->ic_nchans,
+		    IEEE80211_CHAN_HALF |
+		       (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
+	} else {
+		return chanfind(avail->ic_chans, avail->ic_nchans,
+		    IEEE80211_CHAN_QUARTER |
+			(flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
+	}
+}
+
+static void
+regdomain_addchans(struct ieee80211req_chaninfo *ci,
+	const netband_head *bands,
+	const struct ieee80211_regdomain *reg,
+	uint32_t chanFlags,
+	const struct ieee80211req_chaninfo *avail)
+{
+	const struct netband *nb;
+	const struct freqband *b;
+	struct ieee80211_channel *c, *prev;
+	int freq, hi_adj, lo_adj, channelSep;
+	uint32_t flags;
+
+	hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
+	lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
+	channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
+	LIST_FOREACH(nb, bands, next) {
+		b = nb->band;
+		if (verbose) {
+			printf("%s:", __func__);
+			printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
+			printb(" bandFlags", nb->flags | b->flags,
+			    IEEE80211_CHAN_BITS);
+			putchar('\n');
+		}
+		prev = NULL;
+		for (freq = b->freqStart + lo_adj;
+		     freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
+			/*
+			 * Construct flags for the new channel.  We take
+			 * the attributes from the band descriptions except
+			 * for HT40 which is enabled generically (i.e. +/-
+			 * extension channel) in the band description and
+			 * then constrained according by channel separation.
+			 */
+			flags = nb->flags | b->flags;
+			if (flags & IEEE80211_CHAN_HT) {
+				/*
+				 * HT channels are generated specially; we're
+				 * called to add HT20, HT40+, and HT40- chan's
+				 * so we need to expand only band specs for
+				 * the HT channel type being added.
+				 */
+				if ((chanFlags & IEEE80211_CHAN_HT20) &&
+				    (flags & IEEE80211_CHAN_HT20) == 0) {
+					if (verbose)
+						printf("%u: skip, not an "
+						    "HT20 channel\n", freq);
+					continue;
+				}
+				if ((chanFlags & IEEE80211_CHAN_HT40) &&
+				    (flags & IEEE80211_CHAN_HT40) == 0) {
+					if (verbose)
+						printf("%u: skip, not an "
+						    "HT40 channel\n", freq);
+					continue;
+				}
+				/*
+				 * DFS and HT40 don't mix.  This should be
+				 * expressed in the regdomain database but
+				 * just in case enforce it here.
+				 */
+				if ((chanFlags & IEEE80211_CHAN_HT40) &&
+				    (flags & IEEE80211_CHAN_DFS)) {
+					if (verbose)
+						printf("%u: skip, HT40+DFS "
+						    "not permitted\n", freq);
+					continue;
+				}
+				/* NB: HT attribute comes from caller */
+				flags &= ~IEEE80211_CHAN_HT;
+				flags |= chanFlags & IEEE80211_CHAN_HT;
+			}
+			/*
+			 * Check if device can operate on this frequency.
+			 */
+			if (!checkchan(avail, freq, flags)) {
+				if (verbose) {
+					printf("%u: skip, ", freq);
+					printb("flags", flags,
+					    IEEE80211_CHAN_BITS);
+					printf(" not available\n");
+				}
+				continue;
+			}
+			if ((flags & REQ_ECM) && !reg->ecm) {
+				if (verbose)
+					printf("%u: skip, ECM channel\n", freq);
+				continue;
+			}
+			if ((flags & REQ_INDOOR) && reg->location == 'O') {
+				if (verbose)
+					printf("%u: skip, indoor channel\n",
+					    freq);
+				continue;
+			}
+			if ((flags & REQ_OUTDOOR) && reg->location == 'I') {
+				if (verbose)
+					printf("%u: skip, outdoor channel\n",
+					    freq);
+				continue;
+			}
+			if ((flags & IEEE80211_CHAN_HT40) &&
+			    prev != NULL && (freq - prev->ic_freq) < channelSep) {
+				if (verbose)
+					printf("%u: skip, only %u channel "
+					    "separation, need %d\n", freq, 
+					    freq - prev->ic_freq, channelSep);
+				continue;
+			}
+			if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
+				if (verbose)
+					printf("%u: skip, channel table full\n",
+					    freq);
+				break;
+			}
+			c = &ci->ic_chans[ci->ic_nchans++];
+			memset(c, 0, sizeof(*c));
+			c->ic_freq = freq;
+			c->ic_flags = flags;
+			if (c->ic_flags & IEEE80211_CHAN_DFS)
+				c->ic_maxregpower = nb->maxPowerDFS;
+			else
+				c->ic_maxregpower = nb->maxPower;
+			if (verbose) {
+				printf("[%3d] add freq %u ",
+				    ci->ic_nchans-1, c->ic_freq);
+				printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
+				printf(" power %u\n", c->ic_maxregpower);
+			}
+			/* NB: kernel fills in other fields */
+			prev = c;
+		}
+	}
+}
+
+static void
+regdomain_makechannels(
+	struct ieee80211_regdomain_req *req,
+	const struct ieee80211_devcaps_req *dc)
+{
+	struct regdata *rdp = getregdata();
+	const struct country *cc;
+	const struct ieee80211_regdomain *reg = &req->rd;
+	struct ieee80211req_chaninfo *ci = &req->chaninfo;
+	const struct regdomain *rd;
+
+	/*
+	 * Locate construction table for new channel list.  We treat
+	 * the regdomain/SKU as definitive so a country can be in
+	 * multiple with different properties (e.g. US in FCC+FCC3).
+	 * If no regdomain is specified then we fallback on the country
+	 * code to find the associated regdomain since countries always
+	 * belong to at least one regdomain.
+	 */
+	if (reg->regdomain == 0) {
+		cc = lib80211_country_findbycc(rdp, reg->country);
+		if (cc == NULL)
+			errx(1, "internal error, country %d not found",
+			    reg->country);
+		rd = cc->rd;
+	} else
+		rd = lib80211_regdomain_findbysku(rdp, reg->regdomain);
+	if (rd == NULL)
+		errx(1, "internal error, regdomain %d not found",
+			    reg->regdomain);
+	if (rd->sku != SKU_DEBUG) {
+		/*
+		 * regdomain_addchans incrememnts the channel count for
+		 * each channel it adds so initialize ic_nchans to zero.
+		 * Note that we know we have enough space to hold all possible
+		 * channels because the devcaps list size was used to
+		 * allocate our request.
+		 */
+		ci->ic_nchans = 0;
+		if (!LIST_EMPTY(&rd->bands_11b))
+			regdomain_addchans(ci, &rd->bands_11b, reg,
+			    IEEE80211_CHAN_B, &dc->dc_chaninfo);
+		if (!LIST_EMPTY(&rd->bands_11g))
+			regdomain_addchans(ci, &rd->bands_11g, reg,
+			    IEEE80211_CHAN_G, &dc->dc_chaninfo);
+		if (!LIST_EMPTY(&rd->bands_11a))
+			regdomain_addchans(ci, &rd->bands_11a, reg,
+			    IEEE80211_CHAN_A, &dc->dc_chaninfo);
+		if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) {
+			regdomain_addchans(ci, &rd->bands_11na, reg,
+			    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
+			    &dc->dc_chaninfo);
+			if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
+				regdomain_addchans(ci, &rd->bands_11na, reg,
+				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,
+				    &dc->dc_chaninfo);
+				regdomain_addchans(ci, &rd->bands_11na, reg,
+				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,
+				    &dc->dc_chaninfo);
+			}
+		}
+		if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
+			regdomain_addchans(ci, &rd->bands_11ng, reg,
+			    IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
+			    &dc->dc_chaninfo);
+			if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
+				regdomain_addchans(ci, &rd->bands_11ng, reg,
+				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,
+				    &dc->dc_chaninfo);
+				regdomain_addchans(ci, &rd->bands_11ng, reg,
+				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,
+				    &dc->dc_chaninfo);
+			}
+		}
+		qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
+		    regdomain_sort);
+	} else
+		memcpy(ci, &dc->dc_chaninfo,
+		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
+}
+
+static void
+list_countries(void)
+{
+	struct regdata *rdp = getregdata();
+	const struct country *cp;
+	const struct regdomain *dp;
+	int i;
+
+	i = 0;
+	printf("\nCountry codes:\n");
+	LIST_FOREACH(cp, &rdp->countries, next) {
+		printf("%2s %-15.15s%s", cp->isoname,
+		    cp->name, ((i+1)%4) == 0 ? "\n" : " ");
+		i++;
+	}
+	i = 0;
+	printf("\nRegulatory domains:\n");
+	LIST_FOREACH(dp, &rdp->domains, next) {
+		printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " ");
+		i++;
+	}
+	printf("\n");
+}
+
+static void
+defaultcountry(const struct regdomain *rd)
+{
+	struct regdata *rdp = getregdata();
+	const struct country *cc;
+
+	cc = lib80211_country_findbycc(rdp, rd->cc->code);
+	if (cc == NULL)
+		errx(1, "internal error, ISO country code %d not "
+		    "defined for regdomain %s", rd->cc->code, rd->name);
+	regdomain.country = cc->code;
+	regdomain.isocc[0] = cc->isoname[0];
+	regdomain.isocc[1] = cc->isoname[1];
+}
+
+static
+DECL_CMD_FUNC(set80211regdomain, val, d)
+{
+	struct regdata *rdp = getregdata();
+	const struct regdomain *rd;
+
+	rd = lib80211_regdomain_findbyname(rdp, val);
+	if (rd == NULL) {
+		char *eptr;
+		long sku = strtol(val, &eptr, 0);
+
+		if (eptr != val)
+			rd = lib80211_regdomain_findbysku(rdp, sku);
+		if (eptr == val || rd == NULL)
+			errx(1, "unknown regdomain %s", val);
+	}
+	getregdomain(s);
+	regdomain.regdomain = rd->sku;
+	if (regdomain.country == 0 && rd->cc != NULL) {
+		/*
+		 * No country code setup and there's a default
+		 * one for this regdomain fill it in.
+		 */
+		defaultcountry(rd);
+	}
+	callback_register(setregdomain_cb, &regdomain);
+}
+
+static
+DECL_CMD_FUNC(set80211country, val, d)
+{
+	struct regdata *rdp = getregdata();
+	const struct country *cc;
+
+	cc = lib80211_country_findbyname(rdp, val);
+	if (cc == NULL) {
+		char *eptr;
+		long code = strtol(val, &eptr, 0);
+
+		if (eptr != val)
+			cc = lib80211_country_findbycc(rdp, code);
+		if (eptr == val || cc == NULL)
+			errx(1, "unknown ISO country code %s", val);
+	}
+	getregdomain(s);
+	regdomain.regdomain = cc->rd->sku;
+	regdomain.country = cc->code;
+	regdomain.isocc[0] = cc->isoname[0];
+	regdomain.isocc[1] = cc->isoname[1];
+	callback_register(setregdomain_cb, &regdomain);
+}
+
+static void
+set80211location(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	getregdomain(s);
+	regdomain.location = d;
+	callback_register(setregdomain_cb, &regdomain);
+}
+
+static void
+set80211ecm(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	getregdomain(s);
+	regdomain.ecm = d;
+	callback_register(setregdomain_cb, &regdomain);
+}
+
+static void
+LINE_INIT(char c)
+{
+	spacer = c;
+	if (c == '\t')
+		col = 8;
+	else
+		col = 1;
+}
+
+static void
+LINE_BREAK(void)
+{
+	if (spacer != '\t') {
+		printf("\n");
+		spacer = '\t';
+	}
+	col = 8;		/* 8-col tab */
+}
+
+static void
+LINE_CHECK(const char *fmt, ...)
+{
+	char buf[80];
+	va_list ap;
+	int n;
+
+	va_start(ap, fmt);
+	n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
+	va_end(ap);
+	col += 1+n;
+	if (col > MAXCOL) {
+		LINE_BREAK();
+		col += n;
+	}
+	buf[0] = spacer;
+	printf("%s", buf);
+	spacer = ' ';
+}
+
+static int
+getmaxrate(const uint8_t rates[15], uint8_t nrates)
+{
+	int i, maxrate = -1;
+
+	for (i = 0; i < nrates; i++) {
+		int rate = rates[i] & IEEE80211_RATE_VAL;
+		if (rate > maxrate)
+			maxrate = rate;
+	}
+	return maxrate / 2;
+}
+
+static const char *
+getcaps(int capinfo)
+{
+	static char capstring[32];
+	char *cp = capstring;
+
+	if (capinfo & IEEE80211_CAPINFO_ESS)
+		*cp++ = 'E';
+	if (capinfo & IEEE80211_CAPINFO_IBSS)
+		*cp++ = 'I';
+	if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
+		*cp++ = 'c';
+	if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
+		*cp++ = 'C';
+	if (capinfo & IEEE80211_CAPINFO_PRIVACY)
+		*cp++ = 'P';
+	if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
+		*cp++ = 'S';
+	if (capinfo & IEEE80211_CAPINFO_PBCC)
+		*cp++ = 'B';
+	if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
+		*cp++ = 'A';
+	if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
+		*cp++ = 's';
+	if (capinfo & IEEE80211_CAPINFO_RSN)
+		*cp++ = 'R';
+	if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
+		*cp++ = 'D';
+	*cp = '\0';
+	return capstring;
+}
+
+static const char *
+getflags(int flags)
+{
+	static char flagstring[32];
+	char *cp = flagstring;
+
+	if (flags & IEEE80211_NODE_AUTH)
+		*cp++ = 'A';
+	if (flags & IEEE80211_NODE_QOS)
+		*cp++ = 'Q';
+	if (flags & IEEE80211_NODE_ERP)
+		*cp++ = 'E';
+	if (flags & IEEE80211_NODE_PWR_MGT)
+		*cp++ = 'P';
+	if (flags & IEEE80211_NODE_HT) {
+		*cp++ = 'H';
+		if (flags & IEEE80211_NODE_HTCOMPAT)
+			*cp++ = '+';
+	}
+	if (flags & IEEE80211_NODE_WPS)
+		*cp++ = 'W';
+	if (flags & IEEE80211_NODE_TSN)
+		*cp++ = 'N';
+	if (flags & IEEE80211_NODE_AMPDU_TX)
+		*cp++ = 'T';
+	if (flags & IEEE80211_NODE_AMPDU_RX)
+		*cp++ = 'R';
+	if (flags & IEEE80211_NODE_MIMO_PS) {
+		*cp++ = 'M';
+		if (flags & IEEE80211_NODE_MIMO_RTS)
+			*cp++ = '+';
+	}
+	if (flags & IEEE80211_NODE_RIFS)
+		*cp++ = 'I';
+	if (flags & IEEE80211_NODE_SGI40) {
+		*cp++ = 'S';
+		if (flags & IEEE80211_NODE_SGI20)
+			*cp++ = '+';
+	} else if (flags & IEEE80211_NODE_SGI20)
+		*cp++ = 's';
+	if (flags & IEEE80211_NODE_AMSDU_TX)
+		*cp++ = 't';
+	if (flags & IEEE80211_NODE_AMSDU_RX)
+		*cp++ = 'r';
+	*cp = '\0';
+	return flagstring;
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		maxlen -= strlen(tag)+2;
+		if (2*ielen > maxlen)
+			maxlen--;
+		printf("<");
+		for (; ielen > 0; ie++, ielen--) {
+			if (maxlen-- <= 0)
+				break;
+			printf("%02x", *ie);
+		}
+		if (ielen != 0)
+			printf("-");
+		printf(">");
+	}
+}
+
+#define LE_READ_2(p)					\
+	((u_int16_t)					\
+	 ((((const u_int8_t *)(p))[0]      ) |		\
+	  (((const u_int8_t *)(p))[1] <<  8)))
+#define LE_READ_4(p)					\
+	((u_int32_t)					\
+	 ((((const u_int8_t *)(p))[0]      ) |		\
+	  (((const u_int8_t *)(p))[1] <<  8) |		\
+	  (((const u_int8_t *)(p))[2] << 16) |		\
+	  (((const u_int8_t *)(p))[3] << 24)))
+
+/*
+ * NB: The decoding routines assume a properly formatted ie
+ *     which should be safe as the kernel only retains them
+ *     if they parse ok.
+ */
+
+static void
+printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
+	static const char *acnames[] = { "BE", "BK", "VO", "VI" };
+	const struct ieee80211_wme_param *wme =
+	    (const struct ieee80211_wme_param *) ie;
+	int i;
+
+	printf("%s", tag);
+	if (!verbose)
+		return;
+	printf("<qosinfo 0x%x", wme->param_qosInfo);
+	ie += offsetof(struct ieee80211_wme_param, params_acParams);
+	for (i = 0; i < WME_NUM_AC; i++) {
+		const struct ieee80211_wme_acparams *ac =
+		    &wme->params_acParams[i];
+
+		printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
+			, acnames[i]
+			, MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
+			, MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
+			, MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
+			, MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
+			, LE_READ_2(&ac->acp_txop)
+		);
+	}
+	printf(">");
+#undef MS
+}
+
+static void
+printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_wme_info *wme =
+		    (const struct ieee80211_wme_info *) ie;
+		printf("<version 0x%x info 0x%x>",
+		    wme->wme_version, wme->wme_info);
+	}
+}
+
+static void
+printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_ie_htcap *htcap =
+		    (const struct ieee80211_ie_htcap *) ie;
+		const char *sep;
+		int i, j;
+
+		printf("<cap 0x%x param 0x%x",
+		    LE_READ_2(&htcap->hc_cap), htcap->hc_param);
+		printf(" mcsset[");
+		sep = "";
+		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
+			if (isset(htcap->hc_mcsset, i)) {
+				for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
+					if (isclr(htcap->hc_mcsset, j))
+						break;
+				j--;
+				if (i == j)
+					printf("%s%u", sep, i);
+				else
+					printf("%s%u-%u", sep, i, j);
+				i += j-i;
+				sep = ",";
+			}
+		printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
+		    LE_READ_2(&htcap->hc_extcap),
+		    LE_READ_4(&htcap->hc_txbf),
+		    htcap->hc_antenna);
+	}
+}
+
+static void
+printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_ie_htinfo *htinfo =
+		    (const struct ieee80211_ie_htinfo *) ie;
+		const char *sep;
+		int i, j;
+
+		printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
+		    htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
+		    LE_READ_2(&htinfo->hi_byte45));
+		printf(" basicmcs[");
+		sep = "";
+		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
+			if (isset(htinfo->hi_basicmcsset, i)) {
+				for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
+					if (isclr(htinfo->hi_basicmcsset, j))
+						break;
+				j--;
+				if (i == j)
+					printf("%s%u", sep, i);
+				else
+					printf("%s%u-%u", sep, i, j);
+				i += j-i;
+				sep = ",";
+			}
+		printf("]>");
+	}
+}
+
+static void
+printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_ath_ie *ath =
+			(const struct ieee80211_ath_ie *)ie;
+
+		printf("<");
+		if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
+			printf("DTURBO,");
+		if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
+			printf("COMP,");
+		if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
+			printf("FF,");
+		if (ath->ath_capability & ATHEROS_CAP_XR)
+			printf("XR,");
+		if (ath->ath_capability & ATHEROS_CAP_AR)
+			printf("AR,");
+		if (ath->ath_capability & ATHEROS_CAP_BURST)
+			printf("BURST,");
+		if (ath->ath_capability & ATHEROS_CAP_WME)
+			printf("WME,");
+		if (ath->ath_capability & ATHEROS_CAP_BOOST)
+			printf("BOOST,");
+		printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
+	}
+}
+
+
+static void
+printmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+#define MATCHOUI(field, oui, string)					\
+do {									\
+	if (memcmp(field, oui, 4) == 0)					\
+		printf("%s", string);					\
+} while (0)
+
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_meshconf_ie *mconf =
+			(const struct ieee80211_meshconf_ie *)ie;
+		printf("<PATH:");
+		if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP)
+			printf("HWMP");
+		else
+			printf("UNKNOWN");
+		printf(" LINK:");
+		if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME)
+			printf("AIRTIME");
+		else
+			printf("UNKNOWN");
+		printf(" CONGESTION:");
+		if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED)
+			printf("DISABLED");
+		else
+			printf("UNKNOWN");
+		printf(" SYNC:");
+		if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF)
+			printf("NEIGHOFF");
+		else
+			printf("UNKNOWN");
+		printf(" AUTH:");
+		if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED)
+			printf("DISABLED");
+		else
+			printf("UNKNOWN");
+		printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
+		    mconf->conf_cap);
+	}
+#undef MATCHOUI
+}
+
+static const char *
+wpa_cipher(const u_int8_t *sel)
+{
+#define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case WPA_SEL(WPA_CSE_NULL):
+		return "NONE";
+	case WPA_SEL(WPA_CSE_WEP40):
+		return "WEP40";
+	case WPA_SEL(WPA_CSE_WEP104):
+		return "WEP104";
+	case WPA_SEL(WPA_CSE_TKIP):
+		return "TKIP";
+	case WPA_SEL(WPA_CSE_CCMP):
+		return "AES-CCMP";
+	}
+	return "?";		/* NB: so 1<< is discarded */
+#undef WPA_SEL
+}
+
+static const char *
+wpa_keymgmt(const u_int8_t *sel)
+{
+#define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case WPA_SEL(WPA_ASE_8021X_UNSPEC):
+		return "8021X-UNSPEC";
+	case WPA_SEL(WPA_ASE_8021X_PSK):
+		return "8021X-PSK";
+	case WPA_SEL(WPA_ASE_NONE):
+		return "NONE";
+	}
+	return "?";
+#undef WPA_SEL
+}
+
+static void
+printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	u_int8_t len = ie[1];
+
+	printf("%s", tag);
+	if (verbose) {
+		const char *sep;
+		int n;
+
+		ie += 6, len -= 4;		/* NB: len is payload only */
+
+		printf("<v%u", LE_READ_2(ie));
+		ie += 2, len -= 2;
+
+		printf(" mc:%s", wpa_cipher(ie));
+		ie += 4, len -= 4;
+
+		/* unicast ciphers */
+		n = LE_READ_2(ie);
+		ie += 2, len -= 2;
+		sep = " uc:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, wpa_cipher(ie));
+			ie += 4, len -= 4;
+			sep = "+";
+		}
+
+		/* key management algorithms */
+		n = LE_READ_2(ie);
+		ie += 2, len -= 2;
+		sep = " km:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, wpa_keymgmt(ie));
+			ie += 4, len -= 4;
+			sep = "+";
+		}
+
+		if (len > 2)		/* optional capabilities */
+			printf(", caps 0x%x", LE_READ_2(ie));
+		printf(">");
+	}
+}
+
+static const char *
+rsn_cipher(const u_int8_t *sel)
+{
+#define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case RSN_SEL(RSN_CSE_NULL):
+		return "NONE";
+	case RSN_SEL(RSN_CSE_WEP40):
+		return "WEP40";
+	case RSN_SEL(RSN_CSE_WEP104):
+		return "WEP104";
+	case RSN_SEL(RSN_CSE_TKIP):
+		return "TKIP";
+	case RSN_SEL(RSN_CSE_CCMP):
+		return "AES-CCMP";
+	case RSN_SEL(RSN_CSE_WRAP):
+		return "AES-OCB";
+	}
+	return "?";
+#undef WPA_SEL
+}
+
+static const char *
+rsn_keymgmt(const u_int8_t *sel)
+{
+#define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case RSN_SEL(RSN_ASE_8021X_UNSPEC):
+		return "8021X-UNSPEC";
+	case RSN_SEL(RSN_ASE_8021X_PSK):
+		return "8021X-PSK";
+	case RSN_SEL(RSN_ASE_NONE):
+		return "NONE";
+	}
+	return "?";
+#undef RSN_SEL
+}
+
+static void
+printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const char *sep;
+		int n;
+
+		ie += 2, ielen -= 2;
+
+		printf("<v%u", LE_READ_2(ie));
+		ie += 2, ielen -= 2;
+
+		printf(" mc:%s", rsn_cipher(ie));
+		ie += 4, ielen -= 4;
+
+		/* unicast ciphers */
+		n = LE_READ_2(ie);
+		ie += 2, ielen -= 2;
+		sep = " uc:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, rsn_cipher(ie));
+			ie += 4, ielen -= 4;
+			sep = "+";
+		}
+
+		/* key management algorithms */
+		n = LE_READ_2(ie);
+		ie += 2, ielen -= 2;
+		sep = " km:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, rsn_keymgmt(ie));
+			ie += 4, ielen -= 4;
+			sep = "+";
+		}
+
+		if (ielen > 2)		/* optional capabilities */
+			printf(", caps 0x%x", LE_READ_2(ie));
+		/* XXXPMKID */
+		printf(">");
+	}
+}
+
+/* XXX move to a public include file */
+#define IEEE80211_WPS_DEV_PASS_ID	0x1012
+#define IEEE80211_WPS_SELECTED_REG	0x1041
+#define IEEE80211_WPS_SETUP_STATE	0x1044
+#define IEEE80211_WPS_UUID_E		0x1047
+#define IEEE80211_WPS_VERSION		0x104a
+
+#define BE_READ_2(p)					\
+	((u_int16_t)					\
+	 ((((const u_int8_t *)(p))[1]      ) |		\
+	  (((const u_int8_t *)(p))[0] <<  8)))
+
+static void
+printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	u_int8_t len = ie[1];
+
+	printf("%s", tag);
+	if (verbose) {
+		static const char *dev_pass_id[] = {
+			"D",	/* Default (PIN) */
+			"U",	/* User-specified */
+			"M",	/* Machine-specified */
+			"K",	/* Rekey */
+			"P",	/* PushButton */
+			"R"	/* Registrar-specified */
+		};
+		int n;
+
+		ie +=6, len -= 4;		/* NB: len is payload only */
+
+		/* WPS IE in Beacon and Probe Resp frames have different fields */
+		printf("<");
+		while (len) {
+			uint16_t tlv_type = BE_READ_2(ie);
+			uint16_t tlv_len  = BE_READ_2(ie + 2);
+
+			ie += 4, len -= 4;
+
+			switch (tlv_type) {
+			case IEEE80211_WPS_VERSION:
+				printf("v:%d.%d", *ie >> 4, *ie & 0xf);
+				break;
+			case IEEE80211_WPS_SETUP_STATE:
+				/* Only 1 and 2 are valid */
+				if (*ie == 0 || *ie >= 3)
+					printf(" state:B");
+				else
+					printf(" st:%s", *ie == 1 ? "N" : "C");
+				break;
+			case IEEE80211_WPS_SELECTED_REG:
+				printf(" sel:%s", *ie ? "T" : "F");
+				break;
+			case IEEE80211_WPS_DEV_PASS_ID:
+				n = LE_READ_2(ie);
+				if (n < N(dev_pass_id))
+					printf(" dpi:%s", dev_pass_id[n]);
+				break;
+			case IEEE80211_WPS_UUID_E:
+				printf(" uuid-e:");
+				for (n = 0; n < (tlv_len - 1); n++)
+					printf("%02x-", ie[n]);
+				printf("%02x", ie[n]);
+				break;
+			}
+			ie += tlv_len, len -= tlv_len;
+		}
+		printf(">");
+	}
+#undef N
+}
+
+static void
+printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
+		const struct ieee80211_tdma_param *tdma =
+		   (const struct ieee80211_tdma_param *) ie;
+
+		/* XXX tstamp */
+		printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
+		    tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
+		    LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
+		    tdma->tdma_inuse[0]);
+	}
+}
+
+/*
+ * Copy the ssid string contents into buf, truncating to fit.  If the
+ * ssid is entirely printable then just copy intact.  Otherwise convert
+ * to hexadecimal.  If the result is truncated then replace the last
+ * three characters with "...".
+ */
+static int
+copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+{
+	const u_int8_t *p; 
+	size_t maxlen;
+	int i;
+
+	if (essid_len > bufsize)
+		maxlen = bufsize;
+	else
+		maxlen = essid_len;
+	/* determine printable or not */
+	for (i = 0, p = essid; i < maxlen; i++, p++) {
+		if (*p < ' ' || *p > 0x7e)
+			break;
+	}
+	if (i != maxlen) {		/* not printable, print as hex */
+		if (bufsize < 3)
+			return 0;
+		strlcpy(buf, "0x", bufsize);
+		bufsize -= 2;
+		p = essid;
+		for (i = 0; i < maxlen && bufsize >= 2; i++) {
+			sprintf(&buf[2+2*i], "%02x", p[i]);
+			bufsize -= 2;
+		}
+		if (i != essid_len)
+			memcpy(&buf[2+2*i-3], "...", 3);
+	} else {			/* printable, truncate as needed */
+		memcpy(buf, essid, maxlen);
+		if (maxlen != essid_len)
+			memcpy(&buf[maxlen-3], "...", 3);
+	}
+	return maxlen;
+}
+
+static void
+printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	char ssid[2*IEEE80211_NWID_LEN+1];
+
+	printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
+}
+
+static void
+printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	const char *sep;
+	int i;
+
+	printf("%s", tag);
+	sep = "<";
+	for (i = 2; i < ielen; i++) {
+		printf("%s%s%d", sep,
+		    ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
+		    ie[i] & IEEE80211_RATE_VAL);
+		sep = ",";
+	}
+	printf(">");
+}
+
+static void
+printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	const struct ieee80211_country_ie *cie =
+	   (const struct ieee80211_country_ie *) ie;
+	int i, nbands, schan, nchan;
+
+	printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
+	nbands = (cie->len - 3) / sizeof(cie->band[0]);
+	for (i = 0; i < nbands; i++) {
+		schan = cie->band[i].schan;
+		nchan = cie->band[i].nchan;
+		if (nchan != 1)
+			printf(" %u-%u,%u", schan, schan + nchan-1,
+			    cie->band[i].maxtxpwr);
+		else
+			printf(" %u,%u", schan, cie->band[i].maxtxpwr);
+	}
+	printf(">");
+}
+
+/* unaligned little endian access */     
+#define LE_READ_4(p)					\
+	((u_int32_t)					\
+	 ((((const u_int8_t *)(p))[0]      ) |		\
+	  (((const u_int8_t *)(p))[1] <<  8) |		\
+	  (((const u_int8_t *)(p))[2] << 16) |		\
+	  (((const u_int8_t *)(p))[3] << 24)))
+
+static __inline int
+iswpaoui(const u_int8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static __inline int
+iswmeinfo(const u_int8_t *frm)
+{
+	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+		frm[6] == WME_INFO_OUI_SUBTYPE;
+}
+
+static __inline int
+iswmeparam(const u_int8_t *frm)
+{
+	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+		frm[6] == WME_PARAM_OUI_SUBTYPE;
+}
+
+static __inline int
+isatherosoui(const u_int8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+}
+
+static __inline int
+istdmaoui(const uint8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
+}
+
+static __inline int
+iswpsoui(const uint8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static const char *
+iename(int elemid)
+{
+	switch (elemid) {
+	case IEEE80211_ELEMID_FHPARMS:	return " FHPARMS";
+	case IEEE80211_ELEMID_CFPARMS:	return " CFPARMS";
+	case IEEE80211_ELEMID_TIM:	return " TIM";
+	case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
+	case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
+	case IEEE80211_ELEMID_PWRCNSTR:	return " PWRCNSTR";
+	case IEEE80211_ELEMID_PWRCAP:	return " PWRCAP";
+	case IEEE80211_ELEMID_TPCREQ:	return " TPCREQ";
+	case IEEE80211_ELEMID_TPCREP:	return " TPCREP";
+	case IEEE80211_ELEMID_SUPPCHAN:	return " SUPPCHAN";
+	case IEEE80211_ELEMID_CSA:	return " CSA";
+	case IEEE80211_ELEMID_MEASREQ:	return " MEASREQ";
+	case IEEE80211_ELEMID_MEASREP:	return " MEASREP";
+	case IEEE80211_ELEMID_QUIET:	return " QUIET";
+	case IEEE80211_ELEMID_IBSSDFS:	return " IBSSDFS";
+	case IEEE80211_ELEMID_TPC:	return " TPC";
+	case IEEE80211_ELEMID_CCKM:	return " CCKM";
+	}
+	return " ???";
+}
+
+static void
+printies(const u_int8_t *vp, int ielen, int maxcols)
+{
+	while (ielen > 0) {
+		switch (vp[0]) {
+		case IEEE80211_ELEMID_SSID:
+			if (verbose)
+				printssid(" SSID", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_RATES:
+		case IEEE80211_ELEMID_XRATES:
+			if (verbose)
+				printrates(vp[0] == IEEE80211_ELEMID_RATES ?
+				    " RATES" : " XRATES", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_DSPARMS:
+			if (verbose)
+				printf(" DSPARMS<%u>", vp[2]);
+			break;
+		case IEEE80211_ELEMID_COUNTRY:
+			if (verbose)
+				printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_ERP:
+			if (verbose)
+				printf(" ERP<0x%x>", vp[2]);
+			break;
+		case IEEE80211_ELEMID_VENDOR:
+			if (iswpaoui(vp))
+				printwpaie(" WPA", vp, 2+vp[1], maxcols);
+			else if (iswmeinfo(vp))
+				printwmeinfo(" WME", vp, 2+vp[1], maxcols);
+			else if (iswmeparam(vp))
+				printwmeparam(" WME", vp, 2+vp[1], maxcols);
+			else if (isatherosoui(vp))
+				printathie(" ATH", vp, 2+vp[1], maxcols);
+			else if (iswpsoui(vp))
+				printwpsie(" WPS", vp, 2+vp[1], maxcols);
+			else if (istdmaoui(vp))
+				printtdmaie(" TDMA", vp, 2+vp[1], maxcols);
+			else if (verbose)
+				printie(" VEN", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_RSN:
+			printrsnie(" RSN", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_HTCAP:
+			printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_HTINFO:
+			if (verbose)
+				printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_MESHID:
+			if (verbose)
+				printssid(" MESHID", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_MESHCONF:
+			printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols);
+			break;
+		default:
+			if (verbose)
+				printie(iename(vp[0]), vp, 2+vp[1], maxcols);
+			break;
+		}
+		ielen -= 2+vp[1];
+		vp += 2+vp[1];
+	}
+}
+
+static void
+printmimo(const struct ieee80211_mimo_info *mi)
+{
+	/* NB: don't muddy display unless there's something to show */
+	if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) {
+		/* XXX ignore EVM for now */
+		printf(" (rssi %d:%d:%d nf %d:%d:%d)",
+		    mi->rssi[0], mi->rssi[1], mi->rssi[2],
+		    mi->noise[0], mi->noise[1], mi->noise[2]);
+	}
+}
+
+static void
+list_scan(int s)
+{
+	uint8_t buf[24*1024];
+	char ssid[IEEE80211_NWID_LEN+1];
+	const uint8_t *cp;
+	int len, ssidmax, idlen;
+
+	if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
+		errx(1, "unable to get scan results");
+	if (len < sizeof(struct ieee80211req_scan_result))
+		return;
+
+	getchaninfo(s);
+
+	ssidmax = verbose ? IEEE80211_NWID_LEN - 1 : 14;
+	printf("%-*.*s  %-17.17s  %4s %4s  %-7s  %3s %4s\n"
+		, ssidmax, ssidmax, "SSID/MESH ID"
+		, "BSSID"
+		, "CHAN"
+		, "RATE"
+		, " S:N"
+		, "INT"
+		, "CAPS"
+	);
+	cp = buf;
+	do {
+		const struct ieee80211req_scan_result *sr;
+		const uint8_t *vp, *idp;
+
+		sr = (const struct ieee80211req_scan_result *) cp;
+		vp = cp + sr->isr_ie_off;
+		if (sr->isr_meshid_len) {
+			idp = vp + sr->isr_ssid_len;
+			idlen = sr->isr_meshid_len;
+		} else {
+			idp = vp;
+			idlen = sr->isr_ssid_len;
+		}
+		printf("%-*.*s  %s  %3d  %3dM %3d:%-3d  %3d %-4.4s"
+			, ssidmax
+			  , copy_essid(ssid, ssidmax, idp, idlen)
+			  , ssid
+			, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
+			, ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
+			, getmaxrate(sr->isr_rates, sr->isr_nrates)
+			, (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
+			, sr->isr_intval
+			, getcaps(sr->isr_capinfo)
+		);
+		printies(vp + sr->isr_ssid_len + sr->isr_meshid_len,
+		    sr->isr_ie_len, 24);
+		printf("\n");
+		cp += sr->isr_len, len -= sr->isr_len;
+	} while (len >= sizeof(struct ieee80211req_scan_result));
+}
+
+static void
+scan_and_wait(int s)
+{
+	struct ieee80211_scan_req sr;
+	struct ieee80211req ireq;
+	int sroute;
+
+	sroute = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (sroute < 0) {
+		perror("socket(PF_ROUTE,SOCK_RAW)");
+		return;
+	}
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = IEEE80211_IOC_SCAN_REQ;
+
+	memset(&sr, 0, sizeof(sr));
+	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
+		    | IEEE80211_IOC_SCAN_NOPICK
+		    | IEEE80211_IOC_SCAN_ONCE;
+	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
+	sr.sr_nssid = 0;
+
+	ireq.i_data = &sr;
+	ireq.i_len = sizeof(sr);
+	/* NB: only root can trigger a scan so ignore errors */
+	if (ioctl(s, SIOCS80211, &ireq) >= 0) {
+		char buf[2048];
+		struct if_announcemsghdr *ifan;
+		struct rt_msghdr *rtm;
+
+		do {
+			if (read(sroute, buf, sizeof(buf)) < 0) {
+				perror("read(PF_ROUTE)");
+				break;
+			}
+			rtm = (struct rt_msghdr *) buf;
+			if (rtm->rtm_version != RTM_VERSION)
+				break;
+			ifan = (struct if_announcemsghdr *) rtm;
+		} while (rtm->rtm_type != RTM_IEEE80211 ||
+		    ifan->ifan_what != RTM_IEEE80211_SCAN);
+	}
+	close(sroute);
+}
+
+static
+DECL_CMD_FUNC(set80211scan, val, d)
+{
+	scan_and_wait(s);
+	list_scan(s);
+}
+
+static enum ieee80211_opmode get80211opmode(int s);
+
+static int
+gettxseq(const struct ieee80211req_sta_info *si)
+{
+	int i, txseq;
+
+	if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
+		return si->isi_txseqs[0];
+	/* XXX not right but usually what folks want */
+	txseq = 0;
+	for (i = 0; i < IEEE80211_TID_SIZE; i++)
+		if (si->isi_txseqs[i] > txseq)
+			txseq = si->isi_txseqs[i];
+	return txseq;
+}
+
+static int
+getrxseq(const struct ieee80211req_sta_info *si)
+{
+	int i, rxseq;
+
+	if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
+		return si->isi_rxseqs[0];
+	/* XXX not right but usually what folks want */
+	rxseq = 0;
+	for (i = 0; i < IEEE80211_TID_SIZE; i++)
+		if (si->isi_rxseqs[i] > rxseq)
+			rxseq = si->isi_rxseqs[i];
+	return rxseq;
+}
+
+static void
+list_stations(int s)
+{
+	union {
+		struct ieee80211req_sta_req req;
+		uint8_t buf[24*1024];
+	} u;
+	enum ieee80211_opmode opmode = get80211opmode(s);
+	const uint8_t *cp;
+	int len;
+
+	/* broadcast address =>'s get all stations */
+	(void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
+	if (opmode == IEEE80211_M_STA) {
+		/*
+		 * Get information about the associated AP.
+		 */
+		(void) get80211(s, IEEE80211_IOC_BSSID,
+		    u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
+	}
+	if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
+		errx(1, "unable to get station information");
+	if (len < sizeof(struct ieee80211req_sta_info))
+		return;
+
+	getchaninfo(s);
+
+	if (opmode == IEEE80211_M_MBSS)
+		printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
+			, "ADDR"
+			, "CHAN"
+			, "LOCAL"
+			, "PEER"
+			, "STATE"
+			, "RATE"
+			, "RSSI"
+			, "IDLE"
+			, "TXSEQ"
+			, "RXSEQ"
+		);
+	else 
+		printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
+			, "ADDR"
+			, "AID"
+			, "CHAN"
+			, "RATE"
+			, "RSSI"
+			, "IDLE"
+			, "TXSEQ"
+			, "RXSEQ"
+			, "CAPS"
+			, "FLAG"
+		);
+	cp = (const uint8_t *) u.req.info;
+	do {
+		const struct ieee80211req_sta_info *si;
+
+		si = (const struct ieee80211req_sta_info *) cp;
+		if (si->isi_len < sizeof(*si))
+			break;
+		if (opmode == IEEE80211_M_MBSS)
+			printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
+				, ether_ntoa((const struct ether_addr*)
+				    si->isi_macaddr)
+				, ieee80211_mhz2ieee(si->isi_freq,
+				    si->isi_flags)
+				, si->isi_localid
+				, si->isi_peerid
+				, mesh_linkstate_string(si->isi_peerstate)
+				, si->isi_txmbps/2
+				, si->isi_rssi/2.
+				, si->isi_inact
+				, gettxseq(si)
+				, getrxseq(si)
+			);
+		else 
+			printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
+				, ether_ntoa((const struct ether_addr*)
+				    si->isi_macaddr)
+				, IEEE80211_AID(si->isi_associd)
+				, ieee80211_mhz2ieee(si->isi_freq,
+				    si->isi_flags)
+				, si->isi_txmbps/2
+				, si->isi_rssi/2.
+				, si->isi_inact
+				, gettxseq(si)
+				, getrxseq(si)
+				, getcaps(si->isi_capinfo)
+				, getflags(si->isi_state)
+			);
+		printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
+		printmimo(&si->isi_mimo);
+		printf("\n");
+		cp += si->isi_len, len -= si->isi_len;
+	} while (len >= sizeof(struct ieee80211req_sta_info));
+}
+
+static const char *
+mesh_linkstate_string(uint8_t state)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	static const char *state_names[] = {
+	    [0] = "IDLE",
+	    [1] = "OPEN-TX",
+	    [2] = "OPEN-RX",
+	    [3] = "CONF-RX",
+	    [4] = "ESTAB",
+	    [5] = "HOLDING",
+	};
+
+	if (state >= N(state_names)) {
+		static char buf[10];
+		snprintf(buf, sizeof(buf), "#%u", state);
+		return buf;
+	} else
+		return state_names[state];
+#undef N
+}
+
+static const char *
+get_chaninfo(const struct ieee80211_channel *c, int precise,
+	char buf[], size_t bsize)
+{
+	buf[0] = '\0';
+	if (IEEE80211_IS_CHAN_FHSS(c))
+		strlcat(buf, " FHSS", bsize);
+	if (IEEE80211_IS_CHAN_A(c))
+		strlcat(buf, " 11a", bsize);
+	else if (IEEE80211_IS_CHAN_ANYG(c))
+		strlcat(buf, " 11g", bsize);
+	else if (IEEE80211_IS_CHAN_B(c))
+		strlcat(buf, " 11b", bsize);
+	if (IEEE80211_IS_CHAN_HALF(c))
+		strlcat(buf, "/10MHz", bsize);
+	if (IEEE80211_IS_CHAN_QUARTER(c))
+		strlcat(buf, "/5MHz", bsize);
+	if (IEEE80211_IS_CHAN_TURBO(c))
+		strlcat(buf, " Turbo", bsize);
+	if (precise) {
+		if (IEEE80211_IS_CHAN_HT20(c))
+			strlcat(buf, " ht/20", bsize);
+		else if (IEEE80211_IS_CHAN_HT40D(c))
+			strlcat(buf, " ht/40-", bsize);
+		else if (IEEE80211_IS_CHAN_HT40U(c))
+			strlcat(buf, " ht/40+", bsize);
+	} else {
+		if (IEEE80211_IS_CHAN_HT(c))
+			strlcat(buf, " ht", bsize);
+	}
+	return buf;
+}
+
+static void
+print_chaninfo(const struct ieee80211_channel *c, int verb)
+{
+	char buf[14];
+
+	printf("Channel %3u : %u%c MHz%-14.14s",
+		ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
+		IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
+		get_chaninfo(c, verb, buf, sizeof(buf)));
+}
+
+static int
+chanpref(const struct ieee80211_channel *c)
+{
+	if (IEEE80211_IS_CHAN_HT40(c))
+		return 40;
+	if (IEEE80211_IS_CHAN_HT20(c))
+		return 30;
+	if (IEEE80211_IS_CHAN_HALF(c))
+		return 10;
+	if (IEEE80211_IS_CHAN_QUARTER(c))
+		return 5;
+	if (IEEE80211_IS_CHAN_TURBO(c))
+		return 25;
+	if (IEEE80211_IS_CHAN_A(c))
+		return 20;
+	if (IEEE80211_IS_CHAN_G(c))
+		return 20;
+	if (IEEE80211_IS_CHAN_B(c))
+		return 15;
+	if (IEEE80211_IS_CHAN_PUREG(c))
+		return 15;
+	return 0;
+}
+
+static void
+print_channels(int s, const struct ieee80211req_chaninfo *chans,
+	int allchans, int verb)
+{
+	struct ieee80211req_chaninfo *achans;
+	uint8_t reported[IEEE80211_CHAN_BYTES];
+	const struct ieee80211_channel *c;
+	int i, half;
+
+	achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
+	if (achans == NULL)
+		errx(1, "no space for active channel list");
+	achans->ic_nchans = 0;
+	memset(reported, 0, sizeof(reported));
+	if (!allchans) {
+		struct ieee80211req_chanlist active;
+
+		if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
+			errx(1, "unable to get active channel list");
+		for (i = 0; i < chans->ic_nchans; i++) {
+			c = &chans->ic_chans[i];
+			if (!isset(active.ic_channels, c->ic_ieee))
+				continue;
+			/*
+			 * Suppress compatible duplicates unless
+			 * verbose.  The kernel gives us it's
+			 * complete channel list which has separate
+			 * entries for 11g/11b and 11a/turbo.
+			 */
+			if (isset(reported, c->ic_ieee) && !verb) {
+				/* XXX we assume duplicates are adjacent */
+				achans->ic_chans[achans->ic_nchans-1] = *c;
+			} else {
+				achans->ic_chans[achans->ic_nchans++] = *c;
+				setbit(reported, c->ic_ieee);
+			}
+		}
+	} else {
+		for (i = 0; i < chans->ic_nchans; i++) {
+			c = &chans->ic_chans[i];
+			/* suppress duplicates as above */
+			if (isset(reported, c->ic_ieee) && !verb) {
+				/* XXX we assume duplicates are adjacent */
+				struct ieee80211_channel *a =
+				    &achans->ic_chans[achans->ic_nchans-1];
+				if (chanpref(c) > chanpref(a))
+					*a = *c;
+			} else {
+				achans->ic_chans[achans->ic_nchans++] = *c;
+				setbit(reported, c->ic_ieee);
+			}
+		}
+	}
+	half = achans->ic_nchans / 2;
+	if (achans->ic_nchans % 2)
+		half++;
+
+	for (i = 0; i < achans->ic_nchans / 2; i++) {
+		print_chaninfo(&achans->ic_chans[i], verb);
+		print_chaninfo(&achans->ic_chans[half+i], verb);
+		printf("\n");
+	}
+	if (achans->ic_nchans % 2) {
+		print_chaninfo(&achans->ic_chans[i], verb);
+		printf("\n");
+	}
+	free(achans);
+}
+
+static void
+list_channels(int s, int allchans)
+{
+	getchaninfo(s);
+	print_channels(s, chaninfo, allchans, verbose);
+}
+
+static void
+print_txpow(const struct ieee80211_channel *c)
+{
+	printf("Channel %3u : %u MHz %3.1f reg %2d  ",
+	    c->ic_ieee, c->ic_freq,
+	    c->ic_maxpower/2., c->ic_maxregpower);
+}
+
+static void
+print_txpow_verbose(const struct ieee80211_channel *c)
+{
+	print_chaninfo(c, 1);
+	printf("min %4.1f dBm  max %3.1f dBm  reg %2d dBm",
+	    c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
+	/* indicate where regulatory cap limits power use */
+	if (c->ic_maxpower > 2*c->ic_maxregpower)
+		printf(" <");
+}
+
+static void
+list_txpow(int s)
+{
+	struct ieee80211req_chaninfo *achans;
+	uint8_t reported[IEEE80211_CHAN_BYTES];
+	struct ieee80211_channel *c, *prev;
+	int i, half;
+
+	getchaninfo(s);
+	achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
+	if (achans == NULL)
+		errx(1, "no space for active channel list");
+	achans->ic_nchans = 0;
+	memset(reported, 0, sizeof(reported));
+	for (i = 0; i < chaninfo->ic_nchans; i++) {
+		c = &chaninfo->ic_chans[i];
+		/* suppress duplicates as above */
+		if (isset(reported, c->ic_ieee) && !verbose) {
+			/* XXX we assume duplicates are adjacent */
+			prev = &achans->ic_chans[achans->ic_nchans-1];
+			/* display highest power on channel */
+			if (c->ic_maxpower > prev->ic_maxpower)
+				*prev = *c;
+		} else {
+			achans->ic_chans[achans->ic_nchans++] = *c;
+			setbit(reported, c->ic_ieee);
+		}
+	}
+	if (!verbose) {
+		half = achans->ic_nchans / 2;
+		if (achans->ic_nchans % 2)
+			half++;
+
+		for (i = 0; i < achans->ic_nchans / 2; i++) {
+			print_txpow(&achans->ic_chans[i]);
+			print_txpow(&achans->ic_chans[half+i]);
+			printf("\n");
+		}
+		if (achans->ic_nchans % 2) {
+			print_txpow(&achans->ic_chans[i]);
+			printf("\n");
+		}
+	} else {
+		for (i = 0; i < achans->ic_nchans; i++) {
+			print_txpow_verbose(&achans->ic_chans[i]);
+			printf("\n");
+		}
+	}
+	free(achans);
+}
+
+static void
+list_keys(int s)
+{
+}
+
+#define	IEEE80211_C_BITS \
+	"\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
+	"\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
+	"\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
+	"\37TXFRAG\40TDMA"
+
+static void
+list_capabilities(int s)
+{
+	struct ieee80211_devcaps_req *dc;
+
+	if (verbose)
+		dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
+	else
+		dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
+	if (dc == NULL)
+		errx(1, "no space for device capabilities");
+	dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
+	getdevcaps(s, dc);
+	printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
+	if (dc->dc_cryptocaps != 0 || verbose) {
+		putchar('\n');
+		printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
+	}
+	if (dc->dc_htcaps != 0 || verbose) {
+		putchar('\n');
+		printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
+	}
+	putchar('\n');
+	if (verbose) {
+		chaninfo = &dc->dc_chaninfo;	/* XXX */
+		print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose);
+	}
+	free(dc);
+}
+
+static int
+get80211wme(int s, int param, int ac, int *val)
+{
+	struct ieee80211req ireq;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = param;
+	ireq.i_len = ac;
+	if (ioctl(s, SIOCG80211, &ireq) < 0) {
+		warn("cannot get WME parameter %d, ac %d%s",
+		    param, ac & IEEE80211_WMEPARAM_VAL,
+		    ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
+		return -1;
+	}
+	*val = ireq.i_val;
+	return 0;
+}
+
+static void
+list_wme_aci(int s, const char *tag, int ac)
+{
+	int val;
+
+	printf("\t%s", tag);
+
+	/* show WME BSS parameters */
+	if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
+		printf(" cwmin %2u", val);
+	if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
+		printf(" cwmax %2u", val);
+	if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
+		printf(" aifs %2u", val);
+	if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
+		printf(" txopLimit %3u", val);
+	if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
+		if (val)
+			printf(" acm");
+		else if (verbose)
+			printf(" -acm");
+	}
+	/* !BSS only */
+	if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
+		if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
+			if (!val)
+				printf(" -ack");
+			else if (verbose)
+				printf(" ack");
+		}
+	}
+	printf("\n");
+}
+
+static void
+list_wme(int s)
+{
+	static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
+	int ac;
+
+	if (verbose) {
+		/* display both BSS and local settings */
+		for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
+	again:
+			if (ac & IEEE80211_WMEPARAM_BSS)
+				list_wme_aci(s, "     ", ac);
+			else
+				list_wme_aci(s, acnames[ac], ac);
+			if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
+				ac |= IEEE80211_WMEPARAM_BSS;
+				goto again;
+			} else
+				ac &= ~IEEE80211_WMEPARAM_BSS;
+		}
+	} else {
+		/* display only channel settings */
+		for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++)
+			list_wme_aci(s, acnames[ac], ac);
+	}
+}
+
+static void
+list_roam(int s)
+{
+	const struct ieee80211_roamparam *rp;
+	int mode;
+
+	getroam(s);
+	for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
+		rp = &roamparams.params[mode];
+		if (rp->rssi == 0 && rp->rate == 0)
+			continue;
+		if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
+			if (rp->rssi & 1)
+				LINE_CHECK("roam:%-7.7s rssi %2u.5dBm  MCS %2u    ",
+				    modename[mode], rp->rssi/2,
+				    rp->rate &~ IEEE80211_RATE_MCS);
+			else
+				LINE_CHECK("roam:%-7.7s rssi %4udBm  MCS %2u    ",
+				    modename[mode], rp->rssi/2,
+				    rp->rate &~ IEEE80211_RATE_MCS);
+		} else {
+			if (rp->rssi & 1)
+				LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s",
+				    modename[mode], rp->rssi/2, rp->rate/2);
+			else
+				LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s",
+				    modename[mode], rp->rssi/2, rp->rate/2);
+		}
+	}
+}
+
+static void
+list_txparams(int s)
+{
+	const struct ieee80211_txparam *tp;
+	int mode;
+
+	gettxparams(s);
+	for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
+		tp = &txparams.params[mode];
+		if (tp->mgmtrate == 0 && tp->mcastrate == 0)
+			continue;
+		if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) {
+			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
+				LINE_CHECK("%-7.7s ucast NONE    mgmt %2u MCS  "
+				    "mcast %2u MCS  maxretry %u",
+				    modename[mode],
+				    tp->mgmtrate &~ IEEE80211_RATE_MCS,
+				    tp->mcastrate &~ IEEE80211_RATE_MCS,
+				    tp->maxretry);
+			else
+				LINE_CHECK("%-7.7s ucast %2u MCS  mgmt %2u MCS  "
+				    "mcast %2u MCS  maxretry %u",
+				    modename[mode],
+				    tp->ucastrate &~ IEEE80211_RATE_MCS,
+				    tp->mgmtrate &~ IEEE80211_RATE_MCS,
+				    tp->mcastrate &~ IEEE80211_RATE_MCS,
+				    tp->maxretry);
+		} else {
+			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
+				LINE_CHECK("%-7.7s ucast NONE    mgmt %2u Mb/s "
+				    "mcast %2u Mb/s maxretry %u",
+				    modename[mode],
+				    tp->mgmtrate/2,
+				    tp->mcastrate/2, tp->maxretry);
+			else
+				LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s "
+				    "mcast %2u Mb/s maxretry %u",
+				    modename[mode],
+				    tp->ucastrate/2, tp->mgmtrate/2,
+				    tp->mcastrate/2, tp->maxretry);
+		}
+	}
+}
+
+static void
+printpolicy(int policy)
+{
+	switch (policy) {
+	case IEEE80211_MACCMD_POLICY_OPEN:
+		printf("policy: open\n");
+		break;
+	case IEEE80211_MACCMD_POLICY_ALLOW:
+		printf("policy: allow\n");
+		break;
+	case IEEE80211_MACCMD_POLICY_DENY:
+		printf("policy: deny\n");
+		break;
+	case IEEE80211_MACCMD_POLICY_RADIUS:
+		printf("policy: radius\n");
+		break;
+	default:
+		printf("policy: unknown (%u)\n", policy);
+		break;
+	}
+}
+
+static void
+list_mac(int s)
+{
+	struct ieee80211req ireq;
+	struct ieee80211req_maclist *acllist;
+	int i, nacls, policy, len;
+	uint8_t *data;
+	char c;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
+	ireq.i_type = IEEE80211_IOC_MACCMD;
+	ireq.i_val = IEEE80211_MACCMD_POLICY;
+	if (ioctl(s, SIOCG80211, &ireq) < 0) {
+		if (errno == EINVAL) {
+			printf("No acl policy loaded\n");
+			return;
+		}
+		err(1, "unable to get mac policy");
+	}
+	policy = ireq.i_val;
+	if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
+		c = '*';
+	} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
+		c = '+';
+	} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
+		c = '-';
+	} else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) {
+		c = 'r';		/* NB: should never have entries */
+	} else {
+		printf("policy: unknown (%u)\n", policy);
+		c = '?';
+	}
+	if (verbose || c == '?')
+		printpolicy(policy);
+
+	ireq.i_val = IEEE80211_MACCMD_LIST;
+	ireq.i_len = 0;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		err(1, "unable to get mac acl list size");
+	if (ireq.i_len == 0) {		/* NB: no acls */
+		if (!(verbose || c == '?'))
+			printpolicy(policy);
+		return;
+	}
+	len = ireq.i_len;
+
+	data = malloc(len);
+	if (data == NULL)
+		err(1, "out of memory for acl list");
+
+	ireq.i_data = data;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		err(1, "unable to get mac acl list");
+	nacls = len / sizeof(*acllist);
+	acllist = (struct ieee80211req_maclist *) data;
+	for (i = 0; i < nacls; i++)
+		printf("%c%s\n", c, ether_ntoa(
+			(const struct ether_addr *) acllist[i].ml_macaddr));
+	free(data);
+}
+
+static void
+print_regdomain(const struct ieee80211_regdomain *reg, int verb)
+{
+	if ((reg->regdomain != 0 &&
+	    reg->regdomain != reg->country) || verb) {
+		const struct regdomain *rd =
+		    lib80211_regdomain_findbysku(getregdata(), reg->regdomain);
+		if (rd == NULL)
+			LINE_CHECK("regdomain %d", reg->regdomain);
+		else
+			LINE_CHECK("regdomain %s", rd->name);
+	}
+	if (reg->country != 0 || verb) {
+		const struct country *cc =
+		    lib80211_country_findbycc(getregdata(), reg->country);
+		if (cc == NULL)
+			LINE_CHECK("country %d", reg->country);
+		else
+			LINE_CHECK("country %s", cc->isoname);
+	}
+	if (reg->location == 'I')
+		LINE_CHECK("indoor");
+	else if (reg->location == 'O')
+		LINE_CHECK("outdoor");
+	else if (verb)
+		LINE_CHECK("anywhere");
+	if (reg->ecm)
+		LINE_CHECK("ecm");
+	else if (verb)
+		LINE_CHECK("-ecm");
+}
+
+static void
+list_regdomain(int s, int channelsalso)
+{
+	getregdomain(s);
+	if (channelsalso) {
+		getchaninfo(s);
+		spacer = ':';
+		print_regdomain(&regdomain, 1);
+		LINE_BREAK();
+		print_channels(s, chaninfo, 1/*allchans*/, 1/*verbose*/);
+	} else
+		print_regdomain(&regdomain, verbose);
+}
+
+static void
+list_mesh(int s)
+{
+	struct ieee80211req ireq;
+	struct ieee80211req_mesh_route routes[128];
+	struct ieee80211req_mesh_route *rt;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = IEEE80211_IOC_MESH_RTCMD;
+	ireq.i_val = IEEE80211_MESH_RTCMD_LIST;
+	ireq.i_data = &routes;
+	ireq.i_len = sizeof(routes);
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+	 	err(1, "unable to get the Mesh routing table");
+
+	printf("%-17.17s %-17.17s %4s %4s %4s %6s %s\n"
+		, "DEST"
+		, "NEXT HOP"
+		, "HOPS"
+		, "METRIC"
+		, "LIFETIME"
+		, "MSEQ"
+		, "FLAGS");
+
+	for (rt = &routes[0]; rt - &routes[0] < ireq.i_len / sizeof(*rt); rt++){
+		printf("%s ",
+		    ether_ntoa((const struct ether_addr *)rt->imr_dest));
+		printf("%s %4u   %4u   %6u %6u    %c%c\n",
+			ether_ntoa((const struct ether_addr *)rt->imr_nexthop),
+			rt->imr_nhops, rt->imr_metric, rt->imr_lifetime,
+			rt->imr_lastmseq,
+			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ?
+			    'V' : '!',
+			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ?
+			    'P' : ' ');
+	}
+}
+
+static
+DECL_CMD_FUNC(set80211list, arg, d)
+{
+#define	iseq(a,b)	(strncasecmp(a,b,sizeof(b)-1) == 0)
+
+	LINE_INIT('\t');
+
+	if (iseq(arg, "sta"))
+		list_stations(s);
+	else if (iseq(arg, "scan") || iseq(arg, "ap"))
+		list_scan(s);
+	else if (iseq(arg, "chan") || iseq(arg, "freq"))
+		list_channels(s, 1);
+	else if (iseq(arg, "active"))
+		list_channels(s, 0);
+	else if (iseq(arg, "keys"))
+		list_keys(s);
+	else if (iseq(arg, "caps"))
+		list_capabilities(s);
+	else if (iseq(arg, "wme") || iseq(arg, "wmm"))
+		list_wme(s);
+	else if (iseq(arg, "mac"))
+		list_mac(s);
+	else if (iseq(arg, "txpow"))
+		list_txpow(s);
+	else if (iseq(arg, "roam"))
+		list_roam(s);
+	else if (iseq(arg, "txparam") || iseq(arg, "txparm"))
+		list_txparams(s);
+	else if (iseq(arg, "regdomain"))
+		list_regdomain(s, 1);
+	else if (iseq(arg, "countries"))
+		list_countries();
+	else if (iseq(arg, "mesh"))
+		list_mesh(s);
+	else
+		errx(1, "Don't know how to list %s for %s", arg, name);
+	LINE_BREAK();
+#undef iseq
+}
+
+static enum ieee80211_opmode
+get80211opmode(int s)
+{
+	struct ifmediareq ifmr;
+
+	(void) memset(&ifmr, 0, sizeof(ifmr));
+	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
+			if (ifmr.ifm_current & IFM_FLAG0)
+				return IEEE80211_M_AHDEMO;
+			else
+				return IEEE80211_M_IBSS;
+		}
+		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+			return IEEE80211_M_HOSTAP;
+		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+			return IEEE80211_M_MONITOR;
+		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
+			return IEEE80211_M_MBSS;
+	}
+	return IEEE80211_M_STA;
+}
+
+#if 0
+static void
+printcipher(int s, struct ieee80211req *ireq, int keylenop)
+{
+	switch (ireq->i_val) {
+	case IEEE80211_CIPHER_WEP:
+		ireq->i_type = keylenop;
+		if (ioctl(s, SIOCG80211, ireq) != -1)
+			printf("WEP-%s", 
+			    ireq->i_len <= 5 ? "40" :
+			    ireq->i_len <= 13 ? "104" : "128");
+		else
+			printf("WEP");
+		break;
+	case IEEE80211_CIPHER_TKIP:
+		printf("TKIP");
+		break;
+	case IEEE80211_CIPHER_AES_OCB:
+		printf("AES-OCB");
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		printf("AES-CCM");
+		break;
+	case IEEE80211_CIPHER_CKIP:
+		printf("CKIP");
+		break;
+	case IEEE80211_CIPHER_NONE:
+		printf("NONE");
+		break;
+	default:
+		printf("UNKNOWN (0x%x)", ireq->i_val);
+		break;
+	}
+}
+#endif
+
+static void
+printkey(const struct ieee80211req_key *ik)
+{
+	static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
+	int keylen = ik->ik_keylen;
+	int printcontents;
+
+	printcontents = printkeys &&
+		(memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
+	if (printcontents)
+		LINE_BREAK();
+	switch (ik->ik_type) {
+	case IEEE80211_CIPHER_WEP:
+		/* compatibility */
+		LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
+		    keylen <= 5 ? "40-bit" :
+		    keylen <= 13 ? "104-bit" : "128-bit");
+		break;
+	case IEEE80211_CIPHER_TKIP:
+		if (keylen > 128/8)
+			keylen -= 128/8;	/* ignore MIC for now */
+		LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+		break;
+	case IEEE80211_CIPHER_AES_OCB:
+		LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+		break;
+	case IEEE80211_CIPHER_CKIP:
+		LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+		break;
+	case IEEE80211_CIPHER_NONE:
+		LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+		break;
+	default:
+		LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
+			ik->ik_type, ik->ik_keyix+1, 8*keylen);
+		break;
+	}
+	if (printcontents) {
+		int i;
+
+		printf(" <");
+		for (i = 0; i < keylen; i++)
+			printf("%02x", ik->ik_keydata[i]);
+		printf(">");
+		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+		    (ik->ik_keyrsc != 0 || verbose))
+			printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
+		if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+		    (ik->ik_keytsc != 0 || verbose))
+			printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
+		if (ik->ik_flags != 0 && verbose) {
+			const char *sep = " ";
+
+			if (ik->ik_flags & IEEE80211_KEY_XMIT)
+				printf("%stx", sep), sep = "+";
+			if (ik->ik_flags & IEEE80211_KEY_RECV)
+				printf("%srx", sep), sep = "+";
+			if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
+				printf("%sdef", sep), sep = "+";
+		}
+		LINE_BREAK();
+	}
+}
+
+static void
+printrate(const char *tag, int v, int defrate, int defmcs)
+{
+	if ((v & IEEE80211_RATE_MCS) == 0) {
+		if (v != defrate) {
+			if (v & 1)
+				LINE_CHECK("%s %d.5", tag, v/2);
+			else
+				LINE_CHECK("%s %d", tag, v/2);
+		}
+	} else {
+		if (v != defmcs)
+			LINE_CHECK("%s %d", tag, v &~ 0x80);
+	}
+}
+
+static int
+getid(int s, int ix, void *data, size_t len, int *plen, int mesh)
+{
+	struct ieee80211req ireq;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID;
+	ireq.i_val = ix;
+	ireq.i_data = data;
+	ireq.i_len = len;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		return -1;
+	*plen = ireq.i_len;
+	return 0;
+}
+
+static void
+ieee80211_status(int s)
+{
+	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+	enum ieee80211_opmode opmode = get80211opmode(s);
+	int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode;
+	uint8_t data[32];
+	const struct ieee80211_channel *c;
+	const struct ieee80211_roamparam *rp;
+	const struct ieee80211_txparam *tp;
+
+	if (getid(s, -1, data, sizeof(data), &len, 0) < 0) {
+		/* If we can't get the SSID, this isn't an 802.11 device. */
+		return;
+	}
+
+	/*
+	 * Invalidate cached state so printing status for multiple
+	 * if's doesn't reuse the first interfaces' cached state.
+	 */
+	gotcurchan = 0;
+	gotroam = 0;
+	gottxparams = 0;
+	gothtconf = 0;
+	gotregdomain = 0;
+
+	printf("\t");
+	if (opmode == IEEE80211_M_MBSS) {
+		printf("meshid ");
+		getid(s, 0, data, sizeof(data), &len, 1);
+		print_string(data, len);
+	} else {
+		if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0)
+			num = 0;
+		printf("ssid ");
+		if (num > 1) {
+			for (i = 0; i < num; i++) {
+				if (getid(s, i, data, sizeof(data), &len, 0) >= 0 && len > 0) {
+					printf(" %d:", i + 1);
+					print_string(data, len);
+				}
+			}
+		} else
+			print_string(data, len);
+	}
+	c = getcurchan(s);
+	if (c->ic_freq != IEEE80211_CHAN_ANY) {
+		char buf[14];
+		printf(" channel %d (%u MHz%s)", c->ic_ieee, c->ic_freq,
+			get_chaninfo(c, 1, buf, sizeof(buf)));
+	} else if (verbose)
+		printf(" channel UNDEF");
+
+	if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 &&
+	    (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
+		printf(" bssid %s", ether_ntoa((struct ether_addr *)data));
+
+	if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) {
+		printf("\n\tstationname ");
+		print_string(data, len);
+	}
+
+	spacer = ' ';		/* force first break */
+	LINE_BREAK();
+
+	list_regdomain(s, 0);
+
+	wpa = 0;
+	if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) {
+		switch (val) {
+		case IEEE80211_AUTH_NONE:
+			LINE_CHECK("authmode NONE");
+			break;
+		case IEEE80211_AUTH_OPEN:
+			LINE_CHECK("authmode OPEN");
+			break;
+		case IEEE80211_AUTH_SHARED:
+			LINE_CHECK("authmode SHARED");
+			break;
+		case IEEE80211_AUTH_8021X:
+			LINE_CHECK("authmode 802.1x");
+			break;
+		case IEEE80211_AUTH_WPA:
+			if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0)
+				wpa = 1;	/* default to WPA1 */
+			switch (wpa) {
+			case 2:
+				LINE_CHECK("authmode WPA2/802.11i");
+				break;
+			case 3:
+				LINE_CHECK("authmode WPA1+WPA2/802.11i");
+				break;
+			default:
+				LINE_CHECK("authmode WPA");
+				break;
+			}
+			break;
+		case IEEE80211_AUTH_AUTO:
+			LINE_CHECK("authmode AUTO");
+			break;
+		default:
+			LINE_CHECK("authmode UNKNOWN (0x%x)", val);
+			break;
+		}
+	}
+
+	if (wpa || verbose) {
+		if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) {
+			if (val)
+				LINE_CHECK("wps");
+			else if (verbose)
+				LINE_CHECK("-wps");
+		}
+		if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) {
+			if (val)
+				LINE_CHECK("tsn");
+			else if (verbose)
+				LINE_CHECK("-tsn");
+		}
+		if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) {
+			if (val)
+				LINE_CHECK("countermeasures");
+			else if (verbose)
+				LINE_CHECK("-countermeasures");
+		}
+#if 0
+		/* XXX not interesting with WPA done in user space */
+		ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
+		if (ioctl(s, SIOCG80211, &ireq) != -1) {
+		}
+
+		ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
+		if (ioctl(s, SIOCG80211, &ireq) != -1) {
+			LINE_CHECK("mcastcipher ");
+			printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
+			spacer = ' ';
+		}
+
+		ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
+		if (ioctl(s, SIOCG80211, &ireq) != -1) {
+			LINE_CHECK("ucastcipher ");
+			printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
+		}
+
+		if (wpa & 2) {
+			ireq.i_type = IEEE80211_IOC_RSNCAPS;
+			if (ioctl(s, SIOCG80211, &ireq) != -1) {
+				LINE_CHECK("RSN caps 0x%x", ireq.i_val);
+				spacer = ' ';
+			}
+		}
+
+		ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
+		if (ioctl(s, SIOCG80211, &ireq) != -1) {
+		}
+#endif
+	}
+
+	if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 &&
+	    wepmode != IEEE80211_WEP_NOSUP) {
+		int firstkey;
+
+		switch (wepmode) {
+		case IEEE80211_WEP_OFF:
+			LINE_CHECK("privacy OFF");
+			break;
+		case IEEE80211_WEP_ON:
+			LINE_CHECK("privacy ON");
+			break;
+		case IEEE80211_WEP_MIXED:
+			LINE_CHECK("privacy MIXED");
+			break;
+		default:
+			LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
+			break;
+		}
+
+		/*
+		 * If we get here then we've got WEP support so we need
+		 * to print WEP status.
+		 */
+
+		if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) {
+			warn("WEP support, but no tx key!");
+			goto end;
+		}
+		if (val != -1)
+			LINE_CHECK("deftxkey %d", val+1);
+		else if (wepmode != IEEE80211_WEP_OFF || verbose)
+			LINE_CHECK("deftxkey UNDEF");
+
+		if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) {
+			warn("WEP support, but no NUMWEPKEYS support!");
+			goto end;
+		}
+
+		firstkey = 1;
+		for (i = 0; i < num; i++) {
+			struct ieee80211req_key ik;
+
+			memset(&ik, 0, sizeof(ik));
+			ik.ik_keyix = i;
+			if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) {
+				warn("WEP support, but can get keys!");
+				goto end;
+			}
+			if (ik.ik_keylen != 0) {
+				if (verbose)
+					LINE_BREAK();
+				printkey(&ik);
+				firstkey = 0;
+			}
+		}
+end:
+		;
+	}
+
+	if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 &&
+	    val != IEEE80211_POWERSAVE_NOSUP ) {
+		if (val != IEEE80211_POWERSAVE_OFF || verbose) {
+			switch (val) {
+			case IEEE80211_POWERSAVE_OFF:
+				LINE_CHECK("powersavemode OFF");
+				break;
+			case IEEE80211_POWERSAVE_CAM:
+				LINE_CHECK("powersavemode CAM");
+				break;
+			case IEEE80211_POWERSAVE_PSP:
+				LINE_CHECK("powersavemode PSP");
+				break;
+			case IEEE80211_POWERSAVE_PSP_CAM:
+				LINE_CHECK("powersavemode PSP-CAM");
+				break;
+			}
+			if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1)
+				LINE_CHECK("powersavesleep %d", val);
+		}
+	}
+
+	if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) {
+		if (val & 1)
+			LINE_CHECK("txpower %d.5", val/2);
+		else
+			LINE_CHECK("txpower %d", val/2);
+	}
+	if (verbose) {
+		if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1)
+			LINE_CHECK("txpowmax %.1f", val/2.);
+	}
+
+	if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) {
+		if (val)
+			LINE_CHECK("dotd");
+		else if (verbose)
+			LINE_CHECK("-dotd");
+	}
+
+	if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) {
+		if (val != IEEE80211_RTS_MAX || verbose)
+			LINE_CHECK("rtsthreshold %d", val);
+	}
+
+	if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) {
+		if (val != IEEE80211_FRAG_MAX || verbose)
+			LINE_CHECK("fragthreshold %d", val);
+	}
+	if (opmode == IEEE80211_M_STA || verbose) {
+		if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) {
+			if (val != IEEE80211_HWBMISS_MAX || verbose)
+				LINE_CHECK("bmiss %d", val);
+		}
+	}
+
+	if (!verbose) {
+		gettxparams(s);
+		tp = &txparams.params[chan2mode(c)];
+		printrate("ucastrate", tp->ucastrate,
+		    IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE);
+		printrate("mcastrate", tp->mcastrate, 2*1,
+		    IEEE80211_RATE_MCS|0);
+		printrate("mgmtrate", tp->mgmtrate, 2*1,
+		    IEEE80211_RATE_MCS|0);
+		if (tp->maxretry != 6)		/* XXX */
+			LINE_CHECK("maxretry %d", tp->maxretry);
+	} else {
+		LINE_BREAK();
+		list_txparams(s);
+	}
+
+	bgscaninterval = -1;
+	(void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval);
+
+	if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) {
+		if (val != bgscaninterval || verbose)
+			LINE_CHECK("scanvalid %u", val);
+	}
+
+	bgscan = 0;
+	if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) {
+		if (bgscan)
+			LINE_CHECK("bgscan");
+		else if (verbose)
+			LINE_CHECK("-bgscan");
+	}
+	if (bgscan || verbose) {
+		if (bgscaninterval != -1)
+			LINE_CHECK("bgscanintvl %u", bgscaninterval);
+		if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1)
+			LINE_CHECK("bgscanidle %u", val);
+		if (!verbose) {
+			getroam(s);
+			rp = &roamparams.params[chan2mode(c)];
+			if (rp->rssi & 1)
+				LINE_CHECK("roam:rssi %u.5", rp->rssi/2);
+			else
+				LINE_CHECK("roam:rssi %u", rp->rssi/2);
+			LINE_CHECK("roam:rate %u", rp->rate/2);
+		} else {
+			LINE_BREAK();
+			list_roam(s);
+			LINE_BREAK();
+		}
+	}
+
+	if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
+		if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) {
+			if (val)
+				LINE_CHECK("pureg");
+			else if (verbose)
+				LINE_CHECK("-pureg");
+		}
+		if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) {
+			switch (val) {
+			case IEEE80211_PROTMODE_OFF:
+				LINE_CHECK("protmode OFF");
+				break;
+			case IEEE80211_PROTMODE_CTS:
+				LINE_CHECK("protmode CTS");
+				break;
+			case IEEE80211_PROTMODE_RTSCTS:
+				LINE_CHECK("protmode RTSCTS");
+				break;
+			default:
+				LINE_CHECK("protmode UNKNOWN (0x%x)", val);
+				break;
+			}
+		}
+	}
+
+	if (IEEE80211_IS_CHAN_HT(c) || verbose) {
+		gethtconf(s);
+		switch (htconf & 3) {
+		case 0:
+		case 2:
+			LINE_CHECK("-ht");
+			break;
+		case 1:
+			LINE_CHECK("ht20");
+			break;
+		case 3:
+			if (verbose)
+				LINE_CHECK("ht");
+			break;
+		}
+		if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-htcompat");
+			else if (verbose)
+				LINE_CHECK("htcompat");
+		}
+		if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) {
+			switch (val) {
+			case 0:
+				LINE_CHECK("-ampdu");
+				break;
+			case 1:
+				LINE_CHECK("ampdutx -ampdurx");
+				break;
+			case 2:
+				LINE_CHECK("-ampdutx ampdurx");
+				break;
+			case 3:
+				if (verbose)
+					LINE_CHECK("ampdu");
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) {
+			switch (val) {
+			case IEEE80211_HTCAP_MAXRXAMPDU_8K:
+				LINE_CHECK("ampdulimit 8k");
+				break;
+			case IEEE80211_HTCAP_MAXRXAMPDU_16K:
+				LINE_CHECK("ampdulimit 16k");
+				break;
+			case IEEE80211_HTCAP_MAXRXAMPDU_32K:
+				LINE_CHECK("ampdulimit 32k");
+				break;
+			case IEEE80211_HTCAP_MAXRXAMPDU_64K:
+				LINE_CHECK("ampdulimit 64k");
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) {
+			switch (val) {
+			case IEEE80211_HTCAP_MPDUDENSITY_NA:
+				if (verbose)
+					LINE_CHECK("ampdudensity NA");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_025:
+				LINE_CHECK("ampdudensity .25");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_05:
+				LINE_CHECK("ampdudensity .5");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_1:
+				LINE_CHECK("ampdudensity 1");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_2:
+				LINE_CHECK("ampdudensity 2");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_4:
+				LINE_CHECK("ampdudensity 4");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_8:
+				LINE_CHECK("ampdudensity 8");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_16:
+				LINE_CHECK("ampdudensity 16");
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) {
+			switch (val) {
+			case 0:
+				LINE_CHECK("-amsdu");
+				break;
+			case 1:
+				LINE_CHECK("amsdutx -amsdurx");
+				break;
+			case 2:
+				LINE_CHECK("-amsdutx amsdurx");
+				break;
+			case 3:
+				if (verbose)
+					LINE_CHECK("amsdu");
+				break;
+			}
+		}
+		/* XXX amsdu limit */
+		if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) {
+			if (val)
+				LINE_CHECK("shortgi");
+			else if (verbose)
+				LINE_CHECK("-shortgi");
+		}
+		if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) {
+			if (val == IEEE80211_PROTMODE_OFF)
+				LINE_CHECK("htprotmode OFF");
+			else if (val != IEEE80211_PROTMODE_RTSCTS)
+				LINE_CHECK("htprotmode UNKNOWN (0x%x)", val);
+			else if (verbose)
+				LINE_CHECK("htprotmode RTSCTS");
+		}
+		if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) {
+			if (val)
+				LINE_CHECK("puren");
+			else if (verbose)
+				LINE_CHECK("-puren");
+		}
+		if (get80211val(s, IEEE80211_IOC_SMPS, &val) != -1) {
+			if (val == IEEE80211_HTCAP_SMPS_DYNAMIC)
+				LINE_CHECK("smpsdyn");
+			else if (val == IEEE80211_HTCAP_SMPS_ENA)
+				LINE_CHECK("smps");
+			else if (verbose)
+				LINE_CHECK("-smps");
+		}
+		if (get80211val(s, IEEE80211_IOC_RIFS, &val) != -1) {
+			if (val)
+				LINE_CHECK("rifs");
+			else if (verbose)
+				LINE_CHECK("-rifs");
+		}
+	}
+
+	if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) {
+		if (wme)
+			LINE_CHECK("wme");
+		else if (verbose)
+			LINE_CHECK("-wme");
+	} else
+		wme = 0;
+
+	if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) {
+		if (val)
+			LINE_CHECK("burst");
+		else if (verbose)
+			LINE_CHECK("-burst");
+	}
+
+	if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) {
+		if (val)
+			LINE_CHECK("ff");
+		else if (verbose)
+			LINE_CHECK("-ff");
+	}
+	if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) {
+		if (val)
+			LINE_CHECK("dturbo");
+		else if (verbose)
+			LINE_CHECK("-dturbo");
+	}
+	if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) {
+		if (val)
+			LINE_CHECK("dwds");
+		else if (verbose)
+			LINE_CHECK("-dwds");
+	}
+
+	if (opmode == IEEE80211_M_HOSTAP) {
+		if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) {
+			if (val)
+				LINE_CHECK("hidessid");
+			else if (verbose)
+				LINE_CHECK("-hidessid");
+		}
+		if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-apbridge");
+			else if (verbose)
+				LINE_CHECK("apbridge");
+		}
+		if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1)
+			LINE_CHECK("dtimperiod %u", val);
+
+		if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-doth");
+			else if (verbose)
+				LINE_CHECK("doth");
+		}
+		if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-dfs");
+			else if (verbose)
+				LINE_CHECK("dfs");
+		}
+		if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-inact");
+			else if (verbose)
+				LINE_CHECK("inact");
+		}
+	} else {
+		if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) {
+			if (val != IEEE80211_ROAMING_AUTO || verbose) {
+				switch (val) {
+				case IEEE80211_ROAMING_DEVICE:
+					LINE_CHECK("roaming DEVICE");
+					break;
+				case IEEE80211_ROAMING_AUTO:
+					LINE_CHECK("roaming AUTO");
+					break;
+				case IEEE80211_ROAMING_MANUAL:
+					LINE_CHECK("roaming MANUAL");
+					break;
+				default:
+					LINE_CHECK("roaming UNKNOWN (0x%x)",
+						val);
+					break;
+				}
+			}
+		}
+	}
+
+	if (opmode == IEEE80211_M_AHDEMO) {
+		if (get80211val(s, IEEE80211_IOC_TDMA_SLOT, &val) != -1)
+			LINE_CHECK("tdmaslot %u", val);
+		if (get80211val(s, IEEE80211_IOC_TDMA_SLOTCNT, &val) != -1)
+			LINE_CHECK("tdmaslotcnt %u", val);
+		if (get80211val(s, IEEE80211_IOC_TDMA_SLOTLEN, &val) != -1)
+			LINE_CHECK("tdmaslotlen %u", val);
+		if (get80211val(s, IEEE80211_IOC_TDMA_BINTERVAL, &val) != -1)
+			LINE_CHECK("tdmabintval %u", val);
+	} else if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
+		/* XXX default define not visible */
+		if (val != 100 || verbose)
+			LINE_CHECK("bintval %u", val);
+	}
+
+	if (wme && verbose) {
+		LINE_BREAK();
+		list_wme(s);
+	}
+
+	if (opmode == IEEE80211_M_MBSS) {
+		if (get80211val(s, IEEE80211_IOC_MESH_TTL, &val) != -1) {
+			LINE_CHECK("meshttl %u", val);
+		}
+		if (get80211val(s, IEEE80211_IOC_MESH_AP, &val) != -1) {
+			if (val)
+				LINE_CHECK("meshpeering");
+			else
+				LINE_CHECK("-meshpeering");
+		}
+		if (get80211val(s, IEEE80211_IOC_MESH_FWRD, &val) != -1) {
+			if (val)
+				LINE_CHECK("meshforward");
+			else
+				LINE_CHECK("-meshforward");
+		}
+		if (get80211len(s, IEEE80211_IOC_MESH_PR_METRIC, data, 12,
+		    &len) != -1) {
+			data[len] = '\0';
+			LINE_CHECK("meshmetric %s", data);
+		}
+		if (get80211len(s, IEEE80211_IOC_MESH_PR_PATH, data, 12,
+		    &len) != -1) {
+			data[len] = '\0';
+			LINE_CHECK("meshpath %s", data);
+		}
+		if (get80211val(s, IEEE80211_IOC_HWMP_ROOTMODE, &val) != -1) {
+			switch (val) {
+			case IEEE80211_HWMP_ROOTMODE_DISABLED:
+				LINE_CHECK("hwmprootmode DISABLED");
+				break;
+			case IEEE80211_HWMP_ROOTMODE_NORMAL:
+				LINE_CHECK("hwmprootmode NORMAL");
+				break;
+			case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
+				LINE_CHECK("hwmprootmode PROACTIVE");
+				break;
+			case IEEE80211_HWMP_ROOTMODE_RANN:
+				LINE_CHECK("hwmprootmode RANN");
+				break;
+			default:
+				LINE_CHECK("hwmprootmode UNKNOWN(%d)", val);
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_HWMP_MAXHOPS, &val) != -1) {
+			LINE_CHECK("hwmpmaxhops %u", val);
+		}
+	}
+
+	LINE_BREAK();
+}
+
+static int
+get80211(int s, int type, void *data, int len)
+{
+	struct ieee80211req ireq;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	ireq.i_data = data;
+	ireq.i_len = len;
+	return ioctl(s, SIOCG80211, &ireq);
+}
+
+static int
+get80211len(int s, int type, void *data, int len, int *plen)
+{
+	struct ieee80211req ireq;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	ireq.i_len = len;
+	assert(ireq.i_len == len);	/* NB: check for 16-bit truncation */
+	ireq.i_data = data;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		return -1;
+	*plen = ireq.i_len;
+	return 0;
+}
+
+static int
+get80211val(int s, int type, int *val)
+{
+	struct ieee80211req ireq;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		return -1;
+	*val = ireq.i_val;
+	return 0;
+}
+
+static void
+set80211(int s, int type, int val, int len, void *data)
+{
+	struct ieee80211req	ireq;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	ireq.i_val = val;
+	ireq.i_len = len;
+	assert(ireq.i_len == len);	/* NB: check for 16-bit truncation */
+	ireq.i_data = data;
+	if (ioctl(s, SIOCS80211, &ireq) < 0)
+		err(1, "SIOCS80211");
+}
+
+static const char *
+get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
+{
+	int len;
+	int hexstr;
+	u_int8_t *p;
+
+	len = *lenp;
+	p = buf;
+	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
+	if (hexstr)
+		val += 2;
+	for (;;) {
+		if (*val == '\0')
+			break;
+		if (sep != NULL && strchr(sep, *val) != NULL) {
+			val++;
+			break;
+		}
+		if (hexstr) {
+			if (!isxdigit((u_char)val[0])) {
+				warnx("bad hexadecimal digits");
+				return NULL;
+			}
+			if (!isxdigit((u_char)val[1])) {
+				warnx("odd count hexadecimal digits");
+				return NULL;
+			}
+		}
+		if (p >= buf + len) {
+			if (hexstr)
+				warnx("hexadecimal digits too long");
+			else
+				warnx("string too long");
+			return NULL;
+		}
+		if (hexstr) {
+#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
+			*p++ = (tohex((u_char)val[0]) << 4) |
+			    tohex((u_char)val[1]);
+#undef tohex
+			val += 2;
+		} else
+			*p++ = *val++;
+	}
+	len = p - buf;
+	/* The string "-" is treated as the empty string. */
+	if (!hexstr && len == 1 && buf[0] == '-') {
+		len = 0;
+		memset(buf, 0, *lenp);
+	} else if (len < *lenp)
+		memset(p, 0, *lenp - len);
+	*lenp = len;
+	return val;
+}
+
+static void
+print_string(const u_int8_t *buf, int len)
+{
+	int i;
+	int hasspc;
+
+	i = 0;
+	hasspc = 0;
+	for (; i < len; i++) {
+		if (!isprint(buf[i]) && buf[i] != '\0')
+			break;
+		if (isspace(buf[i]))
+			hasspc++;
+	}
+	if (i == len) {
+		if (hasspc || len == 0 || buf[0] == '\0')
+			printf("\"%.*s\"", len, buf);
+		else
+			printf("%.*s", len, buf);
+	} else {
+		printf("0x");
+		for (i = 0; i < len; i++)
+			printf("%02x", buf[i]);
+	}
+}
+
+/*
+ * Virtual AP cloning support.
+ */
+static struct ieee80211_clone_params params = {
+	.icp_opmode	= IEEE80211_M_STA,	/* default to station mode */
+};
+
+static void
+wlan_create(int s, struct ifreq *ifr)
+{
+	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+
+	if (params.icp_parent[0] == '\0')
+		errx(1, "must specify a parent device (wlandev) when creating "
+		    "a wlan device");
+	if (params.icp_opmode == IEEE80211_M_WDS &&
+	    memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0)
+		errx(1, "no bssid specified for WDS (use wlanbssid)");
+	ifr->ifr_data = (caddr_t) ¶ms;
+	if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+		err(1, "SIOCIFCREATE2");
+}
+
+static
+DECL_CMD_FUNC(set80211clone_wlandev, arg, d)
+{
+	strlcpy(params.icp_parent, arg, IFNAMSIZ);
+}
+
+static
+DECL_CMD_FUNC(set80211clone_wlanbssid, arg, d)
+{
+	const struct ether_addr *ea;
+
+	ea = ether_aton(arg);
+	if (ea == NULL)
+		errx(1, "%s: cannot parse bssid", arg);
+	memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN);
+}
+
+static
+DECL_CMD_FUNC(set80211clone_wlanaddr, arg, d)
+{
+	const struct ether_addr *ea;
+
+	ea = ether_aton(arg);
+	if (ea == NULL)
+		errx(1, "%s: cannot parse addres", arg);
+	memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN);
+	params.icp_flags |= IEEE80211_CLONE_MACADDR;
+}
+
+static
+DECL_CMD_FUNC(set80211clone_wlanmode, arg, d)
+{
+#define	iseq(a,b)	(strncasecmp(a,b,sizeof(b)-1) == 0)
+	if (iseq(arg, "sta"))
+		params.icp_opmode = IEEE80211_M_STA;
+	else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo"))
+		params.icp_opmode = IEEE80211_M_AHDEMO;
+	else if (iseq(arg, "ibss") || iseq(arg, "adhoc"))
+		params.icp_opmode = IEEE80211_M_IBSS;
+	else if (iseq(arg, "ap") || iseq(arg, "host"))
+		params.icp_opmode = IEEE80211_M_HOSTAP;
+	else if (iseq(arg, "wds"))
+		params.icp_opmode = IEEE80211_M_WDS;
+	else if (iseq(arg, "monitor"))
+		params.icp_opmode = IEEE80211_M_MONITOR;
+	else if (iseq(arg, "tdma")) {
+		params.icp_opmode = IEEE80211_M_AHDEMO;
+		params.icp_flags |= IEEE80211_CLONE_TDMA;
+	} else if (iseq(arg, "mesh") || iseq(arg, "mp")) /* mesh point */
+		params.icp_opmode = IEEE80211_M_MBSS;
+	else
+		errx(1, "Don't know to create %s for %s", arg, name);
+#undef iseq
+}
+
+static void
+set80211clone_beacons(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	/* NB: inverted sense */
+	if (d)
+		params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS;
+	else
+		params.icp_flags |= IEEE80211_CLONE_NOBEACONS;
+}
+
+static void
+set80211clone_bssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	if (d)
+		params.icp_flags |= IEEE80211_CLONE_BSSID;
+	else
+		params.icp_flags &= ~IEEE80211_CLONE_BSSID;
+}
+
+static void
+set80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	if (d)
+		params.icp_flags |= IEEE80211_CLONE_WDSLEGACY;
+	else
+		params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY;
+}
+
+static struct cmd ieee80211_cmds[] = {
+	DEF_CMD_ARG("ssid",		set80211ssid),
+	DEF_CMD_ARG("nwid",		set80211ssid),
+	DEF_CMD_ARG("meshid",		set80211meshid),
+	DEF_CMD_ARG("stationname",	set80211stationname),
+	DEF_CMD_ARG("station",		set80211stationname),	/* BSD/OS */
+	DEF_CMD_ARG("channel",		set80211channel),
+	DEF_CMD_ARG("authmode",		set80211authmode),
+	DEF_CMD_ARG("powersavemode",	set80211powersavemode),
+	DEF_CMD("powersave",	1,	set80211powersave),
+	DEF_CMD("-powersave",	0,	set80211powersave),
+	DEF_CMD_ARG("powersavesleep", 	set80211powersavesleep),
+	DEF_CMD_ARG("wepmode",		set80211wepmode),
+	DEF_CMD("wep",		1,	set80211wep),
+	DEF_CMD("-wep",		0,	set80211wep),
+	DEF_CMD_ARG("deftxkey",		set80211weptxkey),
+	DEF_CMD_ARG("weptxkey",		set80211weptxkey),
+	DEF_CMD_ARG("wepkey",		set80211wepkey),
+	DEF_CMD_ARG("nwkey",		set80211nwkey),		/* NetBSD */
+	DEF_CMD("-nwkey",	0,	set80211wep),		/* NetBSD */
+	DEF_CMD_ARG("rtsthreshold",	set80211rtsthreshold),
+	DEF_CMD_ARG("protmode",		set80211protmode),
+	DEF_CMD_ARG("txpower",		set80211txpower),
+	DEF_CMD_ARG("roaming",		set80211roaming),
+	DEF_CMD("wme",		1,	set80211wme),
+	DEF_CMD("-wme",		0,	set80211wme),
+	DEF_CMD("wmm",		1,	set80211wme),
+	DEF_CMD("-wmm",		0,	set80211wme),
+	DEF_CMD("hidessid",	1,	set80211hidessid),
+	DEF_CMD("-hidessid",	0,	set80211hidessid),
+	DEF_CMD("apbridge",	1,	set80211apbridge),
+	DEF_CMD("-apbridge",	0,	set80211apbridge),
+	DEF_CMD_ARG("chanlist",		set80211chanlist),
+	DEF_CMD_ARG("bssid",		set80211bssid),
+	DEF_CMD_ARG("ap",		set80211bssid),
+	DEF_CMD("scan",	0,		set80211scan),
+	DEF_CMD_ARG("list",		set80211list),
+	DEF_CMD_ARG2("cwmin",		set80211cwmin),
+	DEF_CMD_ARG2("cwmax",		set80211cwmax),
+	DEF_CMD_ARG2("aifs",		set80211aifs),
+	DEF_CMD_ARG2("txoplimit",	set80211txoplimit),
+	DEF_CMD_ARG("acm",		set80211acm),
+	DEF_CMD_ARG("-acm",		set80211noacm),
+	DEF_CMD_ARG("ack",		set80211ackpolicy),
+	DEF_CMD_ARG("-ack",		set80211noackpolicy),
+	DEF_CMD_ARG2("bss:cwmin",	set80211bsscwmin),
+	DEF_CMD_ARG2("bss:cwmax",	set80211bsscwmax),
+	DEF_CMD_ARG2("bss:aifs",	set80211bssaifs),
+	DEF_CMD_ARG2("bss:txoplimit",	set80211bsstxoplimit),
+	DEF_CMD_ARG("dtimperiod",	set80211dtimperiod),
+	DEF_CMD_ARG("bintval",		set80211bintval),
+	DEF_CMD("mac:open",	IEEE80211_MACCMD_POLICY_OPEN,	set80211maccmd),
+	DEF_CMD("mac:allow",	IEEE80211_MACCMD_POLICY_ALLOW,	set80211maccmd),
+	DEF_CMD("mac:deny",	IEEE80211_MACCMD_POLICY_DENY,	set80211maccmd),
+	DEF_CMD("mac:radius",	IEEE80211_MACCMD_POLICY_RADIUS,	set80211maccmd),
+	DEF_CMD("mac:flush",	IEEE80211_MACCMD_FLUSH,		set80211maccmd),
+	DEF_CMD("mac:detach",	IEEE80211_MACCMD_DETACH,	set80211maccmd),
+	DEF_CMD_ARG("mac:add",		set80211addmac),
+	DEF_CMD_ARG("mac:del",		set80211delmac),
+	DEF_CMD_ARG("mac:kick",		set80211kickmac),
+	DEF_CMD("pureg",	1,	set80211pureg),
+	DEF_CMD("-pureg",	0,	set80211pureg),
+	DEF_CMD("ff",		1,	set80211fastframes),
+	DEF_CMD("-ff",		0,	set80211fastframes),
+	DEF_CMD("dturbo",	1,	set80211dturbo),
+	DEF_CMD("-dturbo",	0,	set80211dturbo),
+	DEF_CMD("bgscan",	1,	set80211bgscan),
+	DEF_CMD("-bgscan",	0,	set80211bgscan),
+	DEF_CMD_ARG("bgscanidle",	set80211bgscanidle),
+	DEF_CMD_ARG("bgscanintvl",	set80211bgscanintvl),
+	DEF_CMD_ARG("scanvalid",	set80211scanvalid),
+	DEF_CMD_ARG("roam:rssi",	set80211roamrssi),
+	DEF_CMD_ARG("roam:rate",	set80211roamrate),
+	DEF_CMD_ARG("mcastrate",	set80211mcastrate),
+	DEF_CMD_ARG("ucastrate",	set80211ucastrate),
+	DEF_CMD_ARG("mgtrate",		set80211mgtrate),
+	DEF_CMD_ARG("mgmtrate",		set80211mgtrate),
+	DEF_CMD_ARG("maxretry",		set80211maxretry),
+	DEF_CMD_ARG("fragthreshold",	set80211fragthreshold),
+	DEF_CMD("burst",	1,	set80211burst),
+	DEF_CMD("-burst",	0,	set80211burst),
+	DEF_CMD_ARG("bmiss",		set80211bmissthreshold),
+	DEF_CMD_ARG("bmissthreshold",	set80211bmissthreshold),
+	DEF_CMD("shortgi",	1,	set80211shortgi),
+	DEF_CMD("-shortgi",	0,	set80211shortgi),
+	DEF_CMD("ampdurx",	2,	set80211ampdu),
+	DEF_CMD("-ampdurx",	-2,	set80211ampdu),
+	DEF_CMD("ampdutx",	1,	set80211ampdu),
+	DEF_CMD("-ampdutx",	-1,	set80211ampdu),
+	DEF_CMD("ampdu",	3,	set80211ampdu),		/* NB: tx+rx */
+	DEF_CMD("-ampdu",	-3,	set80211ampdu),
+	DEF_CMD_ARG("ampdulimit",	set80211ampdulimit),
+	DEF_CMD_ARG("ampdudensity",	set80211ampdudensity),
+	DEF_CMD("amsdurx",	2,	set80211amsdu),
+	DEF_CMD("-amsdurx",	-2,	set80211amsdu),
+	DEF_CMD("amsdutx",	1,	set80211amsdu),
+	DEF_CMD("-amsdutx",	-1,	set80211amsdu),
+	DEF_CMD("amsdu",	3,	set80211amsdu),		/* NB: tx+rx */
+	DEF_CMD("-amsdu",	-3,	set80211amsdu),
+	DEF_CMD_ARG("amsdulimit",	set80211amsdulimit),
+	DEF_CMD("puren",	1,	set80211puren),
+	DEF_CMD("-puren",	0,	set80211puren),
+	DEF_CMD("doth",		1,	set80211doth),
+	DEF_CMD("-doth",	0,	set80211doth),
+	DEF_CMD("dfs",		1,	set80211dfs),
+	DEF_CMD("-dfs",		0,	set80211dfs),
+	DEF_CMD("htcompat",	1,	set80211htcompat),
+	DEF_CMD("-htcompat",	0,	set80211htcompat),
+	DEF_CMD("dwds",		1,	set80211dwds),
+	DEF_CMD("-dwds",	0,	set80211dwds),
+	DEF_CMD("inact",	1,	set80211inact),
+	DEF_CMD("-inact",	0,	set80211inact),
+	DEF_CMD("tsn",		1,	set80211tsn),
+	DEF_CMD("-tsn",		0,	set80211tsn),
+	DEF_CMD_ARG("regdomain",	set80211regdomain),
+	DEF_CMD_ARG("country",		set80211country),
+	DEF_CMD("indoor",	'I',	set80211location),
+	DEF_CMD("-indoor",	'O',	set80211location),
+	DEF_CMD("outdoor",	'O',	set80211location),
+	DEF_CMD("-outdoor",	'I',	set80211location),
+	DEF_CMD("anywhere",	' ',	set80211location),
+	DEF_CMD("ecm",		1,	set80211ecm),
+	DEF_CMD("-ecm",		0,	set80211ecm),
+	DEF_CMD("dotd",		1,	set80211dotd),
+	DEF_CMD("-dotd",	0,	set80211dotd),
+	DEF_CMD_ARG("htprotmode",	set80211htprotmode),
+	DEF_CMD("ht20",		1,	set80211htconf),
+	DEF_CMD("-ht20",	0,	set80211htconf),
+	DEF_CMD("ht40",		3,	set80211htconf),	/* NB: 20+40 */
+	DEF_CMD("-ht40",	0,	set80211htconf),
+	DEF_CMD("ht",		3,	set80211htconf),	/* NB: 20+40 */
+	DEF_CMD("-ht",		0,	set80211htconf),
+	DEF_CMD("rifs",		1,	set80211rifs),
+	DEF_CMD("-rifs",	0,	set80211rifs),
+	DEF_CMD("smps",		IEEE80211_HTCAP_SMPS_ENA,	set80211smps),
+	DEF_CMD("smpsdyn",	IEEE80211_HTCAP_SMPS_DYNAMIC,	set80211smps),
+	DEF_CMD("-smps",	IEEE80211_HTCAP_SMPS_OFF,	set80211smps),
+	/* XXX for testing */
+	DEF_CMD_ARG("chanswitch",	set80211chanswitch),
+
+	DEF_CMD_ARG("tdmaslot",		set80211tdmaslot),
+	DEF_CMD_ARG("tdmaslotcnt",	set80211tdmaslotcnt),
+	DEF_CMD_ARG("tdmaslotlen",	set80211tdmaslotlen),
+	DEF_CMD_ARG("tdmabintval",	set80211tdmabintval),
+
+	DEF_CMD_ARG("meshttl",		set80211meshttl),
+	DEF_CMD("meshforward",	1,	set80211meshforward),
+	DEF_CMD("-meshforward",	0,	set80211meshforward),
+	DEF_CMD("meshpeering",	1,	set80211meshpeering),
+	DEF_CMD("-meshpeering",	0,	set80211meshpeering),
+	DEF_CMD_ARG("meshmetric",	set80211meshmetric),
+	DEF_CMD_ARG("meshpath",		set80211meshpath),
+	DEF_CMD("meshrt:flush",	IEEE80211_MESH_RTCMD_FLUSH,	set80211meshrtcmd),
+	DEF_CMD_ARG("meshrt:add",	set80211addmeshrt),
+	DEF_CMD_ARG("meshrt:del",	set80211delmeshrt),
+	DEF_CMD_ARG("hwmprootmode",	set80211hwmprootmode),
+	DEF_CMD_ARG("hwmpmaxhops",	set80211hwmpmaxhops),
+
+	/* vap cloning support */
+	DEF_CLONE_CMD_ARG("wlanaddr",	set80211clone_wlanaddr),
+	DEF_CLONE_CMD_ARG("wlanbssid",	set80211clone_wlanbssid),
+	DEF_CLONE_CMD_ARG("wlandev",	set80211clone_wlandev),
+	DEF_CLONE_CMD_ARG("wlanmode",	set80211clone_wlanmode),
+	DEF_CLONE_CMD("beacons", 1,	set80211clone_beacons),
+	DEF_CLONE_CMD("-beacons", 0,	set80211clone_beacons),
+	DEF_CLONE_CMD("bssid",	1,	set80211clone_bssid),
+	DEF_CLONE_CMD("-bssid",	0,	set80211clone_bssid),
+	DEF_CLONE_CMD("wdslegacy", 1,	set80211clone_wdslegacy),
+	DEF_CLONE_CMD("-wdslegacy", 0,	set80211clone_wdslegacy),
+};
+static struct afswtch af_ieee80211 = {
+	.af_name	= "af_ieee80211",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = ieee80211_status,
+};
+
+static __constructor void
+ieee80211_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(ieee80211_cmds);  i++)
+		cmd_register(&ieee80211_cmds[i]);
+	af_register(&af_ieee80211);
+	clone_setdefcallback("wlan", wlan_create);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/iflagg.c b/freebsd-userspace/commands/sbin/ifconfig/iflagg.c
new file mode 100644
index 0000000..4204d92
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/iflagg.c
@@ -0,0 +1,198 @@
+/*-
+ */
+
+#ifndef lint
+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 <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#ifdef __rtems__
+#include <freebsd/net/if_lagg.h>
+#else
+#include <net/if_lagg.h>
+#endif
+#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"
+
+char lacpbuf[120];	/* LACP peer '[(a,a,a),(p,p,p)]' */
+
+static void
+setlaggport(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct lagg_reqport rp;
+
+	bzero(&rp, sizeof(rp));
+	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
+	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
+
+	if (ioctl(s, SIOCSLAGGPORT, &rp))
+		err(1, "SIOCSLAGGPORT");
+}
+
+static void
+unsetlaggport(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct lagg_reqport rp;
+
+	bzero(&rp, sizeof(rp));
+	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
+	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
+
+	if (ioctl(s, SIOCSLAGGDELPORT, &rp))
+		err(1, "SIOCSLAGGDELPORT");
+}
+
+static void
+setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct lagg_protos lpr[] = LAGG_PROTOS;
+	struct lagg_reqall ra;
+	int i;
+
+	bzero(&ra, sizeof(ra));
+	ra.ra_proto = LAGG_PROTO_MAX;
+
+	for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+		if (strcmp(val, lpr[i].lpr_name) == 0) {
+			ra.ra_proto = lpr[i].lpr_proto;
+			break;
+		}
+	}
+	if (ra.ra_proto == LAGG_PROTO_MAX)
+		errx(1, "Invalid aggregation protocol: %s", val);
+
+	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
+	if (ioctl(s, SIOCSLAGG, &ra) != 0)
+		err(1, "SIOCSLAGG");
+}
+
+static char *
+lacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
+{
+	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
+	    (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3],
+	    (int)mac[4], (int)mac[5]);
+
+	return (buf);
+}
+
+static char *
+lacp_format_peer(struct lacp_opreq *req, const char *sep)
+{
+	char macbuf1[20];
+	char macbuf2[20];
+
+	snprintf(lacpbuf, sizeof(lacpbuf),
+	    "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]",
+	    req->actor_prio,
+	    lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)),
+	    req->actor_key, req->actor_portprio, req->actor_portno, sep,
+	    req->partner_prio,
+	    lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)),
+	    req->partner_key, req->partner_portprio, req->partner_portno);
+
+	return(lacpbuf);
+}
+
+static void
+lagg_status(int s)
+{
+	struct lagg_protos lpr[] = LAGG_PROTOS;
+	struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
+	struct lagg_reqall ra;
+	struct lacp_opreq *lp;
+	const char *proto = "<unknown>";
+	int i, isport = 0;
+
+	bzero(&rp, sizeof(rp));
+	bzero(&ra, sizeof(ra));
+
+	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
+	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
+
+	if (ioctl(s, SIOCGLAGGPORT, &rp) == 0)
+		isport = 1;
+
+	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
+	ra.ra_size = sizeof(rpbuf);
+	ra.ra_port = rpbuf;
+
+	if (ioctl(s, SIOCGLAGG, &ra) == 0) {
+		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
+
+		for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+			if (ra.ra_proto == lpr[i].lpr_proto) {
+				proto = lpr[i].lpr_name;
+				break;
+			}
+		}
+
+		printf("\tlaggproto %s", proto);
+		if (isport)
+			printf(" laggdev %s", rp.rp_ifname);
+		putchar('\n');
+		if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
+			printf("\tlag id: %s\n",
+			    lacp_format_peer(lp, "\n\t\t "));
+
+		for (i = 0; i < ra.ra_ports; i++) {
+			lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
+			printf("\tlaggport: %s ", rpbuf[i].rp_portname);
+			printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
+			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
+				printf(" state=%X", lp->actor_state);
+			putchar('\n');
+			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
+				printf("\t\t%s\n",
+				    lacp_format_peer(lp, "\n\t\t "));
+		}
+
+		if (0 /* XXX */) {
+			printf("\tsupported aggregation protocols:\n");
+			for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
+				printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
+		}
+	}
+}
+
+static struct cmd lagg_cmds[] = {
+	DEF_CMD_ARG("laggport",		setlaggport),
+	DEF_CMD_ARG("-laggport",	unsetlaggport),
+	DEF_CMD_ARG("laggproto",	setlaggproto),
+};
+static struct afswtch af_lagg = {
+	.af_name	= "af_lagg",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = lagg_status,
+};
+
+static __constructor void
+lagg_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(lagg_cmds);  i++)
+		cmd_register(&lagg_cmds[i]);
+	af_register(&af_lagg);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifmac.c b/freebsd-userspace/commands/sbin/ifconfig/ifmac.c
new file mode 100644
index 0000000..31d40b1
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifmac.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by NAI Labs, the
+ * Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#ifdef __rtems__
+#include <freebsd/sys/mac.h>
+#else
+#include <sys/mac.h>
+#endif
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ifconfig.h"
+
+static void
+maclabel_status(int s)
+{
+	struct ifreq ifr;
+	mac_t label;
+	char *label_text;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+	if (mac_prepare_ifnet_label(&label) == -1)
+		return;
+	ifr.ifr_ifru.ifru_data = (void *)label;
+	if (ioctl(s, SIOCGIFMAC, &ifr) == -1)
+		goto mac_free;
+
+	
+	if (mac_to_text(label, &label_text) == -1)
+		goto mac_free;
+
+	if (strlen(label_text) != 0)
+		printf("\tmaclabel %s\n", label_text);
+	free(label_text);
+
+mac_free:
+	mac_free(label);
+}
+
+static void
+setifmaclabel(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct ifreq ifr;
+	mac_t label;
+	int error;
+
+	if (mac_from_text(&label, val) == -1) {
+		perror(val);
+		return;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_ifru.ifru_data = (void *)label;
+
+	error = ioctl(s, SIOCSIFMAC, &ifr);
+	mac_free(label);
+	if (error == -1)
+		perror("setifmac");
+}
+
+static struct cmd mac_cmds[] = {
+	DEF_CMD_ARG("maclabel",	setifmaclabel),
+};
+static struct afswtch af_mac = {
+	.af_name	= "af_maclabel",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = maclabel_status,
+};
+
+static __constructor void
+mac_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(mac_cmds);  i++)
+		cmd_register(&mac_cmds[i]);
+	af_register(&af_mac);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifmedia.c b/freebsd-userspace/commands/sbin/ifconfig/ifmedia.c
new file mode 100644
index 0000000..ebca67d
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifmedia.c
@@ -0,0 +1,844 @@
+/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1997 Jason R. Thorpe.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project
+ *	by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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 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.
+ */
+
+/*
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 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.
+ */
+
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#ifdef __rtems__
+#define  _KERNEL
+#include <freebsd/net/if_media.h>
+#undef _KERNEL
+#else
+#include <net/if_media.h>
+#endif
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void	domediaopt(const char *, int, int);
+static int	get_media_subtype(int, const char *);
+static int	get_media_mode(int, const char *);
+static int	get_media_options(int, const char *);
+static int	lookup_media_word(struct ifmedia_description *, const char *);
+static void	print_media_word(int, int);
+static void	print_media_word_ifconfig(int);
+
+static struct ifmedia_description *get_toptype_desc(int);
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
+static struct ifmedia_description *get_subtype_desc(int,
+    struct ifmedia_type_to_subtype *ttos);
+
+#define	IFM_OPMODE(x) \
+	((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
+	 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
+	 IFM_IEEE80211_MBSS))
+#define	IFM_IEEE80211_STA	0
+
+static void
+media_status(int s)
+{
+	struct ifmediareq ifmr;
+	int *media_list, i;
+
+	(void) memset(&ifmr, 0, sizeof(ifmr));
+	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+		/*
+		 * Interface doesn't support SIOC{G,S}IFMEDIA.
+		 */
+		return;
+	}
+
+	if (ifmr.ifm_count == 0) {
+		warnx("%s: no media types?", name);
+		return;
+	}
+
+	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+	if (media_list == NULL)
+		err(1, "malloc");
+	ifmr.ifm_ulist = media_list;
+
+	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+		err(1, "SIOCGIFMEDIA");
+
+	printf("\tmedia: ");
+	print_media_word(ifmr.ifm_current, 1);
+	if (ifmr.ifm_active != ifmr.ifm_current) {
+		putchar(' ');
+		putchar('(');
+		print_media_word(ifmr.ifm_active, 0);
+		putchar(')');
+	}
+
+	putchar('\n');
+
+	if (ifmr.ifm_status & IFM_AVALID) {
+		printf("\tstatus: ");
+		switch (IFM_TYPE(ifmr.ifm_active)) {
+		case IFM_ETHER:
+		case IFM_ATM:
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				printf("active");
+			else
+				printf("no carrier");
+			break;
+
+		case IFM_FDDI:
+		case IFM_TOKEN:
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				printf("inserted");
+			else
+				printf("no ring");
+			break;
+
+		case IFM_IEEE80211:
+			if (ifmr.ifm_status & IFM_ACTIVE) {
+				/* NB: only sta mode associates */
+				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
+					printf("associated");
+				else
+					printf("running");
+			} else
+				printf("no carrier");
+			break;
+		}
+		putchar('\n');
+	}
+
+	if (ifmr.ifm_count > 0 && supmedia) {
+		printf("\tsupported media:\n");
+		for (i = 0; i < ifmr.ifm_count; i++) {
+			printf("\t\t");
+			print_media_word_ifconfig(media_list[i]);
+			putchar('\n');
+		}
+	}
+
+	free(media_list);
+}
+
+struct ifmediareq *
+ifmedia_getstate(int s)
+{
+	static struct ifmediareq *ifmr = NULL;
+	int *mwords;
+
+	if (ifmr == NULL) {
+		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+		if (ifmr == NULL)
+			err(1, "malloc");
+
+		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
+		(void) strncpy(ifmr->ifm_name, name,
+		    sizeof(ifmr->ifm_name));
+
+		ifmr->ifm_count = 0;
+		ifmr->ifm_ulist = NULL;
+
+		/*
+		 * We must go through the motions of reading all
+		 * supported media because we need to know both
+		 * the current media type and the top-level type.
+		 */
+
+		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
+			err(1, "SIOCGIFMEDIA");
+		}
+
+		if (ifmr->ifm_count == 0)
+			errx(1, "%s: no media types?", name);
+
+		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
+		if (mwords == NULL)
+			err(1, "malloc");
+  
+		ifmr->ifm_ulist = mwords;
+		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
+			err(1, "SIOCGIFMEDIA");
+	}
+
+	return ifmr;
+}
+
+static void
+setifmediacallback(int s, void *arg)
+{
+	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
+	static int did_it = 0;
+
+	if (!did_it) {
+		ifr.ifr_media = ifmr->ifm_current;
+		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+			err(1, "SIOCSIFMEDIA (media)");
+		free(ifmr->ifm_ulist);
+		free(ifmr);
+		did_it = 1;
+	}
+}
+
+static void
+setmedia(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int subtype;
+
+	ifmr = ifmedia_getstate(s);
+
+	/*
+	 * We are primarily concerned with the top-level type.
+	 * However, "current" may be only IFM_NONE, so we just look
+	 * for the top-level type in the first "supported type"
+	 * entry.
+	 *
+	 * (I'm assuming that all supported media types for a given
+	 * interface will be the same top-level type..)
+	 */
+	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
+	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
+
+	if ((ifr.ifr_media & IFM_TMASK) == 0) {
+		ifr.ifr_media &= ~(IFM_GMASK | IFM_OMASK);
+	}
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	domediaopt(val, 0, s);
+}
+
+static void
+unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	domediaopt(val, 1, s);
+}
+
+static void
+domediaopt(const char *val, int clear, int s)
+{
+	struct ifmediareq *ifmr;
+	int options;
+
+	ifmr = ifmedia_getstate(s);
+
+	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = ifmr->ifm_current;
+	if (clear)
+		ifr.ifr_media &= ~options;
+	else {
+		if (options & IFM_HDX) {
+			ifr.ifr_media &= ~IFM_FDX;
+			options &= ~IFM_HDX;
+		}
+		ifr.ifr_media |= options;
+	}
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediainst(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int inst;
+
+	ifmr = ifmedia_getstate(s);
+
+	inst = atoi(val);
+	if (inst < 0 || inst > (int)IFM_INST_MAX)
+		errx(1, "invalid media instance: %s", val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediamode(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int mode;
+
+	ifmr = ifmedia_getstate(s);
+
+	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+/**********************************************************************
+ * A good chunk of this is duplicated from sys/net/ifmedia.c
+ **********************************************************************/
+
+static struct ifmedia_description ifm_type_descriptions[] =
+    IFM_TYPE_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
+    IFM_SUBTYPE_ETHERNET_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
+    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
+    IFM_SUBTYPE_TOKENRING_ALIASES;
+
+static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
+    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
+    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_aliases[] =
+    IFM_SUBTYPE_FDDI_ALIASES;
+
+static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
+    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+    IFM_SUBTYPE_IEEE80211_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_descriptions[] =
+    IFM_SUBTYPE_ATM_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_atm_aliases[] =
+    IFM_SUBTYPE_ATM_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_shared_descriptions[] =
+    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_shared_aliases[] =
+    IFM_SUBTYPE_SHARED_ALIASES;
+
+static struct ifmedia_description ifm_shared_option_descriptions[] =
+    IFM_SHARED_OPTION_DESCRIPTIONS;
+
+struct ifmedia_type_to_subtype {
+	struct {
+		struct ifmedia_description *desc;
+		int alias;
+	} subtypes[5];
+	struct {
+		struct ifmedia_description *desc;
+		int alias;
+	} options[3];
+	struct {
+		struct ifmedia_description *desc;
+		int alias;
+	} modes[3];
+};
+
+/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
+static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_ethernet_descriptions[0], 0 },
+			{ &ifm_subtype_ethernet_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_tokenring_descriptions[0], 0 },
+			{ &ifm_subtype_tokenring_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_fddi_descriptions[0], 0 },
+			{ &ifm_subtype_fddi_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
+			{ &ifm_subtype_ieee80211_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
+			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_atm_descriptions[0], 0 },
+			{ &ifm_subtype_atm_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_subtype_atm_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+};
+
+static int
+get_media_subtype(int type, const char *val)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int rval, i;
+
+	/* Find the top-level interface type. */
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (type == desc->ifmt_word)
+			break;
+	if (desc->ifmt_string == NULL)
+		errx(1, "unknown media type 0x%x", type);
+
+	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+		rval = lookup_media_word(ttos->subtypes[i].desc, val);
+		if (rval != -1)
+			return (rval);
+	}
+	errx(1, "unknown media subtype: %s", val);
+	/*NOTREACHED*/
+}
+
+static int
+get_media_mode(int type, const char *val)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int rval, i;
+
+	/* Find the top-level interface type. */
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (type == desc->ifmt_word)
+			break;
+	if (desc->ifmt_string == NULL)
+		errx(1, "unknown media mode 0x%x", type);
+
+	for (i = 0; ttos->modes[i].desc != NULL; i++) {
+		rval = lookup_media_word(ttos->modes[i].desc, val);
+		if (rval != -1)
+			return (rval);
+	}
+	return -1;
+}
+
+static int
+get_media_options(int type, const char *val)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	char *optlist, *optptr;
+	int option = 0, i, rval = 0;
+
+	/* We muck with the string, so copy it. */
+	optlist = strdup(val);
+	if (optlist == NULL)
+		err(1, "strdup");
+
+	/* Find the top-level interface type. */
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (type == desc->ifmt_word)
+			break;
+	if (desc->ifmt_string == NULL)
+		errx(1, "unknown media type 0x%x", type);
+
+	/*
+	 * Look up the options in the user-provided comma-separated
+	 * list.
+	 */
+	optptr = optlist;
+	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
+		for (i = 0; ttos->options[i].desc != NULL; i++) {
+			option = lookup_media_word(ttos->options[i].desc, optptr);
+			if (option != -1)
+				break;
+		}
+		if (option == 0)
+			errx(1, "unknown option: %s", optptr);
+		rval |= option;
+	}
+
+	free(optlist);
+	return (rval);
+}
+
+static int
+lookup_media_word(struct ifmedia_description *desc, const char *val)
+{
+
+	for (; desc->ifmt_string != NULL; desc++)
+		if (strcasecmp(desc->ifmt_string, val) == 0)
+			return (desc->ifmt_word);
+
+	return (-1);
+}
+
+static struct ifmedia_description *get_toptype_desc(int ifmw)
+{
+	struct ifmedia_description *desc;
+
+	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
+		if (IFM_TYPE(ifmw) == desc->ifmt_word)
+			break;
+
+	return desc;
+}
+
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (IFM_TYPE(ifmw) == desc->ifmt_word)
+			break;
+
+	return ttos;
+}
+
+static struct ifmedia_description *get_subtype_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
+{
+	int i;
+	struct ifmedia_description *desc;
+
+	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+		if (ttos->subtypes[i].alias)
+			continue;
+		for (desc = ttos->subtypes[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
+				return desc;
+		}
+	}
+
+	return NULL;
+}
+
+static struct ifmedia_description *get_mode_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
+{
+	int i;
+	struct ifmedia_description *desc;
+
+	for (i = 0; ttos->modes[i].desc != NULL; i++) {
+		if (ttos->modes[i].alias)
+			continue;
+		for (desc = ttos->modes[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (IFM_MODE(ifmw) == desc->ifmt_word)
+				return desc;
+		}
+	}
+
+	return NULL;
+}
+
+static void
+print_media_word(int ifmw, int print_toptype)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int seen_option = 0, i;
+
+	/* Find the top-level interface type. */
+	desc = get_toptype_desc(ifmw);
+	ttos = get_toptype_ttos(ifmw);
+	if (desc->ifmt_string == NULL) {
+		printf("<unknown type>");
+		return;
+	} else if (print_toptype) {
+		printf("%s", desc->ifmt_string);
+	}
+
+	/*
+	 * Don't print the top-level type; it's not like we can
+	 * change it, or anything.
+	 */
+
+	/* Find subtype. */
+	desc = get_subtype_desc(ifmw, ttos);
+	if (desc == NULL) {
+		printf("<unknown subtype>");
+		return;
+	}
+
+	if (print_toptype)
+		putchar(' ');
+
+	printf("%s", desc->ifmt_string);
+
+	if (print_toptype) {
+		desc = get_mode_desc(ifmw, ttos);
+		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
+			printf(" mode %s", desc->ifmt_string);
+	}
+
+	/* Find options. */
+	for (i = 0; ttos->options[i].desc != NULL; i++) {
+		if (ttos->options[i].alias)
+			continue;
+		for (desc = ttos->options[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (ifmw & desc->ifmt_word) {
+				if (seen_option == 0)
+					printf(" <");
+				printf("%s%s", seen_option++ ? "," : "",
+				    desc->ifmt_string);
+			}
+		}
+	}
+	printf("%s", seen_option ? ">" : "");
+
+	if (print_toptype && IFM_INST(ifmw) != 0)
+		printf(" instance %d", IFM_INST(ifmw));
+}
+
+static void
+print_media_word_ifconfig(int ifmw)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int seen_option = 0, i;
+
+	/* Find the top-level interface type. */
+	desc = get_toptype_desc(ifmw);
+	ttos = get_toptype_ttos(ifmw);
+	if (desc->ifmt_string == NULL) {
+		printf("<unknown type>");
+		return;
+	}
+
+	/*
+	 * Don't print the top-level type; it's not like we can
+	 * change it, or anything.
+	 */
+
+	/* Find subtype. */
+	desc = get_subtype_desc(ifmw, ttos);
+	if (desc == NULL) {
+		printf("<unknown subtype>");
+		return;
+	}
+
+	printf("media %s", desc->ifmt_string);
+
+	desc = get_mode_desc(ifmw, ttos);
+	if (desc != NULL)
+		printf(" mode %s", desc->ifmt_string);
+
+	/* Find options. */
+	for (i = 0; ttos->options[i].desc != NULL; i++) {
+		if (ttos->options[i].alias)
+			continue;
+		for (desc = ttos->options[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (ifmw & desc->ifmt_word) {
+				if (seen_option == 0)
+					printf(" mediaopt ");
+				printf("%s%s", seen_option++ ? "," : "",
+				    desc->ifmt_string);
+			}
+		}
+	}
+
+	if (IFM_INST(ifmw) != 0)
+		printf(" instance %d", IFM_INST(ifmw));
+}
+
+/**********************************************************************
+ * ...until here.
+ **********************************************************************/
+
+static struct cmd media_cmds[] = {
+	DEF_CMD_ARG("media",	setmedia),
+	DEF_CMD_ARG("mode",	setmediamode),
+	DEF_CMD_ARG("mediaopt",	setmediaopt),
+	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
+	DEF_CMD_ARG("inst",	setmediainst),
+	DEF_CMD_ARG("instance",	setmediainst),
+};
+static struct afswtch af_media = {
+	.af_name	= "af_media",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = media_status,
+};
+
+static __constructor void
+ifmedia_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(media_cmds);  i++)
+		cmd_register(&media_cmds[i]);
+	af_register(&af_media);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifpfsync.c b/freebsd-userspace/commands/sbin/ifconfig/ifpfsync.c
new file mode 100644
index 0000000..886a75e
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifpfsync.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2003 Ryan McBride. All rights reserved.
+ * Copyright (c) 2004 Max Laier. 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#ifdef __rtems__
+#include <freebsd/net/pfvar.h>
+#include <freebsd/net/if_pfsync.h>
+#else
+#include <net/pfvar.h>
+#include <net/if_pfsync.h>
+#endif
+#include <net/route.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+void setpfsync_syncdev(const char *, int, int, const struct afswtch *);
+void unsetpfsync_syncdev(const char *, int, int, const struct afswtch *);
+void setpfsync_syncpeer(const char *, int, int, const struct afswtch *);
+void unsetpfsync_syncpeer(const char *, int, int, const struct afswtch *);
+void setpfsync_syncpeer(const char *, int, int, const struct afswtch *);
+void setpfsync_maxupd(const char *, int, int, const struct afswtch *);
+void pfsync_status(int);
+
+void
+setpfsync_syncdev(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct pfsyncreq preq;
+
+	bzero((char *)&preq, sizeof(struct pfsyncreq));
+	ifr.ifr_data = (caddr_t)&preq;
+
+	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGETPFSYNC");
+
+	strlcpy(preq.pfsyncr_syncdev, val, sizeof(preq.pfsyncr_syncdev));
+
+	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSETPFSYNC");
+}
+
+/* ARGSUSED */
+void
+unsetpfsync_syncdev(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct pfsyncreq preq;
+
+	bzero((char *)&preq, sizeof(struct pfsyncreq));
+	ifr.ifr_data = (caddr_t)&preq;
+
+	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGETPFSYNC");
+
+	bzero((char *)&preq.pfsyncr_syncdev, sizeof(preq.pfsyncr_syncdev));
+
+	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSETPFSYNC");
+}
+
+/* ARGSUSED */
+void
+setpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct pfsyncreq preq;
+	struct addrinfo hints, *peerres;
+	int ecode;
+
+	bzero((char *)&preq, sizeof(struct pfsyncreq));
+	ifr.ifr_data = (caddr_t)&preq;
+
+	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGETPFSYNC");
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
+
+	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
+		errx(1, "error in parsing address string: %s",
+		    gai_strerror(ecode));
+
+	if (peerres->ai_addr->sa_family != AF_INET)
+		errx(1, "only IPv4 addresses supported for the syncpeer");
+
+	preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *)
+	    peerres->ai_addr)->sin_addr.s_addr;
+
+	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSETPFSYNC");
+}
+
+/* ARGSUSED */
+void
+unsetpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct pfsyncreq preq;
+
+	bzero((char *)&preq, sizeof(struct pfsyncreq));
+	ifr.ifr_data = (caddr_t)&preq;
+
+	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGETPFSYNC");
+
+	preq.pfsyncr_syncpeer.s_addr = 0;
+
+	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSETPFSYNC");
+}
+
+/* ARGSUSED */
+void
+setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	struct pfsyncreq preq;
+	int maxupdates;
+
+	maxupdates = atoi(val);
+	if ((maxupdates < 0) || (maxupdates > 255))
+		errx(1, "maxupd %s: out of range", val);
+
+	memset((char *)&preq, 0, sizeof(struct pfsyncreq));
+	ifr.ifr_data = (caddr_t)&preq;
+
+	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGETPFSYNC");
+
+	preq.pfsyncr_maxupdates = maxupdates;
+
+	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSETPFSYNC");
+}
+
+void
+pfsync_status(int s)
+{
+	struct pfsyncreq preq;
+
+	bzero((char *)&preq, sizeof(struct pfsyncreq));
+	ifr.ifr_data = (caddr_t)&preq;
+
+	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+		return;
+
+	if (preq.pfsyncr_syncdev[0] != '\0' ||
+	    preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
+			printf("\t");
+
+	if (preq.pfsyncr_syncdev[0] != '\0')
+		printf("pfsync: syncdev: %s ", preq.pfsyncr_syncdev);
+	if (preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
+		printf("syncpeer: %s ", inet_ntoa(preq.pfsyncr_syncpeer));
+
+	if (preq.pfsyncr_syncdev[0] != '\0' ||
+	    preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
+		printf("maxupd: %d\n", preq.pfsyncr_maxupdates);
+}
+
+static struct cmd pfsync_cmds[] = {
+	DEF_CMD_ARG("syncdev",		setpfsync_syncdev),
+	DEF_CMD("-syncdev",	1,	unsetpfsync_syncdev),
+	DEF_CMD_ARG("syncif",		setpfsync_syncdev),
+	DEF_CMD("-syncif",	1,	unsetpfsync_syncdev),
+	DEF_CMD_ARG("syncpeer",		setpfsync_syncpeer),
+	DEF_CMD("-syncpeer",	1,	unsetpfsync_syncpeer),
+	DEF_CMD_ARG("maxupd",		setpfsync_maxupd)
+};
+static struct afswtch af_pfsync = {
+	.af_name	= "af_pfsync",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = pfsync_status,
+};
+
+static __constructor void
+pfsync_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(pfsync_cmds);  i++)
+		cmd_register(&pfsync_cmds[i]);
+	af_register(&af_pfsync);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/ifvlan.c b/freebsd-userspace/commands/sbin/ifconfig/ifvlan.c
new file mode 100644
index 0000000..8ec3766
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifvlan.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 1999
+ *	Bill Paul <wpaul at ctr.columbia.edu>.  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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ */
+
+#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>
+#ifdef __rtems__
+#include <freebsd/net/if_var.h>
+#include <freebsd/net/if_vlan_var.h>
+#else
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#endif
+#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"
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif
+
+#define	NOTAG	((u_short) -1)
+
+static 	struct vlanreq params = {
+	.vlr_tag	= NOTAG,
+};
+
+static int
+getvlan(int s, struct ifreq *ifr, struct vlanreq *vreq)
+{
+	bzero((char *)vreq, sizeof(*vreq));
+	ifr->ifr_data = (caddr_t)vreq;
+
+	return ioctl(s, SIOCGETVLAN, (caddr_t)ifr);
+}
+
+static void
+vlan_status(int s)
+{
+	struct vlanreq		vreq;
+
+	if (getvlan(s, &ifr, &vreq) != -1)
+		printf("\tvlan: %d parent interface: %s\n",
+		    vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
+		    "<none>" : vreq.vlr_parent);
+}
+
+static void
+vlan_create(int s, struct ifreq *ifr)
+{
+	if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
+		/*
+		 * One or both parameters were specified, make sure both.
+		 */
+		if (params.vlr_tag == NOTAG)
+			errx(1, "must specify a tag for vlan create");
+		if (params.vlr_parent[0] == '\0')
+			errx(1, "must specify a parent device for vlan create");
+		ifr->ifr_data = (caddr_t) ¶ms;
+	}
+	if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+		err(1, "SIOCIFCREATE2");
+}
+
+static void
+vlan_cb(int s, void *arg)
+{
+	if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0'))
+		errx(1, "both vlan and vlandev must be specified");
+}
+
+static void
+vlan_set(int s, struct ifreq *ifr)
+{
+	if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') {
+		ifr->ifr_data = (caddr_t) ¶ms;
+		if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1)
+			err(1, "SIOCSETVLAN");
+	}
+}
+
+static
+DECL_CMD_FUNC(setvlantag, val, d)
+{
+	struct vlanreq vreq;
+	u_long ul;
+	char *endp;
+
+	ul = strtoul(val, &endp, 0);
+	if (*endp != '\0')
+		errx(1, "invalid value for vlan");
+	params.vlr_tag = ul;
+	/* check if the value can be represented in vlr_tag */
+	if (params.vlr_tag != ul)
+		errx(1, "value for vlan out of range");
+
+	if (getvlan(s, &ifr, &vreq) != -1)
+		vlan_set(s, &ifr);
+}
+
+static
+DECL_CMD_FUNC(setvlandev, val, d)
+{
+	struct vlanreq vreq;
+
+	strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent));
+
+	if (getvlan(s, &ifr, &vreq) != -1)
+		vlan_set(s, &ifr);
+}
+
+static
+DECL_CMD_FUNC(unsetvlandev, val, d)
+{
+	struct vlanreq		vreq;
+
+	bzero((char *)&vreq, sizeof(struct vlanreq));
+	ifr.ifr_data = (caddr_t)&vreq;
+
+	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGETVLAN");
+
+	bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
+	vreq.vlr_tag = 0;
+
+	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSETVLAN");
+}
+
+static struct cmd vlan_cmds[] = {
+	DEF_CLONE_CMD_ARG("vlan",			setvlantag),
+	DEF_CLONE_CMD_ARG("vlandev",			setvlandev),
+	/* NB: non-clone cmds */
+	DEF_CMD_ARG("vlan",				setvlantag),
+	DEF_CMD_ARG("vlandev",				setvlandev),
+	/* XXX For compatibility.  Should become DEF_CMD() some day. */
+	DEF_CMD_OPTARG("-vlandev",			unsetvlandev),
+	DEF_CMD("vlanmtu",	IFCAP_VLAN_MTU,		setifcap),
+	DEF_CMD("-vlanmtu",	-IFCAP_VLAN_MTU,	setifcap),
+	DEF_CMD("vlanhwtag",	IFCAP_VLAN_HWTAGGING,	setifcap),
+	DEF_CMD("-vlanhwtag",	-IFCAP_VLAN_HWTAGGING,	setifcap),
+	DEF_CMD("vlanhwfilter",	IFCAP_VLAN_HWFILTER,	setifcap),
+	DEF_CMD("-vlanhwfilter", -IFCAP_VLAN_HWFILTER,	setifcap),
+	DEF_CMD("-vlanhwtso",	-IFCAP_VLAN_HWTSO,	setifcap),
+	DEF_CMD("vlanhwtso",	IFCAP_VLAN_HWTSO,	setifcap),
+};
+static struct afswtch af_vlan = {
+	.af_name	= "af_vlan",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = vlan_status,
+};
+
+static __constructor void
+vlan_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	size_t i;
+
+	for (i = 0; i < N(vlan_cmds);  i++)
+		cmd_register(&vlan_cmds[i]);
+	af_register(&af_vlan);
+	callback_register(vlan_cb, NULL);
+	clone_setdefcallback("vlan", vlan_create);
+#undef N
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/regdomain.c b/freebsd-userspace/commands/sbin/ifconfig/regdomain.c
new file mode 100644
index 0000000..4140289
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/regdomain.c
@@ -0,0 +1,705 @@
+/*-
+ * Copyright (c) 2008 Sam Leffler, Errno Consulting
+ * 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 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/errno.h>
+#include <sys/mman.h>
+#include <sys/sbuf.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <err.h>
+#include <unistd.h>
+
+#include <bsdxml.h>
+
+#include "regdomain.h"
+
+#include <net80211/_ieee80211.h>
+
+#define	MAXLEVEL	20
+
+struct mystate {
+	XML_Parser		parser;
+	struct regdata		*rdp;
+	struct regdomain	*rd;		/* current domain */
+	struct netband		*netband;	/* current netband */
+	struct freqband		*freqband;	/* current freqband */
+	struct country		*country;	/* current country */
+	netband_head		*curband;	/* current netband list */
+	int			level;
+	struct sbuf		*sbuf[MAXLEVEL];
+	int			nident;
+};
+
+struct ident {
+	const void *id;
+	void *p;
+	enum { DOMAIN, COUNTRY, FREQBAND } type;
+};
+
+static void
+start_element(void *data, const char *name, const char **attr)
+{
+#define	iseq(a,b)	(strcasecmp(a,b) == 0)
+	struct mystate *mt;
+	const void *id, *ref, *mode;
+	int i;
+
+	mt = data;
+	if (++mt->level == MAXLEVEL) {
+		/* XXX force parser to abort */
+		return;
+	}
+	mt->sbuf[mt->level] = sbuf_new_auto();
+	id = ref = mode = NULL;
+	for (i = 0; attr[i] != NULL; i += 2) {
+		if (iseq(attr[i], "id")) {
+			id = attr[i+1];
+		} else if (iseq(attr[i], "ref")) {
+			ref = attr[i+1];
+		} else if (iseq(attr[i], "mode")) {
+			mode = attr[i+1];
+		} else
+			printf("%*.*s[%s = %s]\n", mt->level + 1,
+			    mt->level + 1, "", attr[i], attr[i+1]);
+	}
+	if (iseq(name, "rd") && mt->rd == NULL) {
+		if (mt->country == NULL) {
+			mt->rd = calloc(1, sizeof(struct regdomain));
+			mt->rd->name = strdup(id);
+			mt->nident++;
+			LIST_INSERT_HEAD(&mt->rdp->domains, mt->rd, next);
+		} else
+			mt->country->rd = (void *)strdup(ref);
+		return;
+	}
+	if (iseq(name, "defcc") && mt->rd != NULL) {
+		mt->rd->cc = (void *)strdup(ref);
+		return;
+	}
+	if (iseq(name, "netband") && mt->curband == NULL && mt->rd != NULL) {
+		if (mode == NULL) {
+			warnx("no mode for netband at line %ld",
+			    XML_GetCurrentLineNumber(mt->parser));
+			return;
+		}
+		if (iseq(mode, "11b"))
+			mt->curband = &mt->rd->bands_11b;
+		else if (iseq(mode, "11g"))
+			mt->curband = &mt->rd->bands_11g;
+		else if (iseq(mode, "11a"))
+			mt->curband = &mt->rd->bands_11a;
+		else if (iseq(mode, "11ng"))
+			mt->curband = &mt->rd->bands_11ng;
+		else if (iseq(mode, "11na"))
+			mt->curband = &mt->rd->bands_11na;
+		else
+			warnx("unknown mode \"%s\" at line %ld",
+			    __DECONST(char *, mode),
+			    XML_GetCurrentLineNumber(mt->parser));
+		return;
+	}
+	if (iseq(name, "band") && mt->netband == NULL) {
+		if (mt->curband == NULL) {
+			warnx("band without enclosing netband at line %ld",
+			    XML_GetCurrentLineNumber(mt->parser));
+			return;
+		}
+		mt->netband = calloc(1, sizeof(struct netband));
+		LIST_INSERT_HEAD(mt->curband, mt->netband, next);
+		return;
+	}
+	if (iseq(name, "freqband") && mt->freqband == NULL && mt->netband != NULL) {
+		/* XXX handle inlines and merge into table? */
+		if (mt->netband->band != NULL) {
+			warnx("duplicate freqband at line %ld ignored",
+			    XML_GetCurrentLineNumber(mt->parser));
+			/* XXX complain */
+		} else
+			mt->netband->band = (void *)strdup(ref);
+		return;
+	}
+
+	if (iseq(name, "country") && mt->country == NULL) {
+		mt->country = calloc(1, sizeof(struct country));
+		mt->country->isoname = strdup(id);
+		mt->country->code = NO_COUNTRY;
+		mt->nident++;
+		LIST_INSERT_HEAD(&mt->rdp->countries, mt->country, next);
+		return;
+	}
+
+	if (iseq(name, "freqband") && mt->freqband == NULL) {
+		mt->freqband = calloc(1, sizeof(struct freqband));
+		mt->freqband->id = strdup(id);
+		mt->nident++;
+		LIST_INSERT_HEAD(&mt->rdp->freqbands, mt->freqband, next);
+		return;
+	}
+#undef iseq
+}
+
+static int
+decode_flag(struct mystate *mt, const char *p, int len)
+{
+#define	iseq(a,b)	(strcasecmp(a,b) == 0)
+	static const struct {
+		const char *name;
+		int len;
+		uint32_t value;
+	} flags[] = {
+#define	FLAG(x)	{ #x, sizeof(#x)-1, x }
+		FLAG(IEEE80211_CHAN_A),
+		FLAG(IEEE80211_CHAN_B),
+		FLAG(IEEE80211_CHAN_G),
+		FLAG(IEEE80211_CHAN_HT20),
+		FLAG(IEEE80211_CHAN_HT40),
+		FLAG(IEEE80211_CHAN_ST),
+		FLAG(IEEE80211_CHAN_TURBO),
+		FLAG(IEEE80211_CHAN_PASSIVE),
+		FLAG(IEEE80211_CHAN_DFS),
+		FLAG(IEEE80211_CHAN_CCK),
+		FLAG(IEEE80211_CHAN_OFDM),
+		FLAG(IEEE80211_CHAN_2GHZ),
+		FLAG(IEEE80211_CHAN_5GHZ),
+		FLAG(IEEE80211_CHAN_DYN),
+		FLAG(IEEE80211_CHAN_GFSK),
+		FLAG(IEEE80211_CHAN_GSM),
+		FLAG(IEEE80211_CHAN_STURBO),
+		FLAG(IEEE80211_CHAN_HALF),
+		FLAG(IEEE80211_CHAN_QUARTER),
+		FLAG(IEEE80211_CHAN_HT40U),
+		FLAG(IEEE80211_CHAN_HT40D),
+		FLAG(IEEE80211_CHAN_4MSXMIT),
+		FLAG(IEEE80211_CHAN_NOADHOC),
+		FLAG(IEEE80211_CHAN_NOHOSTAP),
+		FLAG(IEEE80211_CHAN_11D),
+		FLAG(IEEE80211_CHAN_FHSS),
+		FLAG(IEEE80211_CHAN_PUREG),
+		FLAG(IEEE80211_CHAN_108A),
+		FLAG(IEEE80211_CHAN_108G),
+#undef FLAG
+		{ "ECM",	3,	REQ_ECM },
+		{ "INDOOR",	6,	REQ_INDOOR },
+		{ "OUTDOOR",	7,	REQ_OUTDOOR },
+	};
+	int i;
+
+	for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++)
+		if (len == flags[i].len && iseq(p, flags[i].name))
+			return flags[i].value;
+	warnx("unknown flag \"%.*s\" at line %ld ignored",
+	    len, p, XML_GetCurrentLineNumber(mt->parser));
+	return 0;
+#undef iseq
+}
+
+static void
+end_element(void *data, const char *name)
+{
+#define	iseq(a,b)	(strcasecmp(a,b) == 0)
+	struct mystate *mt;
+	int len;
+	char *p;
+
+	mt = data;
+	sbuf_finish(mt->sbuf[mt->level]);
+	p = sbuf_data(mt->sbuf[mt->level]);
+	len = sbuf_len(mt->sbuf[mt->level]);
+
+	/* <freqband>...</freqband> */
+	if (iseq(name, "freqstart") && mt->freqband != NULL) {
+		mt->freqband->freqStart = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "freqend") && mt->freqband != NULL) {
+		mt->freqband->freqEnd = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "chanwidth") && mt->freqband != NULL) {
+		mt->freqband->chanWidth = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "chansep") && mt->freqband != NULL) {
+		mt->freqband->chanSep = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "flags")) {
+		if (mt->freqband != NULL)
+			mt->freqband->flags |= decode_flag(mt, p, len);
+		else if (mt->netband != NULL)
+			mt->netband->flags |= decode_flag(mt, p, len);
+		else {
+			warnx("flags without freqband or netband at line %ld ignored",
+			    XML_GetCurrentLineNumber(mt->parser));
+		}
+		goto done;
+	}
+
+	/* <rd> ... </rd> */
+	if (iseq(name, "name") && mt->rd != NULL) {
+		mt->rd->name = strdup(p);
+		goto done;
+	}
+	if (iseq(name, "sku") && mt->rd != NULL) {
+		mt->rd->sku = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "netband") && mt->rd != NULL) {
+		mt->curband = NULL;
+		goto done;
+	}
+
+	/* <band> ... </band> */
+	if (iseq(name, "freqband") && mt->netband != NULL) {
+		/* XXX handle inline freqbands */
+		goto done;
+	}
+	if (iseq(name, "maxpower") && mt->netband != NULL) {
+		mt->netband->maxPower = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "maxpowerdfs") && mt->netband != NULL) {
+		mt->netband->maxPowerDFS = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "maxantgain") && mt->netband != NULL) {
+		mt->netband->maxAntGain = strtoul(p, NULL, 0);
+		goto done;
+	}
+
+	/* <country>...</country> */
+	if (iseq(name, "isocc") && mt->country != NULL) {
+		mt->country->code = strtoul(p, NULL, 0);
+		goto done;
+	}
+	if (iseq(name, "name") && mt->country != NULL) {
+		mt->country->name = strdup(p);
+		goto done;
+	}
+
+	if (len != 0) {
+		warnx("unexpected XML token \"%s\" data \"%s\" at line %ld",
+		    name, p, XML_GetCurrentLineNumber(mt->parser));
+		/* XXX goto done? */
+	}
+	/* </freqband> */
+	if (iseq(name, "freqband") && mt->freqband != NULL) {
+		/* XXX must have start/end frequencies */
+		/* XXX must have channel width/sep */
+		mt->freqband = NULL;
+		goto done;
+	}
+	/* </rd> */
+	if (iseq(name, "rd") && mt->rd != NULL) {
+		mt->rd = NULL;
+		goto done;
+	}
+	/* </band> */
+	if (iseq(name, "band") && mt->netband != NULL) {
+		if (mt->netband->band == NULL) {
+			warnx("no freqbands for band at line %ld",
+			   XML_GetCurrentLineNumber(mt->parser));
+		}
+		if (mt->netband->maxPower == 0) {
+			warnx("no maxpower for band at line %ld",
+			   XML_GetCurrentLineNumber(mt->parser));
+		}
+		/* default max power w/ DFS to max power */
+		if (mt->netband->maxPowerDFS == 0)
+			mt->netband->maxPowerDFS = mt->netband->maxPower;
+		mt->netband = NULL;
+		goto done;
+	}
+	/* </netband> */
+	if (iseq(name, "netband") && mt->netband != NULL) {
+		mt->curband = NULL;
+		goto done;
+	}
+	/* </country> */
+	if (iseq(name, "country") && mt->country != NULL) {
+		if (mt->country->code == NO_COUNTRY) {
+			warnx("no ISO cc for country at line %ld",
+			   XML_GetCurrentLineNumber(mt->parser));
+		}
+		if (mt->country->name == NULL) {
+			warnx("no name for country at line %ld",
+			   XML_GetCurrentLineNumber(mt->parser));
+		}
+		if (mt->country->rd == NULL) {
+			warnx("no regdomain reference for country at line %ld",
+			   XML_GetCurrentLineNumber(mt->parser));
+		}
+		mt->country = NULL;
+		goto done;
+	}
+done:
+	sbuf_delete(mt->sbuf[mt->level]);
+	mt->sbuf[mt->level--] = NULL;
+#undef iseq
+}
+
+static void
+char_data(void *data, const XML_Char *s, int len)
+{
+	struct mystate *mt;
+	const char *b, *e;
+
+	mt = data;
+
+	b = s;
+	e = s + len-1;
+	for (; isspace(*b) && b < e; b++)
+		;
+	for (; isspace(*e) && e > b; e++)
+		;
+	if (e != b || (*b != '\0' && !isspace(*b)))
+		sbuf_bcat(mt->sbuf[mt->level], b, e-b+1);
+}
+
+static void *
+findid(struct regdata *rdp, const void *id, int type)
+{
+	struct ident *ip;
+
+	for (ip = rdp->ident; ip->id != NULL; ip++)
+		if (ip->type == type && strcasecmp(ip->id, id) == 0)
+			return ip->p;
+	return NULL;
+}
+
+/*
+ * Parse an regdomain XML configuration and build the internal representation.
+ */
+int
+lib80211_regdomain_readconfig(struct regdata *rdp, const void *p, size_t len)
+{
+	struct mystate *mt;
+	struct regdomain *dp;
+	struct country *cp;
+	struct freqband *fp;
+	struct netband *nb;
+	const void *id;
+	int i, errors;
+
+	memset(rdp, 0, sizeof(struct regdata));
+	mt = calloc(1, sizeof(struct mystate));
+	if (mt == NULL)
+		return ENOMEM;
+	/* parse the XML input */
+	mt->rdp = rdp;
+	mt->parser = XML_ParserCreate(NULL);
+	XML_SetUserData(mt->parser, mt);
+	XML_SetElementHandler(mt->parser, start_element, end_element);
+	XML_SetCharacterDataHandler(mt->parser, char_data);
+	if (XML_Parse(mt->parser, p, len, 1) != XML_STATUS_OK) {
+		warnx("%s: %s at line %ld", __func__,
+		   XML_ErrorString(XML_GetErrorCode(mt->parser)),
+		   XML_GetCurrentLineNumber(mt->parser));
+		return -1;
+	}
+	XML_ParserFree(mt->parser);
+
+	/* setup the identifer table */
+	rdp->ident = calloc(sizeof(struct ident), mt->nident + 1);
+	if (rdp->ident == NULL)
+		return ENOMEM;
+	free(mt);
+
+	errors = 0;
+	i = 0;
+	LIST_FOREACH(dp, &rdp->domains, next) {
+		rdp->ident[i].id = dp->name;
+		rdp->ident[i].p = dp;
+		rdp->ident[i].type = DOMAIN;
+		i++;
+	}
+	LIST_FOREACH(fp, &rdp->freqbands, next) {
+		rdp->ident[i].id = fp->id;
+		rdp->ident[i].p = fp;
+		rdp->ident[i].type = FREQBAND;
+		i++;
+	}
+	LIST_FOREACH(cp, &rdp->countries, next) {
+		rdp->ident[i].id = cp->isoname;
+		rdp->ident[i].p = cp;
+		rdp->ident[i].type = COUNTRY;
+		i++;
+	}
+
+	/* patch references */
+	LIST_FOREACH(dp, &rdp->domains, next) {
+		if (dp->cc != NULL) {
+			id = dp->cc;
+			dp->cc = findid(rdp, id, COUNTRY);
+			if (dp->cc == NULL) {
+				warnx("undefined country \"%s\"",
+				    __DECONST(char *, id));
+				errors++;
+			}
+			free(__DECONST(char *, id));
+		}
+		LIST_FOREACH(nb, &dp->bands_11b, next) {
+			id = findid(rdp, nb->band, FREQBAND);
+			if (id == NULL) {
+				warnx("undefined 11b band \"%s\"",
+				    __DECONST(char *, nb->band));
+				errors++;
+			}
+			nb->band = id;
+		}
+		LIST_FOREACH(nb, &dp->bands_11g, next) {
+			id = findid(rdp, nb->band, FREQBAND);
+			if (id == NULL) {
+				warnx("undefined 11g band \"%s\"",
+				    __DECONST(char *, nb->band));
+				errors++;
+			}
+			nb->band = id;
+		}
+		LIST_FOREACH(nb, &dp->bands_11a, next) {
+			id = findid(rdp, nb->band, FREQBAND);
+			if (id == NULL) {
+				warnx("undefined 11a band \"%s\"",
+				    __DECONST(char *, nb->band));
+				errors++;
+			}
+			nb->band = id;
+		}
+		LIST_FOREACH(nb, &dp->bands_11ng, next) {
+			id = findid(rdp, nb->band, FREQBAND);
+			if (id == NULL) {
+				warnx("undefined 11ng band \"%s\"",
+				    __DECONST(char *, nb->band));
+				errors++;
+			}
+			nb->band = id;
+		}
+		LIST_FOREACH(nb, &dp->bands_11na, next) {
+			id = findid(rdp, nb->band, FREQBAND);
+			if (id == NULL) {
+				warnx("undefined 11na band \"%s\"",
+				    __DECONST(char *, nb->band));
+				errors++;
+			}
+			nb->band = id;
+		}
+	}
+	LIST_FOREACH(cp, &rdp->countries, next) {
+		id = cp->rd;
+		cp->rd = findid(rdp, id, DOMAIN);
+		if (cp->rd == NULL) {
+			warnx("undefined country \"%s\"",
+			    __DECONST(char *, id));
+			errors++;
+		}
+		free(__DECONST(char *, id));
+	}
+
+	return errors ? EINVAL : 0;
+}
+
+static void
+cleanup_bands(netband_head *head)
+{
+	struct netband *nb;
+
+	for (;;) {
+		nb = LIST_FIRST(head);
+		if (nb == NULL)
+			break;
+		free(nb);
+	}
+}
+
+/*
+ * Cleanup state/resources for a previously parsed regdomain database.
+ */
+void
+lib80211_regdomain_cleanup(struct regdata *rdp)
+{
+
+	free(rdp->ident);
+	rdp->ident = NULL;
+	for (;;) {
+		struct regdomain *dp = LIST_FIRST(&rdp->domains);
+		if (dp == NULL)
+			break;
+		LIST_REMOVE(dp, next);
+		cleanup_bands(&dp->bands_11b);
+		cleanup_bands(&dp->bands_11g);
+		cleanup_bands(&dp->bands_11a);
+		cleanup_bands(&dp->bands_11ng);
+		cleanup_bands(&dp->bands_11na);
+		if (dp->name != NULL)
+			free(__DECONST(char *, dp->name));
+	}
+	for (;;) {
+		struct country *cp = LIST_FIRST(&rdp->countries);
+		if (cp == NULL)
+			break;
+		LIST_REMOVE(cp, next);
+		if (cp->name != NULL)
+			free(__DECONST(char *, cp->name));
+		free(cp);
+	}
+	for (;;) {
+		struct freqband *fp = LIST_FIRST(&rdp->freqbands);
+		if (fp == NULL)
+			break;
+		LIST_REMOVE(fp, next);
+		free(fp);
+	}
+}
+
+struct regdata *
+lib80211_alloc_regdata(void)
+{
+	struct regdata *rdp;
+	struct stat sb;
+	void *xml;
+	int fd;
+
+	rdp = calloc(1, sizeof(struct regdata));
+
+	fd = open(_PATH_REGDOMAIN, O_RDONLY);
+	if (fd < 0) {
+#ifdef DEBUG
+		warn("%s: open(%s)", __func__, _PATH_REGDOMAIN);
+#endif
+		free(rdp);
+		return NULL;
+	}
+	if (fstat(fd, &sb) < 0) {
+#ifdef DEBUG
+		warn("%s: fstat(%s)", __func__, _PATH_REGDOMAIN);
+#endif
+		close(fd);
+		free(rdp);
+		return NULL;
+	}
+	xml = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (xml == MAP_FAILED) {
+#ifdef DEBUG
+		warn("%s: mmap", __func__);
+#endif
+		close(fd);
+		free(rdp);
+		return NULL;
+	}
+	if (lib80211_regdomain_readconfig(rdp, xml, sb.st_size) != 0) {
+#ifdef DEBUG
+		warn("%s: error reading regulatory database", __func__);
+#endif
+		munmap(xml, sb.st_size);
+		close(fd);
+		free(rdp);
+		return NULL;
+	}
+	munmap(xml, sb.st_size);
+	close(fd);
+
+	return rdp;
+}
+
+void
+lib80211_free_regdata(struct regdata *rdp)
+{
+	lib80211_regdomain_cleanup(rdp);
+	free(rdp);
+}
+
+/*
+ * Lookup a regdomain by SKU.
+ */
+const struct regdomain *
+lib80211_regdomain_findbysku(const struct regdata *rdp, enum RegdomainCode sku)
+{
+	const struct regdomain *dp;
+
+	LIST_FOREACH(dp, &rdp->domains, next) {
+		if (dp->sku == sku)
+			return dp;
+	}
+	return NULL;
+}
+
+/*
+ * Lookup a regdomain by name.
+ */
+const struct regdomain *
+lib80211_regdomain_findbyname(const struct regdata *rdp, const char *name)
+{
+	const struct regdomain *dp;
+
+	LIST_FOREACH(dp, &rdp->domains, next) {
+		if (strcasecmp(dp->name, name) == 0)
+			return dp;
+	}
+	return NULL;
+}
+
+/*
+ * Lookup a country by ISO country code.
+ */
+const struct country *
+lib80211_country_findbycc(const struct regdata *rdp, enum ISOCountryCode cc)
+{
+	const struct country *cp;
+
+	LIST_FOREACH(cp, &rdp->countries, next) {
+		if (cp->code == cc)
+			return cp;
+	}
+	return NULL;
+}
+
+/*
+ * Lookup a country by ISO/long name.
+ */
+const struct country *
+lib80211_country_findbyname(const struct regdata *rdp, const char *name)
+{
+	const struct country *cp;
+	int len;
+
+	len = strlen(name);
+	LIST_FOREACH(cp, &rdp->countries, next) {
+		if (strcasecmp(cp->isoname, name) == 0)
+			return cp;
+	}
+	LIST_FOREACH(cp, &rdp->countries, next) {
+		if (strncasecmp(cp->name, name, len) == 0)
+			return cp;
+	}
+	return NULL;
+}
diff --git a/freebsd-userspace/commands/sbin/ifconfig/regdomain.h b/freebsd-userspace/commands/sbin/ifconfig/regdomain.h
new file mode 100644
index 0000000..8158875
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/regdomain.h
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
+ * 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 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _LIB80211_H_
+#define _LIB80211_H_
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+
+#ifdef __rtems__
+#include <freebsd/net80211/ieee80211_regdomain.h>
+#else
+#include <net80211/ieee80211_regdomain.h>
+#endif
+
+
+__BEGIN_DECLS
+
+struct freqband {
+	uint16_t	freqStart;	/* starting frequency (MHz) */
+	uint16_t	freqEnd;	/* ending frequency (MHz) */
+	uint8_t		chanWidth;	/* channel width (MHz) */
+	uint8_t		chanSep;	/* channel sepaaration (MHz) */
+	uint32_t	flags;		/* common operational constraints */
+
+	const void	*id;
+	LIST_ENTRY(freqband) next;
+};
+
+/* private flags, don't pass to os */
+#define	REQ_ECM		0x1		/* enable if ECM set */
+#define	REQ_INDOOR	0x2		/* enable only for indoor operation */
+#define	REQ_OUTDOOR	0x4		/* enable only for outdoor operation */
+
+#define	REQ_FLAGS	(REQ_ECM|REQ_INDOOR|REQ_OUTDOOR)
+
+struct netband {
+	const struct freqband *band;	/* channel list description */
+	uint8_t		maxPower;	/* regulatory cap on tx power (dBm) */
+	uint8_t		maxPowerDFS;	/* regulatory cap w/ DFS (dBm) */
+	uint8_t		maxAntGain;	/* max allowed antenna gain (.5 dBm) */
+	uint32_t	flags;		/* net80211 channel flags */
+
+	LIST_ENTRY(netband) next;
+};
+typedef LIST_HEAD(, netband) netband_head;
+
+struct country;
+
+struct regdomain {
+	enum RegdomainCode	sku;	/* regdomain code/SKU */
+	const char		*name;	/* printable name */ 
+	const struct country	*cc;	/* country code for 1-1/default map */
+
+	netband_head	 bands_11b;	/* 11b operation */
+	netband_head	 bands_11g;	/* 11g operation */
+	netband_head	 bands_11a;	/* 11a operation */
+	netband_head	 bands_11ng;/* 11ng operation */
+	netband_head	 bands_11na;/* 11na operation */
+
+	LIST_ENTRY(regdomain)	next;
+};
+
+struct country {
+	enum ISOCountryCode	code;	   
+#define	NO_COUNTRY	0xffff
+	const struct regdomain	*rd;
+	const char*		isoname;
+	const char*		name;
+
+	LIST_ENTRY(country)	next;
+};
+
+struct ident;
+
+struct regdata {
+	LIST_HEAD(, country)	countries;	/* country code table */
+	LIST_HEAD(, regdomain)	domains;	/* regulatory domains */
+	LIST_HEAD(, freqband)	freqbands;	/* frequency band table */
+	struct ident		*ident;		/* identifier table */
+};
+
+#define	_PATH_REGDOMAIN	"/etc/regdomain.xml"
+
+struct regdata *lib80211_alloc_regdata(void);
+void	lib80211_free_regdata(struct regdata *);
+
+int	lib80211_regdomain_readconfig(struct regdata *, const void *, size_t);
+void	lib80211_regdomain_cleanup(struct regdata *);
+
+const struct regdomain *lib80211_regdomain_findbysku(const struct regdata *,
+	enum RegdomainCode);
+const struct regdomain *lib80211_regdomain_findbyname(const struct regdata *,
+	const char *);
+
+const struct country *lib80211_country_findbycc(const struct regdata *,
+	enum ISOCountryCode);
+const struct country *lib80211_country_findbyname(const struct regdata *,
+	const char *);
+
+__END_DECLS
+
+#endif /* _LIB80211_H_ */
diff --git a/freebsd-userspace/from-freebsd.sh b/freebsd-userspace/from-freebsd.sh
index a56a107..e2fb85a 100755
--- a/freebsd-userspace/from-freebsd.sh
+++ b/freebsd-userspace/from-freebsd.sh
@@ -260,6 +260,7 @@ netinet/udp.h
 sys/socket.h
 sys/socketvar.h
 sys/sysctl.h
+sys/mman.h
 EOF
 
 
diff --git a/freebsd-userspace/include/sys/mman.h b/freebsd-userspace/include/sys/mman.h
new file mode 100644
index 0000000..2d90a14
--- /dev/null
+++ b/freebsd-userspace/include/sys/mman.h
@@ -0,0 +1,3 @@
+#include <freebsd/bsd.h>
+#include <freebsd/sys/mman.h>
+




More information about the vc mailing list