summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJennifer Averett <jennifer.averett@oarcorp.com>2012-09-07 13:16:22 -0500
committerJennifer Averett <jennifer.averett@oarcorp.com>2012-09-07 13:16:22 -0500
commitebbe3cc71f18159cf021192241a2a7a397fff4f8 (patch)
tree082e6ffb46b3526ca399ef8d761a188793ce21cc
parentnetstat: New command - Almost completely compiles (diff)
downloadrtems-libbsd-ebbe3cc71f18159cf021192241a2a7a397fff4f8.tar.bz2
Added the ifconfig command.
-rw-r--r--freebsd-userspace/Makefile29
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/af_atalk.c182
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/af_inet.c213
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/af_inet6.c556
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/af_ipx.c122
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/af_link.c133
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/af_nd6.c238
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifbridge.c767
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifcarp.c204
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifclone.c198
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifconfig.82555
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifconfig.c1185
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifconfig.h154
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifgif.c138
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifgre.c102
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifgroup.c186
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifieee80211.c5295
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/iflagg.c198
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifmac.c125
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifmedia.c844
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifpfsync.c220
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/ifvlan.c210
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/regdomain.c705
-rw-r--r--freebsd-userspace/commands/sbin/ifconfig/regdomain.h126
-rwxr-xr-xfreebsd-userspace/from-freebsd.sh1
-rw-r--r--freebsd-userspace/include/sys/mman.h3
26 files changed, 14689 insertions, 0 deletions
diff --git a/freebsd-userspace/Makefile b/freebsd-userspace/Makefile
index 8e5cc2f9..8e8adee2 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 00000000..c50e0fd1
--- /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 00000000..65488a35
--- /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 00000000..c09c778c
--- /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 00000000..c7b718aa
--- /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 00000000..2de85045
--- /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 00000000..74820732
--- /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 00000000..049a0e7c
--- /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 00000000..6c8c5a1b
--- /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 00000000..3dc5a37f
--- /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 00000000..eaab8fa4
--- /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 00000000..f0c77d11
--- /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 00000000..a624f602
--- /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 00000000..d23b384b
--- /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 00000000..58d5bcf5
--- /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 00000000..9eaac3b6
--- /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 00000000..57713ca4
--- /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) &params;
+ 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 00000000..4204d929
--- /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 00000000..31d40b13
--- /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 00000000..ebca67de
--- /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 00000000..886a75e6
--- /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 00000000..8ec3766f
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/ifconfig/ifvlan.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@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) &params;
+ }
+ 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) &params;
+ 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 00000000..41402895
--- /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 00000000..81588752
--- /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 a56a1075..e2fb85aa 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 00000000..2d90a14d
--- /dev/null
+++ b/freebsd-userspace/include/sys/mman.h
@@ -0,0 +1,3 @@
+#include <freebsd/bsd.h>
+#include <freebsd/sys/mman.h>
+