./sbin/fsck_ext2fs minix-base
./sbin/fsck_mfs minix-base
./sbin/halt minix-base
+./sbin/ifconfig minix-base
./sbin/init minix-base
./sbin/minix-service minix-base
./sbin/mkfs.mfs minix-base
./usr/libdata/debug/sbin/fsck.debug minix-debug debug
./usr/libdata/debug/sbin/fsck_ext2fs.debug minix-debug debug
./usr/libdata/debug/sbin/fsck_mfs.debug minix-debug debug
+./usr/libdata/debug/sbin/ifconfig.debug minix-debug debug
./usr/libdata/debug/sbin/init.debug minix-debug debug
./usr/libdata/debug/sbin/minix-service.debug minix-debug debug
./usr/libdata/debug/sbin/mknod.debug minix-debug debug
./usr/man/man8/halt.8 minix-man
./usr/man/man8/httpd.8 minix-man obsolete
./usr/man/man8/i2cscan.8 minix-man
-./usr/man/man8/ifconfig.8 minix-man obsolete
+./usr/man/man8/ifconfig.8 minix-man
./usr/man/man8/in.httpd.8 minix-man obsolete
./usr/man/man8/inet.8 minix-man obsolete
./usr/man/man8/init.8 minix-man
SUBDIR= \
chown \
- fsck init \
+ fsck ifconfig init \
mknod nologin \
ping \
reboot rcorder \
--- /dev/null
+# $NetBSD: Makefile,v 1.56 2015/05/19 08:14:38 ozaki-r Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+# when making a change to this file, please check if the change is
+# also needed for src/distrib/utils/x_ifconfig.
+# such stuff should be into Makefile.inc.
+
+.include <bsd.own.mk>
+
+RUMPPRG=ifconfig
+MAN= ifconfig.8
+
+#DBG+=-g
+SRCS= af_atalk.c af_link.c carp.c
+.if (${USE_INET6} != "no")
+CPPFLAGS+= -DINET6
+SRCS+= af_inet6.c
+.endif
+
+.include "Makefile.inc"
+
+.PATH: ${.CURDIR}/../../lib/libc/net
+RUMPSRCS= getifaddrs.c getnameinfo.c if_indextoname.c
+.if (${MKRUMP} != "no")
+CPPFLAGS+= -DRUMP_ACTION
+.endif
+
+.ifdef SMALLPROG
+CPPFLAGS+=-DSMALL
+.endif
+
+CPPFLAGS+=-I${NETBSDSRCDIR}/sys/dist/pf/
+SRCS+= pfsync.c
+
+.if ${MACHINE_ARCH} == "m68000"
+# XXX workaround for gcc -O1 bug (PR bin/40036 and toolchain/40066)
+COPTS.ifconfig.c+= -fno-loop-optimize
+.endif
+
+.include <bsd.prog.mk>
--- /dev/null
+# $NetBSD: Makefile.inc,v 1.9 2012/10/31 10:17:34 msaitoh Exp $
+
+# shared stuff with src/distrib/utils/x_ifconfig for install media.
+# stuff not required by install media should be into Makefile.
+
+DPADD+=${LIBUTIL}
+DPADD+=${LIBPROP}
+LDADD+=-lutil
+LDADD+=-lprop
+
+INCS+=af_inetany.h env.h extern.h media.h parse.h util.h
+SRCS+= af_inet.c
+SRCS+= af_inetany.c
+#SRCS+= agr.c
+SRCS+= env.c
+SRCS+= ether.c
+SRCS+= ieee80211.c
+SRCS+= ifconfig.c
+SRCS+= media.c
+SRCS+= parse.c
+SRCS+= tunnel.c
+SRCS+= util.c
+#SRCS+= vlan.c
--- /dev/null
+/* $NetBSD: af_atalk.c,v 1.19 2013/10/19 00:35:30 christos Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: af_atalk.c,v 1.19 2013/10/19 00:35:30 christos Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netatalk/at.h>
+
+#include <netdb.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "af_inetany.h"
+#include "parse.h"
+#include "extern.h"
+#include "prog_ops.h"
+
+#ifndef satocsat
+#define satocsat(__sa) ((const struct sockaddr_at *)(__sa))
+#endif
+
+static void at_status(prop_dictionary_t, prop_dictionary_t, bool);
+static void at_commit_address(prop_dictionary_t, prop_dictionary_t);
+
+static void at_constructor(void) __attribute__((constructor));
+
+static struct afswtch ataf = {
+ .af_name = "atalk", .af_af = AF_APPLETALK, .af_status = at_status,
+ .af_addr_commit = at_commit_address
+};
+struct pinteger phase = PINTEGER_INITIALIZER1(&phase, "phase",
+ 1, 2, 10, NULL, "phase", &command_root.pb_parser);
+
+struct pstr parse_range = PSTR_INITIALIZER(&range, "range", NULL, "range",
+ &command_root.pb_parser);
+
+static const struct kwinst atalkkw[] = {
+ {.k_word = "phase", .k_nextparser = &phase.pi_parser}
+ , {.k_word = "range", .k_nextparser = &parse_range.ps_parser}
+};
+
+struct pkw atalk = PKW_INITIALIZER(&atalk, "AppleTalk", NULL, NULL,
+ atalkkw, __arraycount(atalkkw), NULL);
+
+static cmdloop_branch_t branch;
+
+static void
+setatrange_impl(prop_dictionary_t env, prop_dictionary_t oenv,
+ struct netrange *nr)
+{
+ char range[24];
+ u_short first = 123, last = 123;
+
+ if (getargstr(env, "range", range, sizeof(range)) == -1)
+ return;
+
+ if (sscanf(range, "%hu-%hu", &first, &last) != 2 ||
+ first == 0 || last == 0 || first > last)
+ errx(EXIT_FAILURE, "%s: illegal net range: %u-%u", range,
+ first, last);
+ nr->nr_firstnet = htons(first);
+ nr->nr_lastnet = htons(last);
+}
+
+static void
+at_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifreq ifr;
+ struct ifaliasreq ifra __attribute__((aligned(4)));
+ struct afparam atparam = {
+ .req = BUFPARAM(ifra)
+ , .dgreq = BUFPARAM(ifr)
+ , .name = {
+ {.buf = ifr.ifr_name,
+ .buflen = sizeof(ifr.ifr_name)}
+ , {.buf = ifra.ifra_name,
+ .buflen = sizeof(ifra.ifra_name)}
+ }
+ , .dgaddr = BUFPARAM(ifr.ifr_addr)
+ , .addr = BUFPARAM(ifra.ifra_addr)
+ , .dst = BUFPARAM(ifra.ifra_dstaddr)
+ , .brd = BUFPARAM(ifra.ifra_broadaddr)
+ , .mask = BUFPARAM(ifra.ifra_mask)
+ , .aifaddr = IFADDR_PARAM(SIOCAIFADDR)
+ , .difaddr = IFADDR_PARAM(SIOCDIFADDR)
+ , .gifaddr = IFADDR_PARAM(SIOCGIFADDR)
+ , .defmask = {.buf = NULL, .buflen = 0}
+ };
+ struct netrange nr = {.nr_phase = 2}; /* AppleTalk net range */
+ prop_data_t d, d0;
+ prop_dictionary_t ienv;
+ struct paddr_prefix *addr;
+ struct sockaddr_at *sat;
+
+ if ((d0 = (prop_data_t)prop_dictionary_get(env, "address")) == NULL)
+ return;
+
+ addr = prop_data_data(d0);
+
+ sat = (struct sockaddr_at *)&addr->pfx_addr;
+
+ (void)prop_dictionary_get_uint8(env, "phase", &nr.nr_phase);
+ /* Default range of one */
+ nr.nr_firstnet = nr.nr_lastnet = sat->sat_addr.s_net;
+ setatrange_impl(env, oenv, &nr);
+
+ if (ntohs(nr.nr_firstnet) > ntohs(sat->sat_addr.s_net) ||
+ ntohs(nr.nr_lastnet) < ntohs(sat->sat_addr.s_net))
+ errx(EXIT_FAILURE, "AppleTalk address is not in range");
+ memcpy(&sat->sat_zero, &nr, sizeof(nr));
+
+ /* Copy the new address to a temporary input environment */
+
+ d = prop_data_create_data_nocopy(addr, paddr_prefix_size(addr));
+ ienv = prop_dictionary_copy_mutable(env);
+
+ if (d == NULL)
+ err(EXIT_FAILURE, "%s: prop_data_create_data", __func__);
+ if (ienv == NULL)
+ err(EXIT_FAILURE, "%s: prop_dictionary_copy_mutable", __func__);
+
+ if (!prop_dictionary_set(ienv, "address", (prop_object_t)d))
+ err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
+
+ /* copy to output environment for good measure */
+ if (!prop_dictionary_set(oenv, "address", (prop_object_t)d))
+ err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
+
+ prop_object_release((prop_object_t)d);
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&ifra, 0, sizeof(ifra));
+ commit_address(ienv, oenv, &atparam);
+
+ /* release temporary input environment */
+ prop_object_release((prop_object_t)ienv);
+}
+
+static void
+sat_print1(const char *prefix, const struct sockaddr *sa)
+{
+ char buf[40];
+
+ (void)getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, 0);
+
+ printf("%s%s", prefix, buf);
+}
+
+static void
+at_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
+{
+ struct sockaddr_at *sat;
+ struct ifreq ifr;
+ int s;
+ const char *ifname;
+ unsigned short flags;
+
+ if ((s = getsock(AF_APPLETALK)) == -1) {
+ if (errno == EAFNOSUPPORT)
+ return;
+ err(EXIT_FAILURE, "getsock");
+ }
+ if ((ifname = getifinfo(env, oenv, &flags)) == NULL)
+ err(EXIT_FAILURE, "%s: getifinfo", __func__);
+
+ memset(&ifr, 0, sizeof(ifr));
+ estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_addr.sa_family = AF_APPLETALK;
+ if (prog_ioctl(s, SIOCGIFADDR, &ifr) != -1)
+ ;
+ else if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
+ if (!force)
+ return;
+ memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
+ } else
+ warn("SIOCGIFADDR");
+ sat = (struct sockaddr_at *)&ifr.ifr_addr;
+
+ sat_print1("\tatalk ", &ifr.ifr_addr);
+
+ if (flags & IFF_POINTOPOINT) {
+ estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (prog_ioctl(s, SIOCGIFDSTADDR, &ifr) == -1) {
+ if (errno == EADDRNOTAVAIL)
+ memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
+ else
+ warn("SIOCGIFDSTADDR");
+ }
+ sat_print1(" --> ", &ifr.ifr_dstaddr);
+ }
+ if (flags & IFF_BROADCAST) {
+ /* note RTAX_BRD overlap with IFF_POINTOPOINT */
+ /* note Appletalk broadcast is fixed. */
+ printf(" broadcast %u.%u", ntohs(sat->sat_addr.s_net),
+ ATADDR_BCAST);
+ }
+ printf("\n");
+}
+
+static void
+at_constructor(void)
+{
+ register_family(&ataf);
+ cmdloop_branch_init(&branch, &atalk.pk_parser);
+ register_cmdloop_branch(&branch);
+}
--- /dev/null
+/* $NetBSD: af_inet.c,v 1.17 2015/05/12 14:05:29 roy Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: af_inet.c,v 1.17 2015/05/12 14:05:29 roy Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "af_inetany.h"
+#include "prog_ops.h"
+
+static void in_constructor(void) __attribute__((constructor));
+static void in_status(prop_dictionary_t, prop_dictionary_t, bool);
+static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
+static bool in_addr_tentative(struct ifaddrs *ifa);
+static void in_alias(const char *, prop_dictionary_t, prop_dictionary_t,
+ struct in_aliasreq *);
+
+static struct afswtch af = {
+ .af_name = "inet", .af_af = AF_INET, .af_status = in_status,
+ .af_addr_commit = in_commit_address,
+ .af_addr_tentative = in_addr_tentative
+};
+
+static void
+in_alias(const char *ifname, prop_dictionary_t env, prop_dictionary_t oenv,
+ struct in_aliasreq *creq)
+{
+ struct ifreq ifr;
+ bool alias;
+ int s;
+ unsigned short flags;
+ struct in_aliasreq in_addreq;
+ const struct sockaddr_in * const asin = &in_addreq.ifra_addr;
+ const struct sockaddr_in * const dsin = &in_addreq.ifra_dstaddr;
+ const struct sockaddr_in * const bsin = &in_addreq.ifra_broadaddr;
+ char hbuf[NI_MAXHOST];
+ const int niflag = Nflag ? 0 : NI_NUMERICHOST;
+
+ if (lflag)
+ return;
+
+ alias = true;
+
+ /* Get the non-alias address for this interface. */
+ if ((s = getsock(AF_INET)) == -1) {
+ if (errno == EAFNOSUPPORT)
+ return;
+ err(EXIT_FAILURE, "socket");
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (prog_ioctl(s, SIOCGIFADDR, &ifr) == -1) {
+ if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
+ return;
+ warn("SIOCGIFADDR");
+ }
+ /* If creq and ifr are the same address, this is not an alias. */
+ if (memcmp(&ifr.ifr_addr, &creq->ifra_addr, sizeof(ifr.ifr_addr)) == 0)
+ alias = false;
+ in_addreq = *creq;
+ if (prog_ioctl(s, SIOCGIFALIAS, &in_addreq) == -1) {
+ if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
+ return;
+ } else
+ warn("SIOCGIFALIAS");
+ }
+
+ if (getnameinfo((const struct sockaddr *)asin, asin->sin_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag))
+ strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
+ printf("\tinet %s%s", alias ? "alias " : "", hbuf);
+
+ if (getifflags(env, oenv, &flags) == -1)
+ err(EXIT_FAILURE, "%s: getifflags", __func__);
+
+ if (flags & IFF_POINTOPOINT) {
+ if (getnameinfo((const struct sockaddr *)dsin, dsin->sin_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag))
+ strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
+ printf(" -> %s", hbuf);
+ }
+
+ printf(" netmask 0x%x", ntohl(in_addreq.ifra_mask.sin_addr.s_addr));
+
+ if (flags & IFF_BROADCAST) {
+ if (getnameinfo((const struct sockaddr *)bsin, bsin->sin_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag))
+ strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
+ printf(" broadcast %s", hbuf);
+ }
+
+#ifdef IN_IFF_TENTATIVE
+ memcpy(&ifr.ifr_addr, &creq->ifra_addr, creq->ifra_addr.sin_len);
+ if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1) {
+ if (errno != EADDRNOTAVAIL)
+ warn("SIOCGIFAFLAG_IN");
+ } else {
+ if (ifr.ifr_addrflags & IN_IFF_TENTATIVE)
+ printf(" tentative");
+ if (ifr.ifr_addrflags & IN_IFF_DUPLICATED)
+ printf(" duplicated");
+ if (ifr.ifr_addrflags & IN_IFF_DETACHED)
+ printf(" detached");
+ }
+#endif
+}
+
+static void
+in_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct in_aliasreq ifra;
+ bool printprefs = false;
+ const char *ifname;
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "%s: getifname", __func__);
+
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+
+ printprefs = ifa_any_preferences(ifname, ifap, AF_INET);
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ if (sizeof(ifra.ifra_addr) < ifa->ifa_addr->sa_len)
+ continue;
+
+ memset(&ifra, 0, sizeof(ifra));
+ estrlcpy(ifra.ifra_name, ifa->ifa_name, sizeof(ifra.ifra_name));
+ memcpy(&ifra.ifra_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
+ in_alias(ifa->ifa_name, env, oenv, &ifra);
+ if (printprefs)
+ ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
+ printf("\n");
+ }
+ freeifaddrs(ifap);
+}
+
+static void
+in_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifreq in_ifr;
+ struct in_aliasreq in_ifra;
+ struct afparam inparam = {
+ .req = BUFPARAM(in_ifra)
+ , .dgreq = BUFPARAM(in_ifr)
+ , .name = {
+ {.buf = in_ifr.ifr_name,
+ .buflen = sizeof(in_ifr.ifr_name)}
+ , {.buf = in_ifra.ifra_name,
+ .buflen = sizeof(in_ifra.ifra_name)}
+ }
+ , .dgaddr = BUFPARAM(in_ifr.ifr_addr)
+ , .addr = BUFPARAM(in_ifra.ifra_addr)
+ , .dst = BUFPARAM(in_ifra.ifra_dstaddr)
+ , .brd = BUFPARAM(in_ifra.ifra_broadaddr)
+ , .mask = BUFPARAM(in_ifra.ifra_mask)
+ , .aifaddr = IFADDR_PARAM(SIOCAIFADDR)
+ , .difaddr = IFADDR_PARAM(SIOCDIFADDR)
+ , .gifaddr = IFADDR_PARAM(SIOCGIFADDR)
+ , .defmask = {.buf = NULL, .buflen = 0}
+ };
+ memset(&in_ifr, 0, sizeof(in_ifr));
+ memset(&in_ifra, 0, sizeof(in_ifra));
+ commit_address(env, oenv, &inparam);
+}
+
+static bool
+in_addr_tentative(struct ifaddrs *ifa)
+{
+#ifdef IN_IFF_TENTATIVE
+ int s;
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+ ifr.ifr_addr = *ifa->ifa_addr;
+ if ((s = getsock(AF_INET)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+ if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1)
+ err(EXIT_FAILURE, "SIOCGIFAFLAG_IN");
+ return ifr.ifr_addrflags & IN_IFF_TENTATIVE ? true : false;
+#else
+ return false;
+#endif
+}
+
+static void
+in_constructor(void)
+{
+ register_family(&af);
+}
--- /dev/null
+/* $NetBSD: af_inet6.c,v 1.33 2015/05/12 14:05:29 roy Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: af_inet6.c,v 1.33 2015/05/12 14:05:29 roy Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet6/nd6.h>
+
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "parse.h"
+#include "extern.h"
+#include "af_inetany.h"
+#include "prog_ops.h"
+
+static void in6_constructor(void) __attribute__((constructor));
+static void in6_alias(const char *, prop_dictionary_t, prop_dictionary_t,
+ struct in6_ifreq *);
+static void in6_commit_address(prop_dictionary_t, prop_dictionary_t);
+
+static int setia6eui64_impl(prop_dictionary_t, struct in6_aliasreq *);
+static int setia6flags_impl(prop_dictionary_t, struct in6_aliasreq *);
+static int setia6pltime_impl(prop_dictionary_t, struct in6_aliasreq *);
+static int setia6vltime_impl(prop_dictionary_t, struct in6_aliasreq *);
+
+static int setia6lifetime(prop_dictionary_t, int64_t, time_t *, uint32_t *);
+
+static void in6_status(prop_dictionary_t, prop_dictionary_t, bool);
+static bool in6_addr_tentative(struct ifaddrs *ifa);
+
+static struct usage_func usage;
+static cmdloop_branch_t branch[2];
+
+static const struct kwinst ia6flagskw[] = {
+ IFKW("anycast", IN6_IFF_ANYCAST)
+ , IFKW("deprecated", IN6_IFF_DEPRECATED)
+};
+
+static struct pinteger parse_pltime = PINTEGER_INITIALIZER(&parse_pltime,
+ "pltime", 0, NULL, "pltime", &command_root.pb_parser);
+
+static struct pinteger parse_vltime = PINTEGER_INITIALIZER(&parse_vltime,
+ "vltime", 0, NULL, "vltime", &command_root.pb_parser);
+
+static const struct kwinst inet6kw[] = {
+ {.k_word = "pltime", .k_nextparser = &parse_pltime.pi_parser}
+ , {.k_word = "vltime", .k_nextparser = &parse_vltime.pi_parser}
+ , {.k_word = "eui64", .k_key = "eui64", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_nextparser = &command_root.pb_parser}
+};
+
+struct pkw ia6flags = PKW_INITIALIZER(&ia6flags, "ia6flags", NULL,
+ "ia6flag", ia6flagskw, __arraycount(ia6flagskw), &command_root.pb_parser);
+struct pkw inet6 = PKW_INITIALIZER(&inet6, "IPv6 keywords", NULL,
+ NULL, inet6kw, __arraycount(inet6kw), NULL);
+
+static struct afswtch in6af = {
+ .af_name = "inet6", .af_af = AF_INET6, .af_status = in6_status,
+ .af_addr_commit = in6_commit_address,
+ .af_addr_tentative = in6_addr_tentative
+};
+
+static int
+prefix(void *val, int size)
+{
+ u_char *pname = (u_char *)val;
+ int byte, bit, plen = 0;
+
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (pname[byte] != 0xff)
+ break;
+ if (byte == size)
+ return (plen);
+ for (bit = 7; bit != 0; bit--, plen++)
+ if (!(pname[byte] & (1 << bit)))
+ break;
+ for (; bit != 0; bit--)
+ if (pname[byte] & (1 << bit))
+ return(0);
+ byte++;
+ for (; byte < size; byte++)
+ if (pname[byte])
+ return(0);
+ return (plen);
+}
+
+int
+setia6flags_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
+{
+ int64_t ia6flag;
+
+ if (!prop_dictionary_get_int64(env, "ia6flag", &ia6flag)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (ia6flag < 0) {
+ ia6flag = -ia6flag;
+ ifra->ifra_flags &= ~ia6flag;
+ } else
+ ifra->ifra_flags |= ia6flag;
+ return 0;
+}
+
+int
+setia6pltime_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
+{
+ int64_t pltime;
+
+ if (!prop_dictionary_get_int64(env, "pltime", &pltime)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return setia6lifetime(env, pltime,
+ &ifra->ifra_lifetime.ia6t_preferred,
+ &ifra->ifra_lifetime.ia6t_pltime);
+}
+
+int
+setia6vltime_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
+{
+ int64_t vltime;
+
+ if (!prop_dictionary_get_int64(env, "vltime", &vltime)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ return setia6lifetime(env, vltime,
+ &ifra->ifra_lifetime.ia6t_expire,
+ &ifra->ifra_lifetime.ia6t_vltime);
+}
+
+static int
+setia6lifetime(prop_dictionary_t env, int64_t val, time_t *timep,
+ uint32_t *ivalp)
+{
+ time_t t;
+ int af;
+
+ if ((af = getaf(env)) == -1 || af != AF_INET6) {
+ errx(EXIT_FAILURE,
+ "inet6 address lifetime not allowed for the AF");
+ }
+
+ t = time(NULL);
+ *timep = t + val;
+ *ivalp = val;
+ return 0;
+}
+
+int
+setia6eui64_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
+{
+ char buf[2][80];
+ struct ifaddrs *ifap, *ifa;
+ const struct sockaddr_in6 *sin6 = NULL;
+ const struct in6_addr *lladdr = NULL;
+ struct in6_addr *in6;
+ const char *ifname;
+ bool doit = false;
+ int af;
+
+ if (!prop_dictionary_get_bool(env, "eui64", &doit) || !doit) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if ((ifname = getifname(env)) == NULL)
+ return -1;
+
+ af = getaf(env);
+ if (af != AF_INET6) {
+ errx(EXIT_FAILURE,
+ "eui64 address modifier not allowed for the AF");
+ }
+ in6 = &ifra->ifra_addr.sin6_addr;
+ if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) {
+ union {
+ struct sockaddr_in6 sin6;
+ struct sockaddr sa;
+ } any = {.sin6 = {.sin6_family = AF_INET6}};
+ memcpy(&any.sin6.sin6_addr, &in6addr_any,
+ sizeof(any.sin6.sin6_addr));
+ (void)sockaddr_snprintf(buf[0], sizeof(buf[0]), "%a%%S",
+ &any.sa);
+ (void)sockaddr_snprintf(buf[1], sizeof(buf[1]), "%a%%S",
+ (const struct sockaddr *)&ifra->ifra_addr);
+ errx(EXIT_FAILURE, "interface index is already filled, %s | %s",
+ buf[0], buf[1]);
+ }
+ 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, ifname) == 0) {
+ sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ lladdr = &sin6->sin6_addr;
+ break;
+ }
+ }
+ }
+ if (lladdr == NULL)
+ errx(EXIT_FAILURE, "could not determine link local address");
+
+ memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
+
+ freeifaddrs(ifap);
+ return 0;
+}
+
+/* XXX not really an alias */
+void
+in6_alias(const char *ifname, prop_dictionary_t env, prop_dictionary_t oenv,
+ struct in6_ifreq *creq)
+{
+ struct in6_ifreq ifr6;
+ struct sockaddr_in6 *sin6;
+ char hbuf[NI_MAXHOST];
+ u_int32_t scopeid;
+ int s;
+ const int niflag = Nflag ? 0 : NI_NUMERICHOST;
+ unsigned short flags;
+
+ /* Get the non-alias address for this interface. */
+ if ((s = getsock(AF_INET6)) == -1) {
+ if (errno == EAFNOSUPPORT)
+ return;
+ err(EXIT_FAILURE, "socket");
+ }
+
+ sin6 = &creq->ifr_addr;
+
+ inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL);
+ scopeid = sin6->sin6_scope_id;
+ if (getnameinfo((const struct sockaddr *)sin6, sin6->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag))
+ strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
+ printf("\tinet6 %s", hbuf);
+
+ if (getifflags(env, oenv, &flags) == -1)
+ err(EXIT_FAILURE, "%s: getifflags", __func__);
+
+ if (flags & IFF_POINTOPOINT) {
+ ifr6 = *creq;
+ if (prog_ioctl(s, SIOCGIFDSTADDR_IN6, &ifr6) == -1) {
+ if (errno != EADDRNOTAVAIL)
+ warn("SIOCGIFDSTADDR_IN6");
+ memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
+ ifr6.ifr_addr.sin6_family = AF_INET6;
+ ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
+ }
+ sin6 = &ifr6.ifr_addr;
+ inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL);
+ hbuf[0] = '\0';
+ if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag))
+ strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
+ printf(" -> %s", hbuf);
+ }
+
+ ifr6 = *creq;
+ if (prog_ioctl(s, SIOCGIFNETMASK_IN6, &ifr6) == -1) {
+ if (errno != EADDRNOTAVAIL)
+ warn("SIOCGIFNETMASK_IN6");
+ } else {
+ sin6 = &ifr6.ifr_addr;
+ printf(" prefixlen %d", prefix(&sin6->sin6_addr,
+ sizeof(struct in6_addr)));
+ }
+
+ ifr6 = *creq;
+ if (prog_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
+ if (errno != EADDRNOTAVAIL)
+ warn("SIOCGIFAFLAG_IN6");
+ } else {
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
+ printf(" anycast");
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
+ printf(" tentative");
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
+ printf(" duplicated");
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
+ printf(" detached");
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
+ printf(" deprecated");
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
+ printf(" autoconf");
+ if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TEMPORARY)
+ printf(" temporary");
+ }
+
+ if (scopeid)
+ printf(" scopeid 0x%x", scopeid);
+
+ if (get_flag('L')) {
+ struct in6_addrlifetime *lifetime;
+ ifr6 = *creq;
+ lifetime = &ifr6.ifr_ifru.ifru_lifetime;
+ if (prog_ioctl(s, SIOCGIFALIFETIME_IN6, &ifr6) == -1) {
+ if (errno != EADDRNOTAVAIL)
+ warn("SIOCGIFALIFETIME_IN6");
+ } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
+ time_t t = time(NULL);
+ printf(" pltime ");
+ if (lifetime->ia6t_preferred) {
+ printf("%lu",
+ (unsigned long)(lifetime->ia6t_preferred -
+ MIN(t, lifetime->ia6t_preferred)));
+ } else
+ printf("infty");
+
+ printf(" vltime ");
+ if (lifetime->ia6t_expire) {
+ printf("%lu",
+ (unsigned long)(lifetime->ia6t_expire -
+ MIN(t, lifetime->ia6t_expire)));
+ } else
+ printf("infty");
+ }
+ }
+}
+
+static void
+in6_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct in6_ifreq ifr;
+ const char *ifname;
+ bool printprefs = false;
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "%s: getifname", __func__);
+
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ printprefs = ifa_any_preferences(ifname, ifap, AF_INET6);
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
+ continue;
+
+ memset(&ifr, 0, sizeof(ifr));
+ estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+ memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
+ in6_alias(ifname, env, oenv, &ifr);
+ if (printprefs)
+ ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
+ printf("\n");
+ }
+ freeifaddrs(ifap);
+}
+
+static int
+in6_pre_aifaddr(prop_dictionary_t env, const struct afparam *param)
+{
+ struct in6_aliasreq *ifra = param->req.buf;
+
+ setia6eui64_impl(env, ifra);
+ setia6vltime_impl(env, ifra);
+ setia6pltime_impl(env, ifra);
+ setia6flags_impl(env, ifra);
+ inet6_putscopeid(&ifra->ifra_addr, INET6_IS_ADDR_LINKLOCAL);
+ inet6_putscopeid(&ifra->ifra_dstaddr, INET6_IS_ADDR_LINKLOCAL);
+
+ return 0;
+}
+
+static void
+in6_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct in6_ifreq in6_ifr = {
+ .ifr_addr = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(in6_ifr.ifr_addr),
+ .sin6_addr = {
+ .s6_addr =
+ {0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff}
+ }
+ }
+ };
+ static struct sockaddr_in6 in6_defmask = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(in6_defmask),
+ .sin6_addr = {
+ .s6_addr = {0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff}
+ }
+ };
+
+ struct in6_aliasreq in6_ifra = {
+ .ifra_prefixmask = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(in6_ifra.ifra_prefixmask),
+ .sin6_addr = {
+ .s6_addr =
+ {0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff}}},
+ .ifra_lifetime = {
+ .ia6t_pltime = ND6_INFINITE_LIFETIME
+ , .ia6t_vltime = ND6_INFINITE_LIFETIME
+ }
+ };
+ struct afparam in6param = {
+ .req = BUFPARAM(in6_ifra)
+ , .dgreq = BUFPARAM(in6_ifr)
+ , .name = {
+ {.buf = in6_ifr.ifr_name,
+ .buflen = sizeof(in6_ifr.ifr_name)},
+ {.buf = in6_ifra.ifra_name,
+ .buflen = sizeof(in6_ifra.ifra_name)}
+ }
+ , .dgaddr = BUFPARAM(in6_ifr.ifr_addr)
+ , .addr = BUFPARAM(in6_ifra.ifra_addr)
+ , .dst = BUFPARAM(in6_ifra.ifra_dstaddr)
+ , .brd = BUFPARAM(in6_ifra.ifra_broadaddr)
+ , .mask = BUFPARAM(in6_ifra.ifra_prefixmask)
+ , .aifaddr = IFADDR_PARAM(SIOCAIFADDR_IN6)
+ , .difaddr = IFADDR_PARAM(SIOCDIFADDR_IN6)
+ , .gifaddr = IFADDR_PARAM(SIOCGIFADDR_IN6)
+ , .defmask = BUFPARAM(in6_defmask)
+ , .pre_aifaddr = in6_pre_aifaddr
+ };
+ commit_address(env, oenv, &in6param);
+}
+
+static bool
+in6_addr_tentative(struct ifaddrs *ifa)
+{
+ int s;
+ struct in6_ifreq ifr;
+
+ if ((s = getsock(AF_INET6)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+ ifr.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
+ if (prog_ioctl(s, SIOCGIFAFLAG_IN6, &ifr) == -1)
+ err(EXIT_FAILURE, "SIOCGIFAFLAG_IN6");
+ return ifr.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE ? true : false;
+}
+
+static void
+in6_usage(prop_dictionary_t env)
+{
+ fprintf(stderr,
+ "\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
+ "\t[ pltime n ] [ vltime n ] "
+ "[ eui64 ]\n");
+}
+
+static void
+in6_constructor(void)
+{
+ if (register_flag('L') != 0)
+ err(EXIT_FAILURE, __func__);
+ register_family(&in6af);
+ usage_func_init(&usage, in6_usage);
+ register_usage(&usage);
+ cmdloop_branch_init(&branch[0], &ia6flags.pk_parser);
+ cmdloop_branch_init(&branch[1], &inet6.pk_parser);
+ register_cmdloop_branch(&branch[0]);
+ register_cmdloop_branch(&branch[1]);
+}
--- /dev/null
+/* $NetBSD: af_inetany.c,v 1.17 2012/12/30 22:52:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2008 David Young. 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: af_inetany.c,v 1.17 2012/12/30 22:52:35 christos Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "af_inetany.h"
+#include "prog_ops.h"
+
+static void *
+loadbuf(const struct apbuf *b, const struct paddr_prefix *pfx)
+{
+ return memcpy(b->buf, &pfx->pfx_addr,
+ MIN(b->buflen, pfx->pfx_addr.sa_len));
+}
+
+void
+commit_address(prop_dictionary_t env, prop_dictionary_t oenv,
+ const struct afparam *param)
+{
+ const char *ifname;
+ int af, rc, s;
+ bool alias, delete, replace;
+ prop_data_t d;
+ const struct paddr_prefix *addr, *brd, *dst, *mask;
+ unsigned short flags;
+
+ if ((af = getaf(env)) == -1)
+ af = AF_INET;
+
+ if ((s = getsock(af)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "%s: getifname", __func__);
+
+ strlcpy(param->name[0].buf, ifname, param->name[0].buflen);
+ strlcpy(param->name[1].buf, ifname, param->name[1].buflen);
+
+ if ((d = (prop_data_t)prop_dictionary_get(env, "address")) != NULL)
+ addr = prop_data_data_nocopy(d);
+ else if (!prop_dictionary_get_bool(env, "alias", &alias) || alias ||
+ param->gifaddr.cmd == 0)
+ return;
+ else if (prog_ioctl(s, param->gifaddr.cmd, param->dgreq.buf) == -1)
+ err(EXIT_FAILURE, "%s", param->gifaddr.desc);
+ else if (prog_ioctl(s, param->difaddr.cmd, param->dgreq.buf) == -1)
+ err(EXIT_FAILURE, "%s", param->difaddr.desc);
+ else
+ return;
+
+ if ((d = (prop_data_t)prop_dictionary_get(env, "dst")) != NULL)
+ dst = prop_data_data_nocopy(d);
+ else
+ dst = NULL;
+
+ if ((d = (prop_data_t)prop_dictionary_get(env, "netmask")) != NULL)
+ mask = prop_data_data_nocopy(d);
+ else
+ mask = NULL;
+
+ if ((d = (prop_data_t)prop_dictionary_get(env, "broadcast")) != NULL)
+ brd = prop_data_data_nocopy(d);
+ else
+ brd = NULL;
+
+ if (!prop_dictionary_get_bool(env, "alias", &alias)) {
+ delete = false;
+ replace = (param->gifaddr.cmd != 0);
+ } else {
+ replace = false;
+ delete = !alias;
+ }
+
+ loadbuf(¶m->addr, addr);
+
+ /* TBD: read matching ifaddr from kernel, use the netmask as default
+ * TBD: handle preference
+ */
+ if (getifflags(env, oenv, &flags) == -1)
+ err(EXIT_FAILURE, "%s: getifflags", __func__);
+
+ switch (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) {
+ case IFF_BROADCAST:
+ if (brd != NULL)
+ loadbuf(¶m->brd, brd);
+ /*FALLTHROUGH*/
+ case 0:
+ break;
+ case IFF_POINTOPOINT:
+ if (brd != NULL) {
+ errx(EXIT_FAILURE, "%s is not a broadcast interface",
+ ifname);
+ }
+ if (dst != NULL)
+ loadbuf(¶m->dst, dst);
+ break;
+ case IFF_BROADCAST|IFF_POINTOPOINT:
+ errx(EXIT_FAILURE, "unsupported interface flags");
+ }
+ if (param->mask.buf == NULL) {
+ if (mask != NULL)
+ errx(EXIT_FAILURE, "netmask not supported");
+ } else if (mask != NULL)
+ loadbuf(¶m->mask, mask);
+ else if (param->defmask.buf != NULL) {
+ memcpy(param->mask.buf, param->defmask.buf,
+ MIN(param->mask.buflen, param->defmask.buflen));
+ }
+ if (replace) {
+ if (prog_ioctl(s, param->gifaddr.cmd, param->dgreq.buf) == 0) {
+ rc = prog_ioctl(s, param->difaddr.cmd, param->dgreq.buf);
+ if (rc == -1)
+ err(EXIT_FAILURE, "%s", param->difaddr.desc);
+ } else if (errno == EADDRNOTAVAIL)
+ ; /* No address was assigned yet. */
+ else
+ err(EXIT_FAILURE, "%s", param->gifaddr.desc);
+ } else if (delete) {
+ loadbuf(¶m->dgaddr, addr);
+ if (prog_ioctl(s, param->difaddr.cmd, param->dgreq.buf) == -1)
+ err(EXIT_FAILURE, "%s", param->difaddr.desc);
+ return;
+ }
+ if (param->pre_aifaddr != NULL &&
+ (*param->pre_aifaddr)(env, param) == -1)
+ err(EXIT_FAILURE, "pre-%s", param->aifaddr.desc);
+ if (prog_ioctl(s, param->aifaddr.cmd, param->req.buf) == -1)
+ err(EXIT_FAILURE, "%s", param->aifaddr.desc);
+}
--- /dev/null
+/* $NetBSD: af_inetany.h,v 1.4 2008/07/02 07:44:14 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2008 David Young. 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 _IFCONFIG_AF_INETANY_H
+#define _IFCONFIG_AF_INETANY_H
+
+#include <sys/types.h>
+#include <prop/proplib.h>
+
+#define IFADDR_PARAM(__arg) {.cmd = (__arg), .desc = #__arg}
+#define BUFPARAM(__arg) {.buf = &(__arg), .buflen = sizeof(__arg)}
+
+struct apbuf {
+ void *buf;
+ size_t buflen;
+};
+
+struct afparam {
+ struct {
+ char *buf;
+ size_t buflen;
+ } name[2];
+ struct apbuf dgaddr, addr, brd, dst, mask, req, dgreq, defmask,
+ pre_aifaddr_arg;
+ struct {
+ unsigned long cmd;
+ const char *desc;
+ } aifaddr, difaddr, gifaddr;
+ int (*pre_aifaddr)(prop_dictionary_t, const struct afparam *);
+};
+
+void commit_address(prop_dictionary_t, prop_dictionary_t,
+ const struct afparam *);
+
+#endif /* _IFCONFIG_AF_INETANY_H */
--- /dev/null
+/* $NetBSD: af_link.c,v 1.7 2014/01/19 22:31:13 matt Exp $ */
+
+/*-
+ * Copyright (c) 2008 David Young. 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: af_link.c,v 1.7 2014/01/19 22:31:13 matt Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "af_inetany.h"
+
+static void link_status(prop_dictionary_t, prop_dictionary_t, bool);
+static void link_commit_address(prop_dictionary_t, prop_dictionary_t);
+
+static const struct kwinst linkkw[] = {
+ {.k_word = "active", .k_key = "active", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_nextparser = &command_root.pb_parser}
+};
+
+struct pkw link_pkw = PKW_INITIALIZER(&link_pkw, "link", NULL, NULL,
+ linkkw, __arraycount(linkkw), NULL);
+
+static struct afswtch af = {
+ .af_name = "link", .af_af = AF_LINK, .af_status = link_status,
+ .af_addr_commit = link_commit_address
+};
+
+static cmdloop_branch_t branch;
+
+static void link_constructor(void) __attribute__((constructor));
+
+static void
+link_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
+{
+ print_link_addresses(env, false);
+}
+
+static int
+link_pre_aifaddr(prop_dictionary_t env, const struct afparam *param)
+{
+ bool active;
+ struct if_laddrreq *iflr = param->req.buf;
+
+ if (prop_dictionary_get_bool(env, "active", &active) && active)
+ iflr->flags |= IFLR_ACTIVE;
+
+ return 0;
+}
+
+static void
+link_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct if_laddrreq dgreq = {
+ .addr = {
+ .ss_family = AF_LINK,
+ .ss_len = sizeof(dgreq.addr),
+ },
+ };
+ struct if_laddrreq req = {
+ .addr = {
+ .ss_family = AF_LINK,
+ .ss_len = sizeof(req.addr),
+ }
+ };
+ struct afparam linkparam = {
+ .req = BUFPARAM(req)
+ , .dgreq = BUFPARAM(dgreq)
+ , .name = {
+ {.buf = dgreq.iflr_name,
+ .buflen = sizeof(dgreq.iflr_name)},
+ {.buf = req.iflr_name,
+ .buflen = sizeof(req.iflr_name)}
+ }
+ , .dgaddr = BUFPARAM(dgreq.addr)
+ , .addr = BUFPARAM(req.addr)
+ , .aifaddr = IFADDR_PARAM(SIOCALIFADDR)
+ , .difaddr = IFADDR_PARAM(SIOCDLIFADDR)
+ , .gifaddr = IFADDR_PARAM(0)
+ , .pre_aifaddr = link_pre_aifaddr
+ };
+ commit_address(env, oenv, &linkparam);
+}
+
+static void
+link_constructor(void)
+{
+ register_family(&af);
+ cmdloop_branch_init(&branch, &link_pkw.pk_parser);
+ register_cmdloop_branch(&branch);
+}
--- /dev/null
+/* $NetBSD: agr.c,v 1.15 2008/07/15 21:27:58 dyoung Exp $ */
+
+/*-
+ * Copyright (c)2005 YAMAMOTO Takashi,
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if !defined(lint)
+__RCSID("$NetBSD: agr.c,v 1.15 2008/07/15 21:27:58 dyoung Exp $");
+#endif /* !defined(lint) */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/agr/if_agrioctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "parse.h"
+#include "util.h"
+
+static int agrsetport(prop_dictionary_t, prop_dictionary_t);
+static void agr_constructor(void) __attribute__((constructor));
+static int checkifname(prop_dictionary_t);
+static void assertifname(prop_dictionary_t);
+
+static struct piface agrif = PIFACE_INITIALIZER(&agrif, "agr interface",
+ agrsetport, "agrport", &command_root.pb_parser);
+
+static const struct kwinst agrkw[] = {
+ {.k_word = "agrport", .k_type = KW_T_INT, .k_int = AGRCMD_ADDPORT,
+ .k_nextparser = &agrif.pif_parser}
+ , {.k_word = "-agrport", .k_type = KW_T_INT, .k_int = AGRCMD_REMPORT,
+ .k_nextparser = &agrif.pif_parser}
+};
+
+struct pkw agr = PKW_INITIALIZER(&agr, "agr", NULL, "agrcmd",
+ agrkw, __arraycount(agrkw), NULL);
+
+static int
+checkifname(prop_dictionary_t env)
+{
+ const char *ifname;
+
+ if ((ifname = getifname(env)) == NULL)
+ return 1;
+
+ return strncmp(ifname, "agr", 3) != 0 ||
+ !isdigit((unsigned char)ifname[3]);
+}
+
+static void
+assertifname(prop_dictionary_t env)
+{
+ if (checkifname(env))
+ errx(EXIT_FAILURE, "valid only with agr(4) interfaces");
+}
+
+int
+agrsetport(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ char buf[IFNAMSIZ];
+ struct agrreq ar;
+ const char *port;
+ int64_t cmd;
+
+ if (!prop_dictionary_get_int64(env, "agrcmd", &cmd)) {
+ warnx("%s.%d", __func__, __LINE__);
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (!prop_dictionary_get_cstring_nocopy(env, "agrport", &port)) {
+ warnx("%s.%d", __func__, __LINE__);
+ errno = ENOENT;
+ return -1;
+ }
+ strlcpy(buf, port, sizeof(buf));
+
+ assertifname(env);
+ memset(&ar, 0, sizeof(ar));
+ ar.ar_version = AGRREQ_VERSION;
+ ar.ar_cmd = cmd;
+ ar.ar_buf = buf;
+ ar.ar_buflen = strlen(buf);
+
+ if (indirect_ioctl(env, SIOCSETAGR, &ar) == -1)
+ err(EXIT_FAILURE, "SIOCSETAGR");
+ return 0;
+}
+
+static void
+agr_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct agrreq ar;
+ void *buf = NULL;
+ size_t buflen = 0;
+ struct agrportlist *apl;
+ struct agrportinfo *api;
+ int i;
+
+ if (checkifname(env))
+ return;
+
+again:
+ memset(&ar, 0, sizeof(ar));
+ ar.ar_version = AGRREQ_VERSION;
+ ar.ar_cmd = AGRCMD_PORTLIST;
+ ar.ar_buf = buf;
+ ar.ar_buflen = buflen;
+
+ if (indirect_ioctl(env, SIOCGETAGR, &ar) == -1) {
+ if (errno != E2BIG) {
+ warn("SIOCGETAGR");
+ return;
+ }
+
+ free(buf);
+ buf = NULL;
+ buflen = 0;
+ goto again;
+ }
+
+ if (buf == NULL) {
+ buflen = ar.ar_buflen;
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ err(EXIT_FAILURE, "agr_status");
+ }
+ goto again;
+ }
+
+ apl = buf;
+ api = (void *)(apl + 1);
+
+ for (i = 0; i < apl->apl_nports; i++) {
+ char tmp[256];
+
+ snprintb(tmp, sizeof(tmp), AGRPORTINFO_BITS, api->api_flags);
+ printf("\tagrport: %s, flags=%s\n", api->api_ifname, tmp);
+ api++;
+ }
+}
+
+static status_func_t status;
+static usage_func_t usage;
+static cmdloop_branch_t branch;
+
+static void
+agr_usage(prop_dictionary_t env)
+{
+ fprintf(stderr, "\t[ agrport i ] [ -agrport i ]\n");
+}
+
+static void
+agr_constructor(void)
+{
+ status_func_init(&status, agr_status);
+ usage_func_init(&usage, agr_usage);
+ register_status(&status);
+ register_usage(&usage);
+ cmdloop_branch_init(&branch, &agr.pk_parser);
+ register_cmdloop_branch(&branch);
+}
--- /dev/null
+/* $NetBSD: carp.c,v 1.13 2009/09/11 23:22:28 dyoung 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: carp.c,v 1.13 2009/09/11 23:22:28 dyoung Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <netinet/ip_carp.h>
+#include <net/route.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <util.h>
+
+#include "env.h"
+#include "parse.h"
+#include "extern.h"
+
+static status_func_t status;
+static usage_func_t usage;
+static cmdloop_branch_t branch;
+
+static void carp_constructor(void) __attribute__((constructor));
+static void carp_status(prop_dictionary_t, prop_dictionary_t);
+static int setcarp_advbase(prop_dictionary_t, prop_dictionary_t);
+static int setcarp_advskew(prop_dictionary_t, prop_dictionary_t);
+static int setcarp_passwd(prop_dictionary_t, prop_dictionary_t);
+static int setcarp_vhid(prop_dictionary_t, prop_dictionary_t);
+static int setcarp_state(prop_dictionary_t, prop_dictionary_t);
+static int setcarpdev(prop_dictionary_t, prop_dictionary_t);
+
+static const char *carp_states[] = { CARP_STATES };
+
+struct kwinst carpstatekw[] = {
+ {.k_word = "INIT", .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "BACKUP", .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "MASTER", .k_nextparser = &command_root.pb_parser}
+};
+
+struct pinteger parse_advbase = PINTEGER_INITIALIZER1(&parse_advbase, "advbase",
+ 0, 255, 10, setcarp_advbase, "advbase", &command_root.pb_parser);
+
+struct pinteger parse_advskew = PINTEGER_INITIALIZER1(&parse_advskew, "advskew",
+ 0, 254, 10, setcarp_advskew, "advskew", &command_root.pb_parser);
+
+struct piface carpdev = PIFACE_INITIALIZER(&carpdev, "carpdev", setcarpdev,
+ "carpdev", &command_root.pb_parser);
+
+struct pkw carpstate = PKW_INITIALIZER(&carpstate, "carp state", setcarp_state,
+ "carp_state", carpstatekw, __arraycount(carpstatekw),
+ &command_root.pb_parser);
+
+struct pstr pass = PSTR_INITIALIZER(&pass, "pass", setcarp_passwd,
+ "pass", &command_root.pb_parser);
+
+struct pinteger parse_vhid = PINTEGER_INITIALIZER1(&vhid, "vhid",
+ 0, 255, 10, setcarp_vhid, "vhid", &command_root.pb_parser);
+
+static const struct kwinst carpkw[] = {
+ {.k_word = "advbase", .k_nextparser = &parse_advbase.pi_parser}
+ , {.k_word = "advskew", .k_nextparser = &parse_advskew.pi_parser}
+ , {.k_word = "carpdev", .k_nextparser = &carpdev.pif_parser}
+ , {.k_word = "-carpdev", .k_key = "carpdev", .k_type = KW_T_STR,
+ .k_str = "", .k_exec = setcarpdev,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "pass", .k_nextparser = &pass.ps_parser}
+ , {.k_word = "state", .k_nextparser = &carpstate.pk_parser}
+ , {.k_word = "vhid", .k_nextparser = &parse_vhid.pi_parser}
+};
+
+struct pkw carp = PKW_INITIALIZER(&carp, "CARP", NULL, NULL,
+ carpkw, __arraycount(carpkw), NULL);
+
+static void
+carp_set(prop_dictionary_t env, struct carpreq *carpr)
+{
+ if (indirect_ioctl(env, SIOCSVH, carpr) == -1)
+ err(EXIT_FAILURE, "SIOCSVH");
+}
+
+static int
+carp_get1(prop_dictionary_t env, struct carpreq *carpr)
+{
+ memset(carpr, 0, sizeof(*carpr));
+
+ return indirect_ioctl(env, SIOCGVH, carpr);
+}
+
+static void
+carp_get(prop_dictionary_t env, struct carpreq *carpr)
+{
+ if (carp_get1(env, carpr) == -1)
+ err(EXIT_FAILURE, "SIOCGVH");
+}
+
+static void
+carp_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const char *state;
+ struct carpreq carpr;
+
+ if (carp_get1(env, &carpr) == -1)
+ return;
+
+ if (carpr.carpr_vhid <= 0)
+ return;
+ if (carpr.carpr_state > CARP_MAXSTATE)
+ state = "<UNKNOWN>";
+ else
+ state = carp_states[carpr.carpr_state];
+
+ printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n",
+ state, carpr.carpr_carpdev[0] != '\0' ?
+ carpr.carpr_carpdev : "none", carpr.carpr_vhid,
+ carpr.carpr_advbase, carpr.carpr_advskew);
+}
+
+int
+setcarp_passwd(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct carpreq carpr;
+ prop_data_t data;
+
+ data = (prop_data_t)prop_dictionary_get(env, "pass");
+ if (data == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ carp_get(env, &carpr);
+
+ memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key));
+ /* XXX Should hash the password into the key here, perhaps? */
+ strlcpy((char *)carpr.carpr_key, prop_data_data_nocopy(data),
+ MIN(CARP_KEY_LEN, prop_data_size(data)));
+
+ carp_set(env, &carpr);
+ return 0;
+}
+
+int
+setcarp_vhid(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct carpreq carpr;
+ int64_t vhid;
+
+ if (!prop_dictionary_get_int64(env, "vhid", &vhid)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ carp_get(env, &carpr);
+
+ carpr.carpr_vhid = vhid;
+
+ carp_set(env, &carpr);
+ return 0;
+}
+
+int
+setcarp_advskew(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct carpreq carpr;
+ int64_t advskew;
+
+ if (!prop_dictionary_get_int64(env, "advskew", &advskew)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ carp_get(env, &carpr);
+
+ carpr.carpr_advskew = advskew;
+
+ carp_set(env, &carpr);
+ return 0;
+}
+
+/* ARGSUSED */
+int
+setcarp_advbase(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct carpreq carpr;
+ int64_t advbase;
+
+ if (!prop_dictionary_get_int64(env, "advbase", &advbase)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ carp_get(env, &carpr);
+
+ carpr.carpr_advbase = advbase;
+
+ carp_set(env, &carpr);
+ return 0;
+}
+
+/* ARGSUSED */
+static int
+setcarp_state(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct carpreq carpr;
+ int64_t carp_state;
+
+ if (!prop_dictionary_get_int64(env, "carp_state", &carp_state)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ carp_get(env, &carpr);
+
+ carpr.carpr_state = carp_state;
+
+ carp_set(env, &carpr);
+ return 0;
+}
+
+/* ARGSUSED */
+int
+setcarpdev(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct carpreq carpr;
+ prop_string_t s;
+
+ s = (prop_string_t)prop_dictionary_get(env, "carpdev");
+ if (s == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ carp_get(env, &carpr);
+
+ strlcpy(carpr.carpr_carpdev, prop_string_cstring_nocopy(s),
+ sizeof(carpr.carpr_carpdev));
+
+ carp_set(env, &carpr);
+ return 0;
+}
+
+static void
+carp_usage(prop_dictionary_t env)
+{
+ fprintf(stderr,
+ "\t[ advbase n ] [ advskew n ] [ carpdev iface ] "
+ "[ pass passphrase ] [ state state ] [ vhid n ]\n");
+
+}
+
+static void
+carp_constructor(void)
+{
+ cmdloop_branch_init(&branch, &carp.pk_parser);
+ register_cmdloop_branch(&branch);
+ status_func_init(&status, carp_status);
+ usage_func_init(&usage, carp_usage);
+ register_status(&status);
+ register_usage(&usage);
+}
--- /dev/null
+/* $NetBSD: env.c,v 1.9 2013/02/07 13:20:51 apb Exp $ */
+
+/*-
+ * Copyright (c) 2008 David Young. 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: env.c,v 1.9 2013/02/07 13:20:51 apb Exp $");
+#endif /* not lint */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <util.h>
+
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include "env.h"
+#include "util.h"
+#include "prog_ops.h"
+
+prop_dictionary_t
+prop_dictionary_augment(prop_dictionary_t bottom, prop_dictionary_t top)
+{
+ prop_object_iterator_t i;
+ prop_dictionary_t d;
+ prop_object_t ko, o;
+ prop_dictionary_keysym_t k;
+ const char *key;
+
+ d = prop_dictionary_copy_mutable(bottom);
+ if (d == NULL)
+ return NULL;
+
+ i = prop_dictionary_iterator(top);
+
+ while (i != NULL && (ko = prop_object_iterator_next(i)) != NULL) {
+ k = (prop_dictionary_keysym_t)ko;
+ key = prop_dictionary_keysym_cstring_nocopy(k);
+ o = prop_dictionary_get_keysym(top, k);
+ if (o == NULL || !prop_dictionary_set(d, key, o)) {
+ prop_object_release((prop_object_t)d);
+ d = NULL;
+ break;
+ }
+ }
+ if (i != NULL)
+ prop_object_iterator_release(i);
+ if (d != NULL)
+ prop_dictionary_make_immutable(d);
+ return d;
+}
+
+int
+getifflags(prop_dictionary_t env, prop_dictionary_t oenv,
+ unsigned short *flagsp)
+{
+ struct ifreq ifr;
+ const char *ifname;
+ uint64_t ifflags;
+ int s;
+
+ if (prop_dictionary_get_uint64(env, "ifflags", &ifflags)) {
+ *flagsp = (unsigned short)ifflags;
+ return 0;
+ }
+
+ if ((s = getsock(AF_UNSPEC)) == -1)
+ return -1;
+
+ if ((ifname = getifname(env)) == NULL)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (prog_ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
+ return -1;
+
+ *flagsp = (unsigned short)ifr.ifr_flags;
+
+ prop_dictionary_set_uint64(oenv, "ifflags",
+ (unsigned short)ifr.ifr_flags);
+
+ return 0;
+}
+
+const char *
+getifinfo(prop_dictionary_t env, prop_dictionary_t oenv, unsigned short *flagsp)
+{
+ if (getifflags(env, oenv, flagsp) == -1)
+ return NULL;
+
+ return getifname(env);
+}
+
+const char *
+getifname(prop_dictionary_t env)
+{
+ const char *s;
+
+ return prop_dictionary_get_cstring_nocopy(env, "if", &s) ? s : NULL;
+}
+
+ssize_t
+getargdata(prop_dictionary_t env, const char *key, uint8_t *buf, size_t buflen)
+{
+ prop_data_t data;
+ size_t datalen;
+
+ data = (prop_data_t)prop_dictionary_get(env, key);
+ if (data == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+ datalen = prop_data_size(data);
+ if (datalen > buflen) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memset(buf, 0, buflen);
+ memcpy(buf, prop_data_data_nocopy(data), datalen);
+ return datalen;
+}
+
+ssize_t
+getargstr(prop_dictionary_t env, const char *key, char *buf, size_t buflen)
+{
+ prop_data_t data;
+ size_t datalen;
+
+ data = (prop_data_t)prop_dictionary_get(env, key);
+ if (data == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+ datalen = prop_data_size(data);
+ if (datalen >= buflen) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ memset(buf, 0, buflen);
+ memcpy(buf, prop_data_data_nocopy(data), datalen);
+ return datalen;
+}
+
+int
+getaf(prop_dictionary_t env)
+{
+ int64_t af;
+
+ if (!prop_dictionary_get_int64(env, "af", &af)) {
+ errno = ENOENT;
+ return -1;
+ }
+ return (int)af;
+}
--- /dev/null
+#ifndef _IFCONFIG_ENV_H
+#define _IFCONFIG_ENV_H
+
+#include <prop/proplib.h>
+
+const char *getifname(prop_dictionary_t);
+ssize_t getargstr(prop_dictionary_t, const char *, char *, size_t);
+ssize_t getargdata(prop_dictionary_t, const char *, uint8_t *, size_t);
+int getaf(prop_dictionary_t);
+int getifflags(prop_dictionary_t, prop_dictionary_t, unsigned short *);
+const char *getifinfo(prop_dictionary_t, prop_dictionary_t, unsigned short *);
+prop_dictionary_t prop_dictionary_augment(prop_dictionary_t, prop_dictionary_t);
+
+/*
+ * XXX: this really doesn't belong in here, but env.h is conveniently
+ * included from all source modules *after* system headers, so it
+ * allows us to be lazy. See Makefile for more details.
+ */
+#ifdef RUMP_ACTION
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/rumpclient.h>
+#endif /* RUMP_ACTION */
+
+#endif /* _IFCONFIG_ENV_H */
--- /dev/null
+/* $NetBSD: ether.c,v 1.2 2012/11/01 13:43:23 pgoyette Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ether.c,v 1.2 2012/11/01 13:43:23 pgoyette Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "parse.h"
+#include "extern.h"
+#include "prog_ops.h"
+
+static void ether_status(prop_dictionary_t, prop_dictionary_t);
+static void ether_constructor(void) __attribute__((constructor));
+
+static status_func_t status;
+
+#define MAX_PRINT_LEN 55
+
+void
+ether_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct eccapreq eccr;
+ char fbuf[BUFSIZ];
+ char *bp;
+
+ memset(&eccr, 0, sizeof(eccr));
+
+ if (direct_ioctl(env, SIOCGETHERCAP, &eccr) == -1)
+ return;
+
+ if (eccr.eccr_capabilities != 0) {
+ (void)snprintb_m(fbuf, sizeof(fbuf), ECCAPBITS,
+ eccr.eccr_capabilities, MAX_PRINT_LEN);
+ bp = fbuf;
+ while (*bp != '\0') {
+ printf("\tec_capabilities=%s\n", &bp[2]);
+ bp += strlen(bp) + 1;
+ }
+ (void)snprintb_m(fbuf, sizeof(fbuf), ECCAPBITS,
+ eccr.eccr_capenable, MAX_PRINT_LEN);
+ bp = fbuf;
+ while (*bp != '\0') {
+ printf("\tec_enabled=%s\n", &bp[2]);
+ bp += strlen(bp) + 1;
+ }
+ }
+}
+
+static void
+ether_constructor(void)
+{
+
+ status_func_init(&status, ether_status);
+ register_status(&status);
+}
--- /dev/null
+/* $NetBSD: extern.h,v 1.14 2009/08/07 18:53:37 dyoung Exp $ */
+
+/*
+ * 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. 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 _IFCONFIG_EXTERN_H
+#define _IFCONFIG_EXTERN_H
+
+#include <prop/proplib.h>
+#include "util.h"
+
+#define RIDADDR 0
+#define ADDR 1
+#define MASK 2
+#define DSTADDR 3
+
+typedef void (*usage_cb_t)(prop_dictionary_t);
+typedef void (*status_cb_t)(prop_dictionary_t, prop_dictionary_t);
+typedef void (*statistics_cb_t)(prop_dictionary_t);
+
+enum flag_type {
+ FLAG_T_MOD = 0
+ , FLAG_T_CMD = 1
+};
+
+typedef enum flag_type flag_type_t;
+
+struct statistics_func {
+ SIMPLEQ_ENTRY(statistics_func) f_next;
+ statistics_cb_t f_func;
+};
+
+struct usage_func {
+ SIMPLEQ_ENTRY(usage_func) f_next;
+ usage_cb_t f_func;
+};
+
+struct status_func {
+ SIMPLEQ_ENTRY(status_func) f_next;
+ status_cb_t f_func;
+};
+
+struct cmdloop_branch {
+ SIMPLEQ_ENTRY(cmdloop_branch) b_next;
+ struct parser *b_parser;
+};
+
+
+typedef struct statistics_func statistics_func_t;
+typedef struct status_func status_func_t;
+typedef struct usage_func usage_func_t;
+typedef struct cmdloop_branch cmdloop_branch_t;
+
+void cmdloop_branch_init(cmdloop_branch_t *, struct parser *);
+int register_family(struct afswtch *);
+int register_cmdloop_branch(cmdloop_branch_t *);
+void statistics_func_init(statistics_func_t *, statistics_cb_t);
+void status_func_init(status_func_t *, status_cb_t);
+void usage_func_init(usage_func_t *, usage_cb_t);
+int register_statistics(statistics_func_t *);
+int register_status(status_func_t *);
+int register_usage(usage_func_t *);
+int register_flag(int);
+bool get_flag(int);
+
+extern bool lflag, Nflag, vflag, zflag;
+
+#endif /* _IFCONFIG_EXTERN_H */
--- /dev/null
+/* $NetBSD: ieee80211.c,v 1.28 2015/04/28 15:14:57 christos Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ieee80211.c,v 1.28 2015/04/28 15:14:57 christos Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+#include <net/route.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_netbsd.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "extern.h"
+#include "parse.h"
+#include "env.h"
+#include "util.h"
+#include "prog_ops.h"
+
+static void ieee80211_statistics(prop_dictionary_t);
+static void ieee80211_status(prop_dictionary_t, prop_dictionary_t);
+static void ieee80211_constructor(void) __attribute__((constructor));
+static int set80211(prop_dictionary_t env, uint16_t, int16_t, int16_t,
+ u_int8_t *);
+static u_int ieee80211_mhz2ieee(u_int, u_int);
+static int getmaxrate(const uint8_t [15], u_int8_t);
+static const char * getcaps(int);
+static void printie(const char*, const uint8_t *, size_t, int);
+static int copy_essid(char [], size_t, const u_int8_t *, size_t);
+static void scan_and_wait(prop_dictionary_t);
+static void list_scan(prop_dictionary_t);
+static int mappsb(u_int , u_int);
+static int mapgsm(u_int , u_int);
+
+static int sethidessid(prop_dictionary_t, prop_dictionary_t);
+static int setapbridge(prop_dictionary_t, prop_dictionary_t);
+static int setifssid(prop_dictionary_t, prop_dictionary_t);
+static int setifnwkey(prop_dictionary_t, prop_dictionary_t);
+static int unsetifnwkey(prop_dictionary_t, prop_dictionary_t);
+static int unsetifbssid(prop_dictionary_t, prop_dictionary_t);
+static int setifbssid(prop_dictionary_t, prop_dictionary_t);
+static int setifchan(prop_dictionary_t, prop_dictionary_t);
+static int setiffrag(prop_dictionary_t, prop_dictionary_t);
+static int setifpowersave(prop_dictionary_t, prop_dictionary_t);
+static int setifpowersavesleep(prop_dictionary_t, prop_dictionary_t);
+static int setifrts(prop_dictionary_t, prop_dictionary_t);
+static int scan_exec(prop_dictionary_t, prop_dictionary_t);
+
+static void printies(const u_int8_t *, int, int);
+static void printwmeparam(const char *, const u_int8_t *, size_t , int);
+static void printwmeinfo(const char *, const u_int8_t *, size_t , int);
+static const char * wpa_cipher(const u_int8_t *);
+static const char * wpa_keymgmt(const u_int8_t *);
+static void printwpaie(const char *, const u_int8_t *, size_t , int);
+static const char * rsn_cipher(const u_int8_t *);
+static const char * rsn_keymgmt(const u_int8_t *);
+static void printrsnie(const char *, const u_int8_t *, size_t , int);
+static void printssid(const char *, const u_int8_t *, size_t , int);
+static void printrates(const char *, const u_int8_t *, size_t , int);
+static void printcountry(const char *, const u_int8_t *, size_t , int);
+static int iswpaoui(const u_int8_t *);
+static int iswmeinfo(const u_int8_t *);
+static int iswmeparam(const u_int8_t *);
+static const char * iename(int);
+
+extern struct pinteger parse_chan, parse_frag, parse_rts;
+extern struct pstr parse_bssid, parse_ssid, parse_nwkey;
+extern struct pinteger parse_powersavesleep;
+
+static const struct kwinst ieee80211boolkw[] = {
+ {.k_word = "hidessid", .k_key = "hidessid", .k_neg = true,
+ .k_type = KW_T_BOOL, .k_bool = true, .k_negbool = false,
+ .k_exec = sethidessid}
+ , {.k_word = "apbridge", .k_key = "apbridge", .k_neg = true,
+ .k_type = KW_T_BOOL, .k_bool = true, .k_negbool = false,
+ .k_exec = setapbridge}
+ , {.k_word = "powersave", .k_key = "powersave", .k_neg = true,
+ .k_type = KW_T_BOOL, .k_bool = true, .k_negbool = false,
+ .k_exec = setifpowersave}
+};
+
+static const struct kwinst listskw[] = {
+ {.k_word = "scan", .k_exec = scan_exec}
+};
+
+static struct pkw lists = PKW_INITIALIZER(&lists, "ieee80211 lists", NULL,
+ "list", listskw, __arraycount(listskw), &command_root.pb_parser);
+
+static const struct kwinst kw80211kw[] = {
+ {.k_word = "bssid", .k_nextparser = &parse_bssid.ps_parser}
+ , {.k_word = "-bssid", .k_exec = unsetifbssid,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "chan", .k_nextparser = &parse_chan.pi_parser}
+ , {.k_word = "-chan", .k_key = "chan", .k_type = KW_T_UINT,
+ .k_uint = IEEE80211_CHAN_ANY, .k_exec = setifchan,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "frag", .k_nextparser = &parse_frag.pi_parser}
+ , {.k_word = "-frag", .k_key = "frag", .k_type = KW_T_INT,
+ .k_int = IEEE80211_FRAG_MAX, .k_exec = setiffrag,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "list", .k_nextparser = &lists.pk_parser}
+ , {.k_word = "nwid", .k_nextparser = &parse_ssid.ps_parser}
+ , {.k_word = "nwkey", .k_nextparser = &parse_nwkey.ps_parser}
+ , {.k_word = "-nwkey", .k_exec = unsetifnwkey,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "rts", .k_nextparser = &parse_rts.pi_parser}
+ , {.k_word = "-rts", .k_key = "rts", .k_type = KW_T_INT,
+ .k_int = IEEE80211_RTS_MAX, .k_exec = setifrts,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "ssid", .k_nextparser = &parse_ssid.ps_parser}
+ , {.k_word = "powersavesleep",
+ .k_nextparser = &parse_powersavesleep.pi_parser}
+};
+
+struct pkw kw80211 = PKW_INITIALIZER(&kw80211, "802.11 keywords", NULL, NULL,
+ kw80211kw, __arraycount(kw80211kw), NULL);
+
+struct pkw ieee80211bool = PKW_INITIALIZER(&ieee80211bool, "ieee80211 boolean",
+ NULL, NULL, ieee80211boolkw, __arraycount(ieee80211boolkw),
+ &command_root.pb_parser);
+
+struct pinteger parse_chan = PINTEGER_INITIALIZER1(&parse_chan, "chan",
+ 0, UINT16_MAX, 10, setifchan, "chan", &command_root.pb_parser);
+
+struct pinteger parse_rts = PINTEGER_INITIALIZER1(&parse_rts, "rts",
+ IEEE80211_RTS_MIN, IEEE80211_RTS_MAX, 10,
+ setifrts, "rts", &command_root.pb_parser);
+
+struct pinteger parse_frag = PINTEGER_INITIALIZER1(&parse_frag, "frag",
+ IEEE80211_FRAG_MIN, IEEE80211_FRAG_MAX, 10,
+ setiffrag, "frag", &command_root.pb_parser);
+
+struct pstr parse_ssid = PSTR_INITIALIZER(&parse_pass, "ssid", setifssid,
+ "ssid", &command_root.pb_parser);
+
+struct pinteger parse_powersavesleep =
+ PINTEGER_INITIALIZER1(&parse_powersavesleep, "powersavesleep",
+ 0, INT_MAX, 10, setifpowersavesleep, "powersavesleep",
+ &command_root.pb_parser);
+
+struct pstr parse_nwkey = PSTR_INITIALIZER1(&parse_nwkey, "nwkey", setifnwkey,
+ "nwkey", false, &command_root.pb_parser);
+
+struct pstr parse_bssid = PSTR_INITIALIZER1(&parse_bssid, "bssid", setifbssid,
+ "bssid", false, &command_root.pb_parser);
+
+static int
+set80211(prop_dictionary_t env, uint16_t type, int16_t val, int16_t len,
+ u_int8_t *data)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ ireq.i_type = type;
+ ireq.i_val = val;
+ ireq.i_len = len;
+ ireq.i_data = data;
+ if (direct_ioctl(env, SIOCS80211, &ireq) == -1) {
+ warn("SIOCS80211");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+sethidessid(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool on, rc;
+
+ rc = prop_dictionary_get_bool(env, "hidessid", &on);
+ assert(rc);
+ return set80211(env, IEEE80211_IOC_HIDESSID, on ? 1 : 0, 0, NULL);
+}
+
+static int
+setapbridge(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool on, rc;
+
+ rc = prop_dictionary_get_bool(env, "apbridge", &on);
+ assert(rc);
+ return set80211(env, IEEE80211_IOC_APBRIDGE, on ? 1 : 0, 0, NULL);
+}
+
+static enum ieee80211_opmode
+get80211opmode(prop_dictionary_t env)
+{
+ struct ifmediareq ifmr;
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1)
+ ;
+ else if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
+ return IEEE80211_M_IBSS; /* XXX ahdemo */
+ else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+ return IEEE80211_M_HOSTAP;
+ else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+ return IEEE80211_M_MONITOR;
+
+ return IEEE80211_M_STA;
+}
+
+static int
+setifssid(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ieee80211_nwid nwid;
+ ssize_t len;
+
+ memset(&nwid, 0, sizeof(nwid));
+ if ((len = getargdata(env, "ssid", nwid.i_nwid,
+ sizeof(nwid.i_nwid))) == -1)
+ errx(EXIT_FAILURE, "%s: SSID too long", __func__);
+ nwid.i_len = (uint8_t)len;
+ if (indirect_ioctl(env, SIOCS80211NWID, &nwid) == -1)
+ err(EXIT_FAILURE, "SIOCS80211NWID");
+ return 0;
+}
+
+static int
+unsetifbssid(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ieee80211_bssid bssid;
+
+ memset(&bssid, 0, sizeof(bssid));
+
+ if (direct_ioctl(env, SIOCS80211BSSID, &bssid) == -1)
+ err(EXIT_FAILURE, "SIOCS80211BSSID");
+ return 0;
+}
+
+static int
+setifbssid(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ char buf[24];
+ struct ieee80211_bssid bssid;
+ struct ether_addr *ea;
+
+ if (getargstr(env, "bssid", buf, sizeof(buf)) == -1)
+ errx(EXIT_FAILURE, "%s: BSSID too long", __func__);
+
+ ea = ether_aton(buf);
+ if (ea == NULL) {
+ errx(EXIT_FAILURE, "malformed BSSID: %s", buf);
+ return -1;
+ }
+ memcpy(&bssid.i_bssid, ea->ether_addr_octet,
+ sizeof(bssid.i_bssid));
+
+ if (direct_ioctl(env, SIOCS80211BSSID, &bssid) == -1)
+ err(EXIT_FAILURE, "SIOCS80211BSSID");
+ return 0;
+}
+
+static int
+setifrts(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool rc;
+ int16_t val;
+
+ rc = prop_dictionary_get_int16(env, "rts", &val);
+ assert(rc);
+ if (set80211(env, IEEE80211_IOC_RTSTHRESHOLD, val, 0, NULL) == -1)
+ err(EXIT_FAILURE, "IEEE80211_IOC_RTSTHRESHOLD");
+ return 0;
+}
+
+static int
+setiffrag(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool rc;
+ int16_t val;
+
+ rc = prop_dictionary_get_int16(env, "frag", &val);
+ assert(rc);
+ if (set80211(env, IEEE80211_IOC_FRAGTHRESHOLD, val, 0, NULL) == -1)
+ err(EXIT_FAILURE, "IEEE80211_IOC_FRAGTHRESHOLD");
+ return 0;
+}
+
+static int
+setifchan(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool rc;
+ struct ieee80211chanreq channel;
+
+ rc = prop_dictionary_get_uint16(env, "chan", &channel.i_channel);
+ assert(rc);
+ if (direct_ioctl(env, SIOCS80211CHANNEL, &channel) == -1)
+ err(EXIT_FAILURE, "SIOCS80211CHANNEL");
+ return 0;
+}
+
+static int
+setifnwkey(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const char *val;
+ char buf[256];
+ struct ieee80211_nwkey nwkey;
+ int i;
+ u_int8_t keybuf[IEEE80211_WEP_NKID][16];
+
+ if (getargstr(env, "nwkey", buf, sizeof(buf)) == -1)
+ errx(EXIT_FAILURE, "%s: nwkey too long", __func__);
+
+ val = buf;
+
+ nwkey.i_wepon = IEEE80211_NWKEY_WEP;
+ nwkey.i_defkid = 1;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
+ nwkey.i_key[i].i_keydat = keybuf[i];
+ }
+ if (strcasecmp("persist", val) == 0) {
+ /* use all values from persistent memory */
+ nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
+ nwkey.i_defkid = 0;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ nwkey.i_key[i].i_keylen = -1;
+ } else if (strncasecmp("persist:", val, 8) == 0) {
+ val += 8;
+ /* program keys in persistent memory */
+ nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
+ goto set_nwkey;
+ } else {
+ set_nwkey:
+ if (isdigit((unsigned char)val[0]) && val[1] == ':') {
+ /* specifying a full set of four keys */
+ nwkey.i_defkid = val[0] - '0';
+ val += 2;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ val = get_string(val, ",", keybuf[i],
+ &nwkey.i_key[i].i_keylen, true);
+ if (val == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ if (*val != '\0') {
+ errx(EXIT_FAILURE, "SIOCS80211NWKEY: too many keys.");
+ }
+ } else {
+ val = get_string(val, NULL, keybuf[0],
+ &nwkey.i_key[0].i_keylen, true);
+ if (val == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ i = 1;
+ }
+ }
+ for (; i < IEEE80211_WEP_NKID; i++)
+ nwkey.i_key[i].i_keylen = 0;
+
+ if (direct_ioctl(env, SIOCS80211NWKEY, &nwkey) == -1)
+ err(EXIT_FAILURE, "SIOCS80211NWKEY");
+ return 0;
+}
+
+static int
+unsetifnwkey(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ieee80211_nwkey nwkey;
+ int i;
+
+ nwkey.i_wepon = 0;
+ nwkey.i_defkid = 1;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ nwkey.i_key[i].i_keylen = 0;
+ nwkey.i_key[i].i_keydat = NULL;
+ }
+
+ if (direct_ioctl(env, SIOCS80211NWKEY, &nwkey) == -1)
+ err(EXIT_FAILURE, "SIOCS80211NWKEY");
+ return 0;
+}
+
+static int
+setifpowersave(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ieee80211_power power;
+ bool on, rc;
+
+ if (direct_ioctl(env, SIOCG80211POWER, &power) == -1)
+ err(EXIT_FAILURE, "SIOCG80211POWER");
+
+ rc = prop_dictionary_get_bool(env, "powersave", &on);
+ assert(rc);
+
+ power.i_enabled = on ? 1 : 0;
+ if (direct_ioctl(env, SIOCS80211POWER, &power) == -1) {
+ warn("SIOCS80211POWER");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+setifpowersavesleep(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ieee80211_power power;
+ int64_t maxsleep;
+ bool rc;
+
+ rc = prop_dictionary_get_int64(env, "powersavesleep", &maxsleep);
+ assert(rc);
+
+ if (direct_ioctl(env, SIOCG80211POWER, &power) == -1)
+ err(EXIT_FAILURE, "SIOCG80211POWER");
+
+ power.i_maxsleep = maxsleep;
+ if (direct_ioctl(env, SIOCS80211POWER, &power) == -1)
+ err(EXIT_FAILURE, "SIOCS80211POWER");
+ return 0;
+}
+
+static int
+scan_exec(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifreq ifr;
+
+ if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) {
+ warn("ioctl(SIOCGIFFLAGS)");
+ return -1;
+ }
+
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ errx(EXIT_FAILURE, "The interface must be up before scanning.");
+
+ scan_and_wait(env);
+ list_scan(env);
+
+ return 0;
+}
+
+static void
+ieee80211_statistics(prop_dictionary_t env)
+{
+#ifndef SMALL
+ struct ieee80211_stats stats;
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_buflen = sizeof(stats);
+ ifr.ifr_buf = (caddr_t)&stats;
+ if (direct_ioctl(env, (zflag) ? SIOCG80211ZSTATS : SIOCG80211STATS,
+ &ifr) == -1)
+ return;
+#define STAT_PRINT(_member, _desc) \
+ printf("\t" _desc ": %" PRIu32 "\n", stats._member)
+
+ STAT_PRINT(is_rx_badversion, "rx frame with bad version");
+ STAT_PRINT(is_rx_tooshort, "rx frame too short");
+ STAT_PRINT(is_rx_wrongbss, "rx from wrong bssid");
+ STAT_PRINT(is_rx_dup, "rx discard 'cuz dup");
+ STAT_PRINT(is_rx_wrongdir, "rx w/ wrong direction");
+ STAT_PRINT(is_rx_mcastecho, "rx discard 'cuz mcast echo");
+ STAT_PRINT(is_rx_notassoc, "rx discard 'cuz sta !assoc");
+ STAT_PRINT(is_rx_noprivacy, "rx w/ wep but privacy off");
+ STAT_PRINT(is_rx_unencrypted, "rx w/o wep and privacy on");
+ STAT_PRINT(is_rx_wepfail, "rx wep processing failed");
+ STAT_PRINT(is_rx_decap, "rx decapsulation failed");
+ STAT_PRINT(is_rx_mgtdiscard, "rx discard mgt frames");
+ STAT_PRINT(is_rx_ctl, "rx discard ctrl frames");
+ STAT_PRINT(is_rx_beacon, "rx beacon frames");
+ STAT_PRINT(is_rx_rstoobig, "rx rate set truncated");
+ STAT_PRINT(is_rx_elem_missing, "rx required element missing");
+ STAT_PRINT(is_rx_elem_toobig, "rx element too big");
+ STAT_PRINT(is_rx_elem_toosmall, "rx element too small");
+ STAT_PRINT(is_rx_elem_unknown, "rx element unknown");
+ STAT_PRINT(is_rx_badchan, "rx frame w/ invalid chan");
+ STAT_PRINT(is_rx_chanmismatch, "rx frame chan mismatch");
+ STAT_PRINT(is_rx_nodealloc, "rx frame dropped");
+ STAT_PRINT(is_rx_ssidmismatch, "rx frame ssid mismatch ");
+ STAT_PRINT(is_rx_auth_unsupported, "rx w/ unsupported auth alg");
+ STAT_PRINT(is_rx_auth_fail, "rx sta auth failure");
+ STAT_PRINT(is_rx_auth_countermeasures, "rx auth discard 'cuz CM");
+ STAT_PRINT(is_rx_assoc_bss, "rx assoc from wrong bssid");
+ STAT_PRINT(is_rx_assoc_notauth, "rx assoc w/o auth");
+ STAT_PRINT(is_rx_assoc_capmismatch, "rx assoc w/ cap mismatch");
+ STAT_PRINT(is_rx_assoc_norate, "rx assoc w/ no rate match");
+ STAT_PRINT(is_rx_assoc_badwpaie, "rx assoc w/ bad WPA IE");
+ STAT_PRINT(is_rx_deauth, "rx deauthentication");
+ STAT_PRINT(is_rx_disassoc, "rx disassociation");
+ STAT_PRINT(is_rx_badsubtype, "rx frame w/ unknown subtyp");
+ STAT_PRINT(is_rx_nobuf, "rx failed for lack of buf");
+ STAT_PRINT(is_rx_decryptcrc, "rx decrypt failed on crc");
+ STAT_PRINT(is_rx_ahdemo_mgt, "rx discard ahdemo mgt fram");
+ STAT_PRINT(is_rx_bad_auth, "rx bad auth request");
+ STAT_PRINT(is_rx_unauth, "rx on unauthorized port");
+ STAT_PRINT(is_rx_badkeyid, "rx w/ incorrect keyid");
+ STAT_PRINT(is_rx_ccmpreplay, "rx seq# violation (CCMP)");
+ STAT_PRINT(is_rx_ccmpformat, "rx format bad (CCMP)");
+ STAT_PRINT(is_rx_ccmpmic, "rx MIC check failed (CCMP)");
+ STAT_PRINT(is_rx_tkipreplay, "rx seq# violation (TKIP)");
+ STAT_PRINT(is_rx_tkipformat, "rx format bad (TKIP)");
+ STAT_PRINT(is_rx_tkipmic, "rx MIC check failed (TKIP)");
+ STAT_PRINT(is_rx_tkipicv, "rx ICV check failed (TKIP)");
+ STAT_PRINT(is_rx_badcipher, "rx failed 'cuz key type");
+ STAT_PRINT(is_rx_nocipherctx, "rx failed 'cuz key !setup");
+ STAT_PRINT(is_rx_acl, "rx discard 'cuz acl policy");
+
+ STAT_PRINT(is_tx_nobuf, "tx failed for lack of buf");
+ STAT_PRINT(is_tx_nonode, "tx failed for no node");
+ STAT_PRINT(is_tx_unknownmgt, "tx of unknown mgt frame");
+ STAT_PRINT(is_tx_badcipher, "tx failed 'cuz key type");
+ STAT_PRINT(is_tx_nodefkey, "tx failed 'cuz no defkey");
+ STAT_PRINT(is_tx_noheadroom, "tx failed 'cuz no space");
+ STAT_PRINT(is_tx_fragframes, "tx frames fragmented");
+ STAT_PRINT(is_tx_frags, "tx fragments created");
+
+ STAT_PRINT(is_scan_active, "active scans started");
+ STAT_PRINT(is_scan_passive, "passive scans started");
+ STAT_PRINT(is_node_timeout, "nodes timed out inactivity");
+ STAT_PRINT(is_crypto_nomem, "no memory for crypto ctx");
+ STAT_PRINT(is_crypto_tkip, "tkip crypto done in s/w");
+ STAT_PRINT(is_crypto_tkipenmic, "tkip en-MIC done in s/w");
+ STAT_PRINT(is_crypto_tkipdemic, "tkip de-MIC done in s/w");
+ STAT_PRINT(is_crypto_tkipcm, "tkip counter measures");
+ STAT_PRINT(is_crypto_ccmp, "ccmp crypto done in s/w");
+ STAT_PRINT(is_crypto_wep, "wep crypto done in s/w");
+ STAT_PRINT(is_crypto_setkey_cipher, "cipher rejected key");
+ STAT_PRINT(is_crypto_setkey_nokey, "no key index for setkey");
+ STAT_PRINT(is_crypto_delkey, "driver key delete failed");
+ STAT_PRINT(is_crypto_badcipher, "unknown cipher");
+ STAT_PRINT(is_crypto_nocipher, "cipher not available");
+ STAT_PRINT(is_crypto_attachfail, "cipher attach failed");
+ STAT_PRINT(is_crypto_swfallback, "cipher fallback to s/w");
+ STAT_PRINT(is_crypto_keyfail, "driver key alloc failed");
+ STAT_PRINT(is_crypto_enmicfail, "en-MIC failed");
+ STAT_PRINT(is_ibss_capmismatch, "merge failed-cap mismatch");
+ STAT_PRINT(is_ibss_norate, "merge failed-rate mismatch");
+ STAT_PRINT(is_ps_unassoc, "ps-poll for unassoc. sta");
+ STAT_PRINT(is_ps_badaid, "ps-poll w/ incorrect aid");
+ STAT_PRINT(is_ps_qempty, "ps-poll w/ nothing to send");
+ STAT_PRINT(is_ff_badhdr, "fast frame rx'd w/ bad hdr");
+ STAT_PRINT(is_ff_tooshort, "fast frame rx decap error");
+ STAT_PRINT(is_ff_split, "fast frame rx split error");
+ STAT_PRINT(is_ff_decap, "fast frames decap'd");
+ STAT_PRINT(is_ff_encap, "fast frames encap'd for tx");
+ STAT_PRINT(is_rx_badbintval, "rx frame w/ bogus bintval");
+#endif
+}
+
+static void
+ieee80211_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int i, nwkey_verbose;
+ struct ieee80211_nwid nwid;
+ struct ieee80211_nwkey nwkey;
+ struct ieee80211_power power;
+ u_int8_t keybuf[IEEE80211_WEP_NKID][16];
+ struct ieee80211_bssid bssid;
+ struct ieee80211chanreq channel;
+ struct ieee80211req ireq;
+ struct ether_addr ea;
+ static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN];
+ enum ieee80211_opmode opmode = get80211opmode(env);
+
+ memset(&bssid, 0, sizeof(bssid));
+ memset(&nwkey, 0, sizeof(nwkey));
+ memset(&nwid, 0, sizeof(nwid));
+ memset(&nwid, 0, sizeof(nwid));
+
+ if (indirect_ioctl(env, SIOCG80211NWID, &nwid) == -1)
+ return;
+ if (nwid.i_len > IEEE80211_NWID_LEN) {
+ errx(EXIT_FAILURE, "SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len);
+ }
+ printf("\tssid ");
+ print_string(nwid.i_nwid, nwid.i_len);
+
+ if (opmode == IEEE80211_M_HOSTAP) {
+ ireq.i_type = IEEE80211_IOC_HIDESSID;
+ if (direct_ioctl(env, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ printf(" [hidden]");
+ else if (vflag)
+ printf(" [shown]");
+ }
+
+ ireq.i_type = IEEE80211_IOC_APBRIDGE;
+ if (direct_ioctl(env, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ printf(" apbridge");
+ else if (vflag)
+ printf(" -apbridge");
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+ if (direct_ioctl(env, SIOCG80211, &ireq) == -1)
+ ;
+ else if (ireq.i_val < IEEE80211_RTS_MAX)
+ printf(" rts %d", ireq.i_val);
+ else if (vflag)
+ printf(" -rts");
+
+ ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
+ if (direct_ioctl(env, SIOCG80211, &ireq) == -1)
+ ;
+ else if (ireq.i_val < IEEE80211_FRAG_MAX)
+ printf(" frag %d", ireq.i_val);
+ else if (vflag)
+ printf(" -frag");
+
+ memset(&nwkey, 0, sizeof(nwkey));
+ /* show nwkey only when WEP is enabled */
+ if (direct_ioctl(env, SIOCG80211NWKEY, &nwkey) == -1 ||
+ nwkey.i_wepon == 0) {
+ printf("\n");
+ goto skip_wep;
+ }
+
+ printf(" nwkey ");
+ /* try to retrieve WEP keys */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ nwkey.i_key[i].i_keydat = keybuf[i];
+ nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
+ }
+ if (direct_ioctl(env, SIOCG80211NWKEY, &nwkey) == -1) {
+ printf("*****");
+ } else {
+ nwkey_verbose = 0;
+ /* check to see non default key or multiple keys defined */
+ if (nwkey.i_defkid != 1) {
+ nwkey_verbose = 1;
+ } else {
+ for (i = 1; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey.i_key[i].i_keylen != 0) {
+ nwkey_verbose = 1;
+ break;
+ }
+ }
+ }
+ /* check extra ambiguity with keywords */
+ if (!nwkey_verbose) {
+ if (nwkey.i_key[0].i_keylen >= 2 &&
+ isdigit(nwkey.i_key[0].i_keydat[0]) &&
+ nwkey.i_key[0].i_keydat[1] == ':')
+ nwkey_verbose = 1;
+ else if (nwkey.i_key[0].i_keylen >= 7 &&
+ strncasecmp("persist",
+ (const char *)nwkey.i_key[0].i_keydat, 7) == 0)
+ nwkey_verbose = 1;
+ }
+ if (nwkey_verbose)
+ printf("%d:", nwkey.i_defkid);
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (i > 0)
+ printf(",");
+ if (nwkey.i_key[i].i_keylen < 0)
+ printf("persist");
+ else
+ print_string(nwkey.i_key[i].i_keydat,
+ nwkey.i_key[i].i_keylen);
+ if (!nwkey_verbose)
+ break;
+ }
+ }
+ printf("\n");
+
+ skip_wep:
+ if (direct_ioctl(env, SIOCG80211POWER, &power) == -1)
+ goto skip_power;
+ printf("\tpowersave ");
+ if (power.i_enabled)
+ printf("on (%dms sleep)", power.i_maxsleep);
+ else
+ printf("off");
+ printf("\n");
+
+ skip_power:
+ if (direct_ioctl(env, SIOCG80211BSSID, &bssid) == -1)
+ return;
+ if (direct_ioctl(env, SIOCG80211CHANNEL, &channel) == -1)
+ return;
+ if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) {
+ if (channel.i_channel != (u_int16_t)-1)
+ printf("\tchan %d\n", channel.i_channel);
+ } else {
+ memcpy(ea.ether_addr_octet, bssid.i_bssid,
+ sizeof(ea.ether_addr_octet));
+ printf("\tbssid %s", ether_ntoa(&ea));
+ if (channel.i_channel != IEEE80211_CHAN_ANY)
+ printf(" chan %d", channel.i_channel);
+ printf("\n");
+ }
+}
+
+static void
+scan_and_wait(prop_dictionary_t env)
+{
+ int sroute;
+
+ sroute = prog_socket(PF_ROUTE, SOCK_RAW, 0);
+ if (sroute < 0) {
+ warn("socket(PF_ROUTE,SOCK_RAW)");
+ return;
+ }
+ /* NB: only root can trigger a scan so ignore errors */
+ if (set80211(env, IEEE80211_IOC_SCAN_REQ, 0, 0, NULL) >= 0) {
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+
+ do {
+ if (prog_read(sroute, buf, sizeof(buf)) < 0) {
+ warn("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);
+ }
+ prog_close(sroute);
+}
+
+static void
+list_scan(prop_dictionary_t env)
+{
+ u_int8_t buf[24*1024];
+ struct ieee80211req ireq;
+ char ssid[IEEE80211_NWID_LEN+1];
+ const u_int8_t *cp;
+ int len, ssidmax;
+
+ memset(&ireq, 0, sizeof(ireq));
+ ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
+ ireq.i_data = buf;
+ ireq.i_len = sizeof(buf);
+ if (direct_ioctl(env, SIOCG80211, &ireq) < 0)
+ errx(EXIT_FAILURE, "unable to get scan results");
+ len = ireq.i_len;
+ if (len < (int)sizeof(struct ieee80211req_scan_result))
+ return;
+
+ ssidmax = IEEE80211_NWID_LEN;
+ printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
+ , ssidmax, ssidmax, "SSID"
+ , "BSSID"
+ , "CHAN"
+ , "RATE"
+ , "S:N"
+ , "INT"
+ , "CAPS"
+ );
+ cp = buf;
+ do {
+ const struct ieee80211req_scan_result *sr;
+ const uint8_t *vp;
+
+ sr = (const struct ieee80211req_scan_result *) cp;
+ vp = (const u_int8_t *)(sr+1);
+ printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
+ , ssidmax
+ , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
+ , 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, sr->isr_noise
+ , sr->isr_intval
+ , getcaps(sr->isr_capinfo)
+ );
+ printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
+ printf("\n");
+ cp += sr->isr_len, len -= sr->isr_len;
+ } while (len >= (int)sizeof(struct ieee80211req_scan_result));
+}
+/*
+ * Convert MHz frequency to IEEE channel number.
+ */
+static u_int
+ieee80211_mhz2ieee(u_int isrfreq, u_int isrflags)
+{
+ if ((isrflags & IEEE80211_CHAN_GSM) || (907 <= isrfreq && isrfreq <= 922))
+ return mapgsm(isrfreq, isrflags);
+ if (isrfreq == 2484)
+ return 14;
+ if (isrfreq < 2484)
+ return (isrfreq - 2407) / 5;
+ if (isrfreq < 5000) {
+ if (isrflags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER))
+ return mappsb(isrfreq, isrflags);
+ else if (isrfreq > 4900)
+ return (isrfreq - 4000) / 5;
+ else
+ return 15 + ((isrfreq - 2512) / 20);
+ }
+ return (isrfreq - 5000) / 5;
+}
+
+static int
+getmaxrate(const u_int8_t rates[15], u_int8_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 void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+ printf("%s", tag);
+
+ maxlen -= strlen(tag)+2;
+ if ((int)(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 (!vflag)
+ 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 (vflag) {
+ 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 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 (vflag) {
+ 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)
+{
+ const char *sep;
+ int n;
+
+ printf("%s", tag);
+ if (!vflag)
+ return;
+
+ 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(">");
+}
+
+/*
+ * 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, 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;
+ size_t 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 int
+iswpaoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static 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 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 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_CHANSWITCHANN: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 (vflag)
+ printssid(" SSID", vp, 2+vp[1], maxcols);
+ break;
+ case IEEE80211_ELEMID_RATES:
+ case IEEE80211_ELEMID_XRATES:
+ if (vflag)
+ printrates(vp[0] == IEEE80211_ELEMID_RATES ?
+ " RATES" : " XRATES", vp, 2+vp[1], maxcols);
+ break;
+ case IEEE80211_ELEMID_DSPARMS:
+ if (vflag)
+ printf(" DSPARMS<%u>", vp[2]);
+ break;
+ case IEEE80211_ELEMID_COUNTRY:
+ if (vflag)
+ printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
+ break;
+ case IEEE80211_ELEMID_ERP:
+ if (vflag)
+ 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 (vflag)
+ printie(" VEN", vp, 2+vp[1], maxcols);
+ break;
+ case IEEE80211_ELEMID_RSN:
+ printrsnie(" RSN", vp, 2+vp[1], maxcols);
+ break;
+ default:
+ if (vflag)
+ printie(iename(vp[0]), vp, 2+vp[1], maxcols);
+ break;
+ }
+ ielen -= 2+vp[1];
+ vp += 2+vp[1];
+ }
+}
+
+static int
+mapgsm(u_int isrfreq, u_int isrflags)
+{
+ isrfreq *= 10;
+ if (isrflags & IEEE80211_CHAN_QUARTER)
+ isrfreq += 5;
+ else if (isrflags & IEEE80211_CHAN_HALF)
+ isrfreq += 10;
+ else
+ isrfreq += 20;
+ /* NB: there is no 907/20 wide but leave room */
+ return (isrfreq - 906*10) / 5;
+}
+
+static int
+mappsb(u_int isrfreq, u_int isrflags)
+{
+ return 37 + ((isrfreq * 10) + ((isrfreq % 5) == 2 ? 5 : 0) - 49400) / 5;
+}
+
+static status_func_t status;
+static usage_func_t usage;
+static statistics_func_t statistics;
+static cmdloop_branch_t branch[2];
+
+static void
+ieee80211_usage(prop_dictionary_t env)
+{
+ fprintf(stderr,
+ "\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
+ "\t[ list scan ]\n"
+ "\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
+ "\t[ hidessid | -hidessid ] [ apbridge | -apbridge ]\n");
+}
+
+static void
+ieee80211_constructor(void)
+{
+ cmdloop_branch_init(&branch[0], &ieee80211bool.pk_parser);
+ cmdloop_branch_init(&branch[1], &kw80211.pk_parser);
+ register_cmdloop_branch(&branch[0]);
+ register_cmdloop_branch(&branch[1]);
+ status_func_init(&status, ieee80211_status);
+ statistics_func_init(&statistics, ieee80211_statistics);
+ usage_func_init(&usage, ieee80211_usage);
+ register_status(&status);
+ register_statistics(&statistics);
+ register_usage(&usage);
+}
--- /dev/null
+.\" $NetBSD: ifconfig.8,v 1.109 2014/10/20 14:50:09 roy Exp $
+.\"
+.\" 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.
+.\" 3. 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.
+.\"
+.\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94
+.\"
+.Dd October 12, 2014
+.Dt IFCONFIG 8
+.Os
+.Sh NAME
+.Nm ifconfig
+.Nd configure network interface parameters
+.Sh SYNOPSIS
+.Nm
+.Op Fl N
+.Ar interface address_family
+.Oo
+.Ar address
+.Op Ar dest_address
+.Oc
+.Op Ar parameters
+.Nm
+.Op Fl hLmNvz
+.Ar interface
+.Op Ar protocol_family
+.Nm
+.Fl a
+.Op Fl bdhLNmsuvz
+.Op Ar protocol_family
+.Nm
+.Fl l
+.Op Fl bdsu
+.Nm
+.Fl s
+.Ar interface
+.Nm
+.Fl w
+.Ar secs
+.Nm
+.Fl C
+.Sh DESCRIPTION
+.Nm
+is used to assign an address
+to a network interface and/or configure
+network interface parameters.
+.Nm
+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
+Available operands for
+.Nm :
+.Bl -tag -width Ds
+.It Ar address
+For the
+.Tn DARPA-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 .
+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
+.Pq 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 Ethernet 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
+.Pq carefully
+count out long strings of digits in network byte order.
+.It Ar address_family
+Specifies the
+.Ar 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 iso ,
+and
+.Dq link .
+.It Ar interface
+The
+.Ar interface
+parameter is a string of the form
+.Dq name unit ,
+for example,
+.Dq en0
+.El
+.Pp
+The following parameters may be set with
+.Nm :
+.Bl -tag -width dest_addressxx
+.It Cm active
+This keyword applies when
+.Nm
+adds or modifies any link-layer address.
+It indicates that
+.Nm
+should
+.Dq activate
+the address.
+Activation makes an address the default source for transmissions
+on the interface.
+You may not delete the active address from an interface.
+You must activate some other address, first.
+.It Cm advbase Ar n
+If the driver is a
+.Xr carp 4
+pseudo-device, set the base advertisement interval to
+.Ar n
+seconds.
+This ia an 8-bit number; the default value is 1 second.
+.It Cm advskew Ar n
+If the driver is a
+.Xr carp 4
+pseudo-device, skew the advertisement interval by
+.Ar n .
+This is an 8-bit number; the default value is 0.
+.Pp
+Taken together the
+.Cm advbase
+indicate how frequently, in seconds, the host will advertise the fact that it
+considers itself the master of the virtual host.
+The formula is
+.Cm advbase
++
+.Pf ( Cm advskew
+/ 256).
+If the master does not advertise within three times this interval, this host
+will begin advertising as master.
+.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.
+.It Fl alias
+Remove the specified network address alias.
+.It Cm arp
+Enable the use of the Address Resolution Protocol in mapping
+between network level addresses and link level addresses
+.Pq default .
+This is currently implemented for mapping between
+.Tn DARPA
+Internet
+addresses and Ethernet addresses.
+.It Fl arp
+Disable the use of the Address Resolution Protocol.
+.It Cm anycast
+.Pq inet6 only
+Set the IPv6 anycast address bit.
+.It Fl anycast
+.Pq inet6 only
+Clear the IPv6 anycast address bit.
+.It Cm broadcast Ar mask
+.Pq 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 carpdev Ar iface
+If the driver is a
+.Xr carp 4
+pseudo-device, attach it to
+.Ar iface .
+If not specified, the kernel will attempt to select an interface with
+a subnet matching that of the carp interface.
+.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 delete
+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.
+.Cm delete
+does not work for IPv6 addresses.
+Use
+.Fl alias
+with explicit IPv6 address instead.
+.It Ar dest_address
+Specify the address of the correspondent on the other end
+of a point to point link.
+.It Cm down
+Mark an interface ``down''.
+When an interface is
+marked ``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 ipdst
+This is used to specify an Internet host who is willing to receive
+ip packets encapsulating NS packets bound for a remote network.
+An apparent point to point link is constructed, and
+the address specified will be taken as the NS address and network
+of the destination.
+IP encapsulation of
+.Tn CLNP
+packets is done differently.
+.It Cm media Ar type
+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 10Mb/s Ethernet
+interface might support the use of either
+.Tn AUI
+or twisted pair connectors.
+Setting the media type to
+.Dq 10base5
+or
+.Dq AUI
+would change the currently active connector to the AUI port.
+Setting it to
+.Dq 10baseT
+or
+.Dq UTP
+would activate twisted pair.
+Refer to the interfaces' driver
+specific man page for a complete list of the available types
+and the
+.Xr ifmedia 4
+manual page for a list of media types.
+See the
+.Fl m
+flag below.
+.It Cm mediaopt Ar opts
+Set the specified media options on the interface.
+.Ar opts
+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.
+Also see the
+.Xr ifmedia 4
+manual page for a list of media options.
+.It Fl mediaopt Ar opts
+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 Dq 11a ,
+802.11b
+.Pq Dq 11b ,
+and 802.11g
+.Pq Dq 11g
+operating modes.
+.It Cm instance Ar minst
+Set the media instance to
+.Ar minst .
+This is useful for devices which have multiple physical layer interfaces
+.Pq PHYs .
+Setting the instance on such devices may not be strictly required
+by the network interface driver as the driver may take care of this
+automatically; see the driver's manual page for more information.
+.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 addition hops
+to the destination network or host.
+.It Cm mtu Ar n
+Set the maximum transmission unit of the interface to
+.Ar n .
+Most interfaces don't support this option.
+.It Cm netmask Ar mask
+.Pq inet, inet6, and ISO
+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 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
+For INET and INET6 addresses, the netmask can also be given with
+slash-notation after the address
+.Pq e.g 192.168.17.3/24 .
+.\" 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
+.Pq 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 state Ar state
+Explicitly force the
+.Xr carp 4
+pseudo-device to enter this state.
+Valid states are
+.Ar init ,
+.Ar backup ,
+and
+.Ar master .
+.It Cm frag Ar threshold
+.Pq IEEE 802.11 devices only
+Configure the fragmentation threshold for IEEE 802.11-based wireless
+network interfaces.
+.It Cm rts Ar threshold
+.Pq IEEE 802.11 devices only
+Configure the RTS/CTS threshold for IEEE 802.11-based wireless
+network interfaces.
+This controls the number of bytes used for the RTS/CTS handshake boundary.
+The
+.Ar threshold
+can be any value between 0 and 2347.
+The default is 2347, which indicates the RTS/CTS mechanism should not be used.
+.It Cm ssid Ar id
+.Pq IEEE 802.11 devices only
+Configure the Service Set Identifier (a.k.a. the network name)
+for IEEE 802.11-based wireless network interfaces.
+The
+.Ar id
+can either be any text string up to 32 characters in length,
+or a series of up to 64 hexadecimal digits preceded by
+.Dq 0x .
+Setting
+.Ar id
+to the empty string allows the interface to connect to any available
+access point.
+.It Cm nwid Ar id
+Synonym for
+.Dq ssid .
+.It Cm hidessid
+.Pq IEEE 802.11 devices only
+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.
+.It Fl hidessid
+.Pq IEEE 802.11 devices only
+When operating as an access point, broadcast the SSID
+in beacon frames and answer and respond to undirected probe
+request frames (default).
+.It Cm nwkey Ar key
+.Pq IEEE 802.11 devices only
+Enable WEP encryption for IEEE 802.11-based wireless network interfaces
+with the
+.Ar key .
+The
+.Ar key
+can either be a string, a series of hexadecimal digits preceded by
+.Dq 0x ,
+or a set of keys in the form
+.Ar n:k1,k2,k3,k4 ,
+where
+.Ar n
+specifies which of keys will be used for all transmitted packets,
+and four keys,
+.Ar k1
+through
+.Ar k4 ,
+are configured as WEP keys.
+Note that the order must be match within same network if multiple keys
+are used.
+For IEEE 802.11 wireless network, the length of each key is restricted to
+40 bits, i.e. 5-character string or 10 hexadecimal digits,
+while the WaveLAN/IEEE Gold cards accept the 104 bits
+.Pq 13 characters
+key.
+.It Cm nwkey Cm persist
+.Pq IEEE 802.11 devices only
+Enable WEP encryption for IEEE 802.11-based wireless network interfaces
+with the persistent key written in the network card.
+.It Cm nwkey Cm persist: Ns Ar key
+.Pq IEEE 802.11 devices only
+Write the
+.Ar key
+to the persistent memory of the network card, and
+enable WEP encryption for IEEE 802.11-based wireless network interfaces
+with the
+.Ar key .
+.It Fl nwkey
+.Pq IEEE 802.11 devices only
+Disable WEP encryption for IEEE 802.11-based wireless network interfaces.
+.It Cm apbridge
+.Pq IEEE 802.11 devices only
+When operating as an access point, pass packets between
+wireless clients directly (default).
+.It Fl apbridge
+.Pq IEEE 802.11 devices only
+When operating as an access point, pass packets through
+the system so that they can be forwared using some other mechanism.
+Disabling the internal bridging is useful when traffic
+is to be processed with packet filtering.
+.It Cm pass Ar passphrase
+If the driver is a
+.Xr carp 4
+pseudo-device, set the authentication key to
+.Ar passphrase .
+There is no passphrase by default
+.It Cm powersave
+.Pq IEEE 802.11 devices only
+Enable 802.11 power saving mode.
+.It Fl powersave
+.Pq IEEE 802.11 devices only
+Disable 802.11 power saving mode.
+.It Cm powersavesleep Ar duration
+.Pq IEEE 802.11 devices only
+Set the receiver sleep duration in milliseconds for 802.11 power saving mode.
+.It Cm bssid Ar bssid
+.Pq IEEE 802.11 devices only
+Set the desired BSSID for IEEE 802.11-based wireless network interfaces.
+.It Fl bssid
+.Pq IEEE 802.11 devices only
+Unset the desired BSSID for IEEE 802.11-based wireless network interfaces.
+The interface will automatically select a BSSID in this mode, which is
+the default.
+.It Cm chan Ar chan
+.Pq IEEE 802.11 devices only
+Select the channel
+.Pq radio frequency
+to be used for IEEE 802.11-based wireless network interfaces.
+.It Fl chan
+.Pq IEEE 802.11 devices only
+Unset the desired channel to be used
+for IEEE 802.11-based wireless network interfaces.
+It doesn't affect the channel to be created for IBSS or hostap mode.
+.It Cm list scan
+.Pq IEEE 802.11 devices only
+Display the access points and/or ad-hoc neighbors
+located in the vicinity.
+The
+.Fl v
+flag may be used to display long SSIDs.
+.Fl v
+also causes received information elements to be displayed symbolically.
+The interface must be up before any scanning operation.
+Only the super-user can use this command.
+.It Cm tunnel Ar src_addr Ns Oo Ar ,src_port Oc Ar dest_addr Ns Oo Ar ,dest_port
+.Oc
+.Pq IP tunnel devices only
+Configure the physical source and destination address for IP tunnel
+interfaces, including
+.Xr gif 4 .
+The arguments
+.Ar src_addr
+and
+.Ar dest_addr
+are interpreted as the outer source/destination for the encapsulating
+IPv4/IPv6 header.
+.Pp
+On a
+.Xr gre 4
+interface in UDP mode, the arguments
+.Ar src_port
+and
+.Ar dest_port
+are interpreted as the outer source/destination port for the encapsulating
+UDP header.
+.It Cm deletetunnel
+Unconfigure the physical source and destination address for IP tunnel
+interfaces previously configured with
+.Cm tunnel .
+.It Cm create
+Create the specified network pseudo-device.
+.It Cm destroy
+Destroy the specified network pseudo-device.
+.It Cm pltime Ar n
+.Pq inet6 only
+Set preferred lifetime for the address.
+.It Cm prefixlen Ar n
+.Pq inet and inet6 only
+Effect is similar to
+.Cm netmask .
+but you can specify by prefix length by digits.
+.It Cm deprecated
+.Pq inet6 only
+Set the IPv6 deprecated address bit.
+.It Fl deprecated
+.Pq inet6 only
+Clear the IPv6 deprecated address bit.
+.It Cm eui64
+.Pq inet6 only
+Fill interface index
+.Pq lowermost 64bit of an IPv6 address
+automatically.
+.It Cm link[0-2]
+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.
+.It Fl link[0-2]
+Disable special processing at the link level with the specified interface.
+.It Cm linkstr
+Set a link-level string parameter for the interface.
+This functionality varies from interface to interface.
+Refer to the man page for the specific driver
+for more information.
+.It Fl linkstr
+Remove an interface link-level string parameter.
+.It Cm up
+Mark an interface ``up''.
+This may be used to enable an interface after an ``ifconfig 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.
+.It Cm vhid Ar n
+If the driver is a
+.Xr carp 4
+pseudo-device, set the virtual host ID to
+.Ar n .
+Acceptable values are 1 to 255.
+.It Cm vlan Ar vid
+If the interface is a
+.Xr vlan 4
+pseudo-interface, set the VLAN identifier to
+.Ar vid .
+These are the first 12 bits (0-4095) from a 16-bit integer used
+to create an 802.1Q VLAN header for packets sent from the
+.Xr vlan 4
+interface.
+Note that
+.Cm vlan
+and
+.Cm vlanif
+must be set at the same time.
+.It Cm vlanif Ar iface
+If the interface is a
+.Xr vlan 4
+pseudo-interface, associate the physical interface
+.Ar iface
+with it.
+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 physical interface with the correct VLAN tag will be diverted to the
+associated
+.Xr vlan 4
+pseudo-interface.
+The VLAN interface is assigned a copy of the physical
+interface's flags and
+.Tn Ethernet
+address.
+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.
+Note that
+.Cm vlanif
+and
+.Cm vlan
+must be set at the same time.
+.It Cm -vlanif Ar iface
+Dissociate
+.Ar iface
+from the
+.Xr vlan 4
+interface.
+.It Cm agrport Ar iface
+Add
+.Ar iface
+to the
+.Xr agr 4
+interface.
+.It Cm -agrport Ar iface
+Remove
+.Ar iface
+from the
+.Xr agr 4
+interface.
+.It Cm vltime Ar n
+.Pq inet6 only
+Set valid lifetime for the address.
+.It Cm ip4csum
+Shorthand of
+.Dq ip4csum-tx ip4csum-rx
+.It Cm -ip4csum
+Shorthand of
+.Dq -ip4csum-tx -ip4csum-rx
+.It Cm tcp4csum
+Shorthand of
+.Dq tcp4csum-tx tcp4csum-rx
+.It Cm -tcp4csum
+Shorthand of
+.Dq -tcp4csum-tx -tcp4csum-rx
+.It Cm udp4csum
+Shorthand of
+.Dq udp4csum-tx udp4csum-rx
+.It Cm -udp4csum
+Shorthand of
+.Dq -udp4csum-tx -udp4csum-rx
+.It Cm tcp6csum
+Shorthand of
+.Dq tcp6csum-tx tcp6csum-rx
+.It Cm -tcp6csum
+Shorthand of
+.Dq -tcp6csum-tx -tcp6csum-rx
+.It Cm udp6csum
+Shorthand of
+.Dq udp6csum-tx udp6csum-rx
+.It Cm -udp6csum
+Shorthand of
+.Dq -udp6csum-tx -udp6csum-rx
+.It Cm ip4csum-tx
+Enable hardware-assisted IPv4 header checksums for the out-bound direction.
+.It Cm -ip4csum-tx
+Disable hardware-assisted IPv4 header checksums for the out-bound direction.
+.It Cm ip4csum-rx
+Enable hardware-assisted IPv4 header checksums for the in-bound direction.
+.It Cm -ip4csum-rx
+Disable hardware-assisted IPv4 header checksums for the in-bound direction.
+.It Cm tcp4csum-tx
+Enable hardware-assisted TCP/IPv4 checksums for the out-bound direction.
+.It Cm -tcp4csum-tx
+Disable hardware-assisted TCP/IPv4 checksums for the out-bound direction.
+.It Cm tcp4csum-rx
+Enable hardware-assisted TCP/IPv4 checksums for the in-bound direction.
+.It Cm -tcp4csum-rx
+Disable hardware-assisted TCP/IPv4 checksums for the in-bound direction.
+.It Cm udp4csum-tx
+Enable hardware-assisted UDP/IPv4 checksums for the out-bound direction.
+.It Cm -udp4csum-tx
+Disable hardware-assisted UDP/IPv4 checksums for the out-bound direction.
+.It Cm udp4csum-rx
+Enable hardware-assisted UDP/IPv4 checksums for the in-bound direction.
+.It Cm -udp4csum-rx
+Disable hardware-assisted UDP/IPv4 checksums for the in-bound direction.
+.It Cm tcp6csum-tx
+Enable hardware-assisted TCP/IPv6 checksums for the out-bound direction.
+.It Cm -tcp6csum-tx
+Disable hardware-assisted TCP/IPv6 checksums for the out-bound direction.
+.It Cm tcp6csum-rx
+Enable hardware-assisted TCP/IPv6 checksums for the in-bound direction.
+.It Cm -tcp6csum-rx
+Disable hardware-assisted TCP/IPv6 checksums for the in-bound direction.
+.It Cm udp6csum-tx
+Enable hardware-assisted UDP/IPv6 checksums for the out-bound direction.
+.It Cm -udp6csum-tx
+Disable hardware-assisted UDP/IPv6 checksums for the out-bound direction.
+.It Cm udp6csum-rx
+Enable hardware-assisted UDP/IPv6 checksums for the in-bound direction.
+.It Cm -udp6csum-rx
+Disable hardware-assisted UDP/IPv6 checksums for the in-bound direction.
+.It Cm tso4
+Enable hardware-assisted TCP/IPv4 segmentation on interfaces that
+support it.
+.It Cm -tso4
+Disable hardware-assisted TCP/IPv4 segmentation on interfaces that
+support it.
+.It Cm tso6
+Enable hardware-assisted TCP/IPv6 segmentation on interfaces that
+support it.
+.It Cm -tso6
+Disable hardware-assisted TCP/IPv6 segmentation on interfaces that
+support it.
+.It Cm maxupd Ar n
+If the driver is a
+.Xr pfsync 4
+pseudo-device, indicate 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.
+.It Cm syncdev Ar iface
+If the driver is a
+.Xr pfsync 4
+pseudo-device, use the specified interface
+to send and receive pfsync state synchronisation messages.
+.It Fl syncdev
+If the driver is a
+.Xr pfsync 4
+pseudo-device, stop sending pfsync state
+synchronisation messages over the network.
+.It Cm syncpeer Ar peer_address
+If the driver is a
+.Xr pfsync 4
+pseudo-device, make the pfsync link point-to-point rather than using
+multicast to broadcast the state synchronisation messages.
+The peer_address is the IP address of the other host taking part in
+the pfsync cluster.
+With this option,
+.Xr pfsync 4
+traffic can be protected using
+.Xr ipsec 4 .
+.It Fl syncpeer
+If the driver is a
+.Xr pfsync 4
+pseudo-device, broadcast the packets using multicast.
+.El
+.Pp
+.Nm
+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 s
+flag is passed before an interface name,
+.Nm
+will attempt to query the interface for its media status.
+If the
+interface supports reporting media status, and it reports that it does
+not appear to be connected to a network,
+.Nm
+will exit with status of 1
+.Pq false ;
+otherwise, it will exit with a
+zero
+.Pq true
+exit status.
+Not all interface drivers support media
+status reporting.
+.Pp
+If the
+.Fl m
+flag is passed before an interface name,
+.Nm
+will display all of the supported media for the specified interface.
+If the
+.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.
+This is also the default behaviour when no arguments are given to
+.Nm
+on the command line.
+When
+.Fl a
+is used, the output can be modified by adding more flags:
+.Fl d
+limits this to interfaces that are down,
+.Fl u
+limits this to interfaces that are up,
+.Fl b
+limits this to broadcast interfaces, and
+.Fl s
+omits interfaces which appear not to be connected to a network.
+.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
+.Pq only list interfaces that are down ,
+.Fl u
+.Pq only list interfaces that are up ,
+.Fl s
+.Pq only list interfaces that may be connected ,
+.Fl b
+.Pq only list broadcast interfaces .
+.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 v
+flag prints statistics on packets sent and received on the given
+interface.
+If
+.Fl h
+is used in conjunction with
+.Fl v ,
+the byte statistics will be printed in "human-readable" format.
+The
+.Fl z
+flag is identical to the
+.Fl v
+flag except that it zeros the interface input and output statistics
+after printing them.
+.Pp
+The
+.Fl w
+flag may be used to wait
+.Ar seconds
+seconds for the
+.Cm tentative
+flag to be removed from all addresses.
+0 seconds means to wait indefinitely until all addresses no longer have the
+.Cm tentative
+flag.
+.Pp
+The
+.Fl N
+flag is just the opposite of the
+.Fl n
+flag in
+.Xr netstat 1
+or in
+.Xr route 8 :
+it tells
+.Nm
+to try to resolve numbers to hostnames or to service names.
+The default
+.Nm
+behavior is to print numbers instead of names.
+.Pp
+Only the super-user may modify the configuration of a network interface.
+.Sh EXAMPLES
+Add a link-layer (MAC) address to an Ethernet:
+.Pp
+.Ic ifconfig sip0 link 00:11:22:33:44:55
+.Pp
+Add and activate a link-layer (MAC) address:
+.Pp
+.Ic ifconfig sip0 link 00:11:22:33:44:55 active
+.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 agr 4 ,
+.Xr carp 4 ,
+.Xr ifmedia 4 ,
+.Xr netintro 4 ,
+.Xr pfsync 4 ,
+.Xr vlan 4 ,
+.Xr ifconfig.if 5 ,
+.\" .Xr eon 5 ,
+.Xr rc 8 ,
+.Xr routed 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
--- /dev/null
+/* $NetBSD: ifconfig.c,v 1.235 2015/07/29 07:42:27 ozaki-r Exp $ */
+
+/*-
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1993\
+ The Regents of the University of California. All rights reserved.");
+__RCSID("$NetBSD: ifconfig.c,v 1.235 2015/07/29 07:42:27 ozaki-r Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+#include <netinet/in.h> /* XXX */
+#include <netinet/in_var.h> /* XXX */
+
+#include <netdb.h>
+
+#include <sys/protosw.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <util.h>
+
+#include "extern.h"
+
+#include "media.h"
+#include "parse.h"
+#include "env.h"
+#include "prog_ops.h"
+
+#define WAIT_DAD 10000000 /* nanoseconds between each poll, 10ms */
+
+static bool bflag, dflag, hflag, sflag, uflag, wflag;
+bool lflag, Nflag, vflag, zflag;
+static long wflag_secs;
+
+static char gflags[10 + 26 * 2 + 1] = "AabCdhlNsuvw:z";
+bool gflagset[10 + 26 * 2];
+
+static int carrier(prop_dictionary_t);
+static int clone_command(prop_dictionary_t, prop_dictionary_t);
+static void do_setifpreference(prop_dictionary_t);
+static int flag_index(int);
+static void init_afs(void);
+static int list_cloners(prop_dictionary_t, prop_dictionary_t);
+static int media_status_exec(prop_dictionary_t, prop_dictionary_t);
+static int wait_dad_exec(prop_dictionary_t, prop_dictionary_t);
+static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t);
+static int notrailers(prop_dictionary_t, prop_dictionary_t);
+static void printall(const char *, prop_dictionary_t);
+static int setifaddr(prop_dictionary_t, prop_dictionary_t);
+static int setifbroadaddr(prop_dictionary_t, prop_dictionary_t);
+static int setifcaps(prop_dictionary_t, prop_dictionary_t);
+static int setifdstormask(prop_dictionary_t, prop_dictionary_t);
+static int setifflags(prop_dictionary_t, prop_dictionary_t);
+static int setifmetric(prop_dictionary_t, prop_dictionary_t);
+static int setifmtu(prop_dictionary_t, prop_dictionary_t);
+static int setifnetmask(prop_dictionary_t, prop_dictionary_t);
+static int setifprefixlen(prop_dictionary_t, prop_dictionary_t);
+static int setlinkstr(prop_dictionary_t, prop_dictionary_t);
+static int unsetlinkstr(prop_dictionary_t, prop_dictionary_t);
+static void status(const struct sockaddr *, prop_dictionary_t,
+ prop_dictionary_t);
+__dead static void usage(void);
+
+static const struct kwinst ifflagskw[] = {
+ IFKW("arp", -IFF_NOARP)
+ , IFKW("debug", IFF_DEBUG)
+ , IFKW("link0", IFF_LINK0)
+ , IFKW("link1", IFF_LINK1)
+ , IFKW("link2", IFF_LINK2)
+ , {.k_word = "down", .k_type = KW_T_INT, .k_int = -IFF_UP}
+ , {.k_word = "up", .k_type = KW_T_INT, .k_int = IFF_UP}
+};
+
+static const struct kwinst ifcapskw[] = {
+ IFKW("ip4csum-tx", IFCAP_CSUM_IPv4_Tx)
+ , IFKW("ip4csum-rx", IFCAP_CSUM_IPv4_Rx)
+ , IFKW("tcp4csum-tx", IFCAP_CSUM_TCPv4_Tx)
+ , IFKW("tcp4csum-rx", IFCAP_CSUM_TCPv4_Rx)
+ , IFKW("udp4csum-tx", IFCAP_CSUM_UDPv4_Tx)
+ , IFKW("udp4csum-rx", IFCAP_CSUM_UDPv4_Rx)
+ , IFKW("tcp6csum-tx", IFCAP_CSUM_TCPv6_Tx)
+ , IFKW("tcp6csum-rx", IFCAP_CSUM_TCPv6_Rx)
+ , IFKW("udp6csum-tx", IFCAP_CSUM_UDPv6_Tx)
+ , IFKW("udp6csum-rx", IFCAP_CSUM_UDPv6_Rx)
+ , IFKW("ip4csum", IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx)
+ , IFKW("tcp4csum", IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx)
+ , IFKW("udp4csum", IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx)
+ , IFKW("tcp6csum", IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx)
+ , IFKW("udp6csum", IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx)
+ , IFKW("tso4", IFCAP_TSOv4)
+ , IFKW("tso6", IFCAP_TSOv6)
+};
+
+extern struct pbranch command_root;
+extern struct pbranch opt_command;
+extern struct pbranch opt_family, opt_silent_family;
+extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc;
+extern struct pstr parse_linkstr;
+
+struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10,
+ setifmetric, "metric", &command_root.pb_parser);
+
+struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10,
+ setifmtu, "mtu", &command_root.pb_parser);
+
+struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen,
+ "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser);
+
+struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference,
+ "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference",
+ &command_root.pb_parser);
+
+struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask",
+ setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser);
+
+struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast,
+ "broadcast address",
+ setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser);
+
+static const struct kwinst misckw[] = {
+ {.k_word = "alias", .k_key = "alias", .k_deact = "alias",
+ .k_type = KW_T_BOOL, .k_neg = true,
+ .k_bool = true, .k_negbool = false,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "broadcast", .k_nextparser = &parse_broadcast.pa_parser}
+ , {.k_word = "delete", .k_key = "alias", .k_deact = "alias",
+ .k_type = KW_T_BOOL, .k_bool = false,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "metric", .k_nextparser = &parse_metric.pi_parser}
+ , {.k_word = "mtu", .k_nextparser = &parse_mtu.pi_parser}
+ , {.k_word = "netmask", .k_nextparser = &parse_netmask.pa_parser}
+ , {.k_word = "preference", .k_act = "address",
+ .k_nextparser = &parse_preference.pi_parser}
+ , {.k_word = "prefixlen", .k_nextparser = &parse_prefixlen.pi_parser}
+ , {.k_word = "trailers", .k_neg = true,
+ .k_exec = notrailers, .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "linkstr", .k_nextparser = &parse_linkstr.ps_parser }
+ , {.k_word = "-linkstr", .k_exec = unsetlinkstr,
+ .k_nextparser = &command_root.pb_parser }
+};
+
+/* key: clonecmd */
+static const struct kwinst clonekw[] = {
+ {.k_word = "create", .k_type = KW_T_INT, .k_int = SIOCIFCREATE,
+ .k_nextparser = &opt_silent_family.pb_parser},
+ {.k_word = "destroy", .k_type = KW_T_INT, .k_int = SIOCIFDESTROY}
+};
+
+static struct kwinst familykw[24];
+
+struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners",
+ list_cloners, "none");
+
+struct pterm wait_dad = PTERM_INITIALIZER(&wait_dad, "wait DAD", wait_dad_exec,
+ "none");
+
+struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec,
+ "none");
+
+struct pkw family_only =
+ PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw,
+ __arraycount(familykw), &no_cmds.pt_parser);
+
+struct paddr address = PADDR_INITIALIZER(&address,
+ "local address (address 1)",
+ setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser);
+
+struct paddr dstormask = PADDR_INITIALIZER(&dstormask,
+ "destination/netmask (address 2)",
+ setifdstormask, "dstormask", NULL, "address", "dstormask",
+ &command_root.pb_parser);
+
+struct paddr broadcast = PADDR_INITIALIZER(&broadcast,
+ "broadcast address (address 3)",
+ setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast",
+ &command_root.pb_parser);
+
+struct pstr parse_linkstr = PSTR_INITIALIZER(&parse_linkstr, "linkstr",
+ setlinkstr, "linkstr", &command_root.pb_parser);
+
+static SIMPLEQ_HEAD(, afswtch) aflist = SIMPLEQ_HEAD_INITIALIZER(aflist);
+
+static SIMPLEQ_HEAD(, usage_func) usage_funcs =
+ SIMPLEQ_HEAD_INITIALIZER(usage_funcs);
+static SIMPLEQ_HEAD(, status_func) status_funcs =
+ SIMPLEQ_HEAD_INITIALIZER(status_funcs);
+static SIMPLEQ_HEAD(, statistics_func) statistics_funcs =
+ SIMPLEQ_HEAD_INITIALIZER(statistics_funcs);
+static SIMPLEQ_HEAD(, cmdloop_branch) cmdloop_branches =
+ SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches);
+
+struct branch opt_clone_brs[] = {
+ {.b_nextparser = &cloning.pk_parser}
+ , {.b_nextparser = &opt_family.pb_parser}
+}, opt_silent_family_brs[] = {
+ {.b_nextparser = &silent_family.pk_parser}
+ , {.b_nextparser = &command_root.pb_parser}
+}, opt_family_brs[] = {
+ {.b_nextparser = &family.pk_parser}
+ , {.b_nextparser = &opt_command.pb_parser}
+}, command_root_brs[] = {
+ {.b_nextparser = &ifflags.pk_parser}
+ , {.b_nextparser = &ifcaps.pk_parser}
+ , {.b_nextparser = &kwmedia.pk_parser}
+ , {.b_nextparser = &misc.pk_parser}
+ , {.b_nextparser = &address.pa_parser}
+ , {.b_nextparser = &dstormask.pa_parser}
+ , {.b_nextparser = &broadcast.pa_parser}
+ , {.b_nextparser = NULL}
+}, opt_command_brs[] = {
+ {.b_nextparser = &no_cmds.pt_parser}
+ , {.b_nextparser = &command_root.pb_parser}
+};
+
+struct branch opt_family_only_brs[] = {
+ {.b_nextparser = &no_cmds.pt_parser}
+ , {.b_nextparser = &family_only.pk_parser}
+};
+struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only,
+ "opt-family-only", opt_family_only_brs,
+ __arraycount(opt_family_only_brs), true);
+struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command,
+ "optional command",
+ opt_command_brs, __arraycount(opt_command_brs), true);
+
+struct pbranch command_root = PBRANCH_INITIALIZER(&command_root,
+ "command-root", command_root_brs, __arraycount(command_root_brs), true);
+
+struct piface iface_opt_family_only =
+ PIFACE_INITIALIZER(&iface_opt_family_only, "iface-opt-family-only",
+ NULL, "if", &opt_family_only.pb_parser);
+
+struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af",
+ familykw, __arraycount(familykw), &opt_command.pb_parser);
+
+struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family",
+ NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser);
+
+struct pkw *family_users[] = {&family_only, &family, &silent_family};
+
+struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps,
+ "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser);
+
+struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags,
+ "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser);
+
+struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command,
+ "clonecmd", clonekw, __arraycount(clonekw), NULL);
+
+struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL,
+ misckw, __arraycount(misckw), NULL);
+
+struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone,
+ "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true);
+
+struct pbranch opt_silent_family = PBRANCH_INITIALIZER(&opt_silent_family,
+ "optional silent family", opt_silent_family_brs,
+ __arraycount(opt_silent_family_brs), true);
+
+struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family,
+ "opt-family", opt_family_brs, __arraycount(opt_family_brs), true);
+
+struct piface iface_start = PIFACE_INITIALIZER(&iface_start,
+ "iface-opt-family", NULL, "if", &opt_clone.pb_parser);
+
+struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface",
+ media_status_exec, "if", NULL);
+
+static bool
+flag_is_registered(const char *flags, int flag)
+{
+ return flags != NULL && strchr(flags, flag) != NULL;
+}
+
+static int
+check_flag(const char *flags, int flag)
+{
+ if (flag_is_registered(flags, flag)) {
+ errno = EEXIST;
+ return -1;
+ }
+
+ if (flag >= '0' && flag <= '9')
+ return 0;
+ if (flag >= 'a' && flag <= 'z')
+ return 0;
+ if (flag >= 'A' && flag <= 'Z')
+ return 0;
+
+ errno = EINVAL;
+ return -1;
+}
+
+void
+cmdloop_branch_init(cmdloop_branch_t *b, struct parser *p)
+{
+ b->b_parser = p;
+}
+
+void
+statistics_func_init(statistics_func_t *f, statistics_cb_t func)
+{
+ f->f_func = func;
+}
+
+void
+status_func_init(status_func_t *f, status_cb_t func)
+{
+ f->f_func = func;
+}
+
+void
+usage_func_init(usage_func_t *f, usage_cb_t func)
+{
+ f->f_func = func;
+}
+
+int
+register_cmdloop_branch(cmdloop_branch_t *b)
+{
+ SIMPLEQ_INSERT_TAIL(&cmdloop_branches, b, b_next);
+ return 0;
+}
+
+int
+register_statistics(statistics_func_t *f)
+{
+ SIMPLEQ_INSERT_TAIL(&statistics_funcs, f, f_next);
+ return 0;
+}
+
+int
+register_status(status_func_t *f)
+{
+ SIMPLEQ_INSERT_TAIL(&status_funcs, f, f_next);
+ return 0;
+}
+
+int
+register_usage(usage_func_t *f)
+{
+ SIMPLEQ_INSERT_TAIL(&usage_funcs, f, f_next);
+ return 0;
+}
+
+int
+register_family(struct afswtch *af)
+{
+ SIMPLEQ_INSERT_TAIL(&aflist, af, af_next);
+ return 0;
+}
+
+int
+register_flag(int flag)
+{
+ if (check_flag(gflags, flag) == -1)
+ return -1;
+
+ if (strlen(gflags) + 1 >= sizeof(gflags)) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ gflags[strlen(gflags)] = flag;
+
+ return 0;
+}
+
+static int
+flag_index(int flag)
+{
+ if (flag >= '0' && flag <= '9')
+ return flag - '0';
+ if (flag >= 'a' && flag <= 'z')
+ return 10 + flag - 'a';
+ if (flag >= 'A' && flag <= 'Z')
+ return 10 + 26 + flag - 'a';
+
+ errno = EINVAL;
+ return -1;
+}
+
+static bool
+set_flag(int flag)
+{
+ int idx;
+
+ if ((idx = flag_index(flag)) == -1)
+ return false;
+
+ return gflagset[idx] = true;
+}
+
+bool
+get_flag(int flag)
+{
+ int idx;
+
+ if ((idx = flag_index(flag)) == -1)
+ return false;
+
+ return gflagset[idx];
+}
+
+static struct parser *
+init_parser(void)
+{
+ cmdloop_branch_t *b;
+
+ if (parser_init(&iface_opt_family_only.pif_parser) == -1)
+ err(EXIT_FAILURE, "parser_init(iface_opt_family_only)");
+ if (parser_init(&iface_only.pif_parser) == -1)
+ err(EXIT_FAILURE, "parser_init(iface_only)");
+ if (parser_init(&iface_start.pif_parser) == -1)
+ err(EXIT_FAILURE, "parser_init(iface_start)");
+
+ SIMPLEQ_FOREACH(b, &cmdloop_branches, b_next)
+ pbranch_addbranch(&command_root, b->b_parser);
+
+ return &iface_start.pif_parser;
+}
+
+static int
+no_cmds_exec(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const char *ifname;
+ unsigned short ignore;
+
+ /* ifname == NULL is ok. It indicates 'ifconfig -a'. */
+ if ((ifname = getifname(env)) == NULL)
+ ;
+ else if (getifflags(env, oenv, &ignore) == -1)
+ err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname);
+
+ printall(ifname, env);
+ exit(EXIT_SUCCESS);
+}
+
+static int
+wait_dad_exec(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool waiting;
+ struct ifaddrs *ifaddrs, *ifa;
+ const struct timespec ts = { .tv_sec = 0, .tv_nsec = WAIT_DAD };
+ const struct timespec add = { .tv_sec = wflag_secs, .tv_nsec = 0};
+ struct timespec now, end = { .tv_sec = wflag_secs, .tv_nsec = 0};
+ const struct afswtch *afp;
+
+ if (wflag_secs) {
+ if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
+ err(EXIT_FAILURE, "clock_gettime");
+ timespecadd(&now, &add, &end);
+ }
+
+ if (getifaddrs(&ifaddrs) == -1)
+ err(EXIT_FAILURE, "getifaddrs");
+
+ for (;;) {
+ waiting = false;
+ for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ afp = lookup_af_bynum(ifa->ifa_addr->sa_family);
+ if (afp && afp->af_addr_tentative &&
+ afp->af_addr_tentative(ifa))
+ {
+ waiting = true;
+ break;
+ }
+ }
+ if (!waiting)
+ break;
+ nanosleep(&ts, NULL);
+ if (wflag_secs) {
+ if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
+ err(EXIT_FAILURE, "clock_gettime");
+ if (timespeccmp(&now, &end, >))
+ errx(EXIT_FAILURE, "timed out");
+ }
+ }
+
+ freeifaddrs(ifaddrs);
+ exit(EXIT_SUCCESS);
+}
+
+static int
+media_status_exec(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const char *ifname;
+ unsigned short ignore;
+
+ /* ifname == NULL is ok. It indicates 'ifconfig -a'. */
+ if ((ifname = getifname(env)) == NULL)
+ ;
+ else if (getifflags(env, oenv, &ignore) == -1)
+ err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname);
+
+ exit(carrier(env));
+}
+
+static void
+do_setifcaps(prop_dictionary_t env)
+{
+ struct ifcapreq ifcr;
+ prop_data_t d;
+
+ d = (prop_data_t )prop_dictionary_get(env, "ifcaps");
+ if (d == NULL)
+ return;
+
+ assert(sizeof(ifcr) == prop_data_size(d));
+
+ memcpy(&ifcr, prop_data_data_nocopy(d), sizeof(ifcr));
+ if (direct_ioctl(env, SIOCSIFCAP, &ifcr) == -1)
+ err(EXIT_FAILURE, "SIOCSIFCAP");
+}
+
+int
+main(int argc, char **argv)
+{
+ const struct afswtch *afp;
+ int af, s;
+ bool aflag = false, Cflag = false;
+ struct match match[32];
+ size_t nmatch;
+ struct parser *start;
+ int ch, narg = 0, rc;
+ prop_dictionary_t env, oenv;
+ const char *ifname;
+ char *end;
+
+ memset(match, 0, sizeof(match));
+
+ init_afs();
+
+ start = init_parser();
+
+ /* Parse command-line options */
+ Nflag = vflag = zflag = false;
+ aflag = argc == 1 ? true : false;
+ if (aflag)
+ start = &opt_family_only.pb_parser;
+
+ while ((ch = getopt(argc, argv, gflags)) != -1) {
+ switch (ch) {
+ case 'A':
+ warnx("-A is deprecated");
+ break;
+
+ case 'a':
+ aflag = true;
+ break;
+
+ case 'b':
+ bflag = true;
+ break;
+
+ case 'C':
+ Cflag = true;
+ break;
+
+ case 'd':
+ dflag = true;
+ break;
+ case 'h':
+ hflag = true;
+ break;
+ case 'l':
+ lflag = true;
+ break;
+ case 'N':
+ Nflag = true;
+ break;
+
+ case 's':
+ sflag = true;
+ break;
+
+ case 'u':
+ uflag = true;
+ break;
+
+ case 'v':
+ vflag = true;
+ break;
+
+ case 'w':
+ wflag = true;
+ wflag_secs = strtol(optarg, &end, 10);
+ if ((end != NULL && *end != '\0') ||
+ wflag_secs < 0 || wflag_secs >= INT32_MAX)
+ errx(EXIT_FAILURE, "%s: not a number", optarg);
+ break;
+
+ case 'z':
+ zflag = true;
+ break;
+
+ default:
+ if (!set_flag(ch))
+ usage();
+ break;
+ }
+ switch (ch) {
+ case 'a':
+ start = &opt_family_only.pb_parser;
+ break;
+
+ case 'L':
+ case 'm':
+ case 'z':
+ if (start != &opt_family_only.pb_parser)
+ start = &iface_opt_family_only.pif_parser;
+ break;
+ case 'C':
+ start = &cloneterm.pt_parser;
+ break;
+ case 'l':
+ start = &no_cmds.pt_parser;
+ break;
+ case 's':
+ if (start != &no_cmds.pt_parser &&
+ start != &opt_family_only.pb_parser)
+ start = &iface_only.pif_parser;
+ break;
+ case 'w':
+ start = &wait_dad.pt_parser;
+ break;
+ default:
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * -l means "list all interfaces", and is mutually exclusive with
+ * all other flags/commands.
+ *
+ * -C means "list all names of cloners", and it mutually exclusive
+ * with all other flags/commands.
+ *
+ * -a means "print status of all interfaces".
+ *
+ * -w means "spin until DAD completes for all addreseses", and is
+ * mutually exclusivewith all other flags/commands.
+ */
+ if ((lflag || Cflag || wflag) &&
+ (aflag || get_flag('m') || vflag || zflag))
+ usage();
+ if ((lflag || Cflag || wflag) && get_flag('L'))
+ usage();
+ if ((lflag && Cflag) || (lflag & wflag) || (Cflag && wflag))
+ usage();
+
+ nmatch = __arraycount(match);
+
+ rc = parse(argc, argv, start, match, &nmatch, &narg);
+ if (rc != 0)
+ usage();
+
+ if (prog_init && prog_init() == -1)
+ err(1, "rump client init");
+
+ if ((oenv = prop_dictionary_create()) == NULL)
+ err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
+
+ if (matches_exec(match, oenv, nmatch) == -1)
+ err(EXIT_FAILURE, "exec_matches");
+
+ argc -= narg;
+ argv += narg;
+
+ env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL;
+ if (env == NULL)
+ env = oenv;
+ else {
+ env = prop_dictionary_augment(env, oenv);
+ if (env == NULL)
+ err(EXIT_FAILURE, "%s: prop_dictionary_augment",
+ __func__);
+ }
+
+ /* Process any media commands that may have been issued. */
+ process_media_commands(env);
+
+ if ((af = getaf(env)) == -1)
+ af = AF_INET;
+
+ if ((s = getsock(af)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "%s: getifname", __func__);
+
+ if ((afp = lookup_af_bynum(af)) == NULL)
+ errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__);
+
+ assert(afp->af_addr_commit != NULL);
+ (*afp->af_addr_commit)(env, oenv);
+
+ do_setifpreference(env);
+ do_setifcaps(env);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void
+init_afs(void)
+{
+ size_t i;
+ const struct afswtch *afp;
+ struct kwinst kw = {.k_type = KW_T_INT};
+
+ SIMPLEQ_FOREACH(afp, &aflist, af_next) {
+ kw.k_word = afp->af_name;
+ kw.k_int = afp->af_af;
+ for (i = 0; i < __arraycount(familykw); i++) {
+ if (familykw[i].k_word == NULL) {
+ familykw[i] = kw;
+ break;
+ }
+ }
+ }
+}
+
+const struct afswtch *
+lookup_af_bynum(int afnum)
+{
+ const struct afswtch *afp;
+
+ SIMPLEQ_FOREACH(afp, &aflist, af_next) {
+ if (afp->af_af == afnum)
+ break;
+ }
+ return afp;
+}
+
+void
+printall(const char *ifname, prop_dictionary_t env0)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct ifreq ifr;
+ const struct sockaddr *sdl = NULL;
+ prop_dictionary_t env, oenv;
+ int idx;
+ char *p;
+
+ if (env0 == NULL)
+ env = prop_dictionary_create();
+ else
+ env = prop_dictionary_copy_mutable(env0);
+
+ oenv = prop_dictionary_create();
+
+ if (env == NULL || oenv == NULL)
+ errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__);
+
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ p = NULL;
+ idx = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ memset(&ifr, 0, sizeof(ifr));
+ estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+ if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
+ memcpy(&ifr.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 = ifa->ifa_addr;
+ if (p && strcmp(p, ifa->ifa_name) == 0)
+ continue;
+ if (!prop_dictionary_set_cstring(env, "if", ifa->ifa_name))
+ continue;
+ p = ifa->ifa_name;
+
+ if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
+ continue;
+ if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
+ continue;
+ if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+
+ if (sflag && carrier(env))
+ continue;
+ idx++;
+ /*
+ * Are we just listing the interfaces?
+ */
+ if (lflag) {
+ if (idx > 1)
+ printf(" ");
+ fputs(ifa->ifa_name, stdout);
+ continue;
+ }
+
+ status(sdl, env, oenv);
+ sdl = NULL;
+ }
+ if (lflag)
+ printf("\n");
+ prop_object_release((prop_object_t)env);
+ prop_object_release((prop_object_t)oenv);
+ freeifaddrs(ifap);
+}
+
+static int
+list_cloners(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct if_clonereq ifcr;
+ char *cp, *buf;
+ int idx, s;
+
+ memset(&ifcr, 0, sizeof(ifcr));
+
+ s = getsock(AF_INET);
+
+ if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
+ err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
+
+ buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
+ if (buf == NULL)
+ err(EXIT_FAILURE, "unable to allocate cloner name buffer");
+
+ ifcr.ifcr_count = ifcr.ifcr_total;
+ ifcr.ifcr_buffer = buf;
+
+ if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
+ err(EXIT_FAILURE, "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)
+ printf(" ");
+ printf("%s", cp);
+ }
+
+ printf("\n");
+ free(buf);
+ exit(EXIT_SUCCESS);
+}
+
+static int
+clone_command(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int64_t cmd;
+
+ if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) {
+ warn("%s", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+setifaddr(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const struct paddr_prefix *pfx0;
+ struct paddr_prefix *pfx;
+ prop_data_t d;
+ int af;
+
+ if ((af = getaf(env)) == -1)
+ af = AF_INET;
+
+ d = (prop_data_t)prop_dictionary_get(env, "address");
+ assert(d != NULL);
+ pfx0 = prop_data_data_nocopy(d);
+
+ if (pfx0->pfx_len >= 0) {
+ pfx = prefixlen_to_mask(af, pfx0->pfx_len);
+ if (pfx == NULL)
+ err(EXIT_FAILURE, "prefixlen_to_mask");
+ free(pfx);
+ }
+
+ return 0;
+}
+
+static int
+setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ prop_data_t d;
+
+ d = (prop_data_t)prop_dictionary_get(env, "dstormask");
+ assert(d != NULL);
+
+ if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d))
+ return -1;
+
+ return 0;
+}
+
+static int
+setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ prop_data_t d;
+ unsigned short flags;
+
+ if (getifflags(env, oenv, &flags) == -1)
+ err(EXIT_FAILURE, "%s: getifflags", __func__);
+
+ if ((flags & IFF_BROADCAST) == 0)
+ errx(EXIT_FAILURE, "not a broadcast interface");
+
+ d = (prop_data_t)prop_dictionary_get(env, "broadcast");
+ assert(d != NULL);
+
+ if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d))
+ return -1;
+
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+notrailers(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ puts("Note: trailers are no longer sent, but always received");
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const char *key;
+ prop_data_t d;
+ unsigned short flags;
+
+ if (getifflags(env, oenv, &flags) == -1)
+ err(EXIT_FAILURE, "%s: getifflags", __func__);
+
+ d = (prop_data_t)prop_dictionary_get(env, "dstormask");
+ assert(d != NULL);
+
+ if ((flags & IFF_BROADCAST) == 0) {
+ key = "dst";
+ } else {
+ key = "netmask";
+ }
+
+ if (!prop_dictionary_set(oenv, key, (prop_object_t)d))
+ return -1;
+
+ return 0;
+}
+
+static int
+setifflags(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifreq ifr;
+ int64_t ifflag;
+ bool rc;
+
+ rc = prop_dictionary_get_int64(env, "ifflag", &ifflag);
+ assert(rc);
+
+ if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1)
+ return -1;
+
+ if (ifflag < 0) {
+ ifflag = -ifflag;
+ ifr.ifr_flags &= ~ifflag;
+ } else
+ ifr.ifr_flags |= ifflag;
+
+ if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr)
+{
+ bool rc;
+ struct ifcapreq ifcr;
+ const struct ifcapreq *tmpifcr;
+ prop_data_t capdata;
+
+ capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps");
+
+ if (capdata != NULL) {
+ tmpifcr = prop_data_data_nocopy(capdata);
+ *oifcr = *tmpifcr;
+ return 0;
+ }
+
+ (void)direct_ioctl(env, SIOCGIFCAP, &ifcr);
+ *oifcr = ifcr;
+
+ capdata = prop_data_create_data(&ifcr, sizeof(ifcr));
+
+ rc = prop_dictionary_set(oenv, "ifcaps", capdata);
+
+ prop_object_release((prop_object_t)capdata);
+
+ return rc ? 0 : -1;
+}
+
+static int
+setifcaps(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int64_t ifcap;
+ bool rc;
+ prop_data_t capdata;
+ struct ifcapreq ifcr;
+
+ rc = prop_dictionary_get_int64(env, "ifcap", &ifcap);
+ assert(rc);
+
+ if (getifcaps(env, oenv, &ifcr) == -1)
+ return -1;
+
+ if (ifcap < 0) {
+ ifcap = -ifcap;
+ ifcr.ifcr_capenable &= ~ifcap;
+ } else
+ ifcr.ifcr_capenable |= ifcap;
+
+ if ((capdata = prop_data_create_data(&ifcr, sizeof(ifcr))) == NULL)
+ return -1;
+
+ rc = prop_dictionary_set(oenv, "ifcaps", capdata);
+ prop_object_release((prop_object_t)capdata);
+
+ return rc ? 0 : -1;
+}
+
+static int
+setifmetric(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifreq ifr;
+ bool rc;
+ int64_t metric;
+
+ rc = prop_dictionary_get_int64(env, "metric", &metric);
+ assert(rc);
+
+ ifr.ifr_metric = metric;
+ if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1)
+ warn("SIOCSIFMETRIC");
+ return 0;
+}
+
+static void
+do_setifpreference(prop_dictionary_t env)
+{
+ struct if_addrprefreq ifap;
+ prop_data_t d;
+ const struct paddr_prefix *pfx;
+
+ memset(&ifap, 0, sizeof(ifap));
+
+ if (!prop_dictionary_get_int16(env, "preference",
+ &ifap.ifap_preference))
+ return;
+
+ d = (prop_data_t)prop_dictionary_get(env, "address");
+ assert(d != NULL);
+
+ pfx = prop_data_data_nocopy(d);
+
+ memcpy(&ifap.ifap_addr, &pfx->pfx_addr,
+ MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len));
+ if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1)
+ warn("SIOCSIFADDRPREF");
+}
+
+static int
+setifmtu(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int64_t mtu;
+ bool rc;
+ struct ifreq ifr;
+
+ rc = prop_dictionary_get_int64(env, "mtu", &mtu);
+ assert(rc);
+
+ ifr.ifr_mtu = mtu;
+ if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1)
+ warn("SIOCSIFMTU");
+
+ return 0;
+}
+
+static int
+carrier(prop_dictionary_t env)
+{
+ struct ifmediareq ifmr;
+
+ memset(&ifmr, 0, sizeof(ifmr));
+
+ if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) {
+ /*
+ * Interface doesn't support SIOC{G,S}IFMEDIA;
+ * assume ok.
+ */
+ return EXIT_SUCCESS;
+ }
+ if ((ifmr.ifm_status & IFM_AVALID) == 0) {
+ /*
+ * Interface doesn't report media-valid status.
+ * assume ok.
+ */
+ return EXIT_SUCCESS;
+ }
+ /* otherwise, return ok for active, not-ok if not active. */
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+static void
+print_plural(const char *prefix, uint64_t n, const char *unit)
+{
+ printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s");
+}
+
+static void
+print_human_bytes(bool humanize, uint64_t n)
+{
+ char buf[5];
+
+ if (humanize) {
+ (void)humanize_number(buf, sizeof(buf),
+ (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
+ printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s");
+ } else
+ print_plural(", ", n, "byte");
+}
+
+/*
+ * Print the status of the interface. If an address family was
+ * specified, show it and it only; otherwise, show them all.
+ */
+
+#define MAX_PRINT_LEN 58 /* XXX need a better way to determine this! */
+
+void
+status(const struct sockaddr *sdl, prop_dictionary_t env,
+ prop_dictionary_t oenv)
+{
+ const struct if_data *ifi;
+ status_func_t *status_f;
+ statistics_func_t *statistics_f;
+ struct ifdatareq ifdr;
+ struct ifreq ifr;
+ struct ifdrv ifdrv;
+ char fbuf[BUFSIZ];
+ char *bp;
+ int af, s;
+ const char *ifname;
+ struct ifcapreq ifcr;
+ unsigned short flags;
+ const struct afswtch *afp;
+
+ if ((af = getaf(env)) == -1) {
+ afp = NULL;
+ af = AF_UNSPEC;
+ } else
+ afp = lookup_af_bynum(af);
+
+ /* get out early if the family is unsupported by the kernel */
+ if ((s = getsock(af)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+
+ if ((ifname = getifinfo(env, oenv, &flags)) == NULL)
+ err(EXIT_FAILURE, "%s: getifinfo", __func__);
+
+ (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
+ printf("%s: flags=%s", ifname, fbuf);
+
+ estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (prog_ioctl(s, SIOCGIFMETRIC, &ifr) == -1)
+ warn("SIOCGIFMETRIC %s", ifr.ifr_name);
+ else if (ifr.ifr_metric != 0)
+ printf(" metric %d", ifr.ifr_metric);
+
+ estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0)
+ printf(" mtu %d", ifr.ifr_mtu);
+ printf("\n");
+
+ if (getifcaps(env, oenv, &ifcr) == -1)
+ err(EXIT_FAILURE, "%s: getifcaps", __func__);
+
+ if (ifcr.ifcr_capabilities != 0) {
+ (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS,
+ ifcr.ifcr_capabilities, MAX_PRINT_LEN);
+ bp = fbuf;
+ while (*bp != '\0') {
+ printf("\tcapabilities=%s\n", &bp[2]);
+ bp += strlen(bp) + 1;
+ }
+ (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS,
+ ifcr.ifcr_capenable, MAX_PRINT_LEN);
+ bp = fbuf;
+ while (*bp != '\0') {
+ printf("\tenabled=%s\n", &bp[2]);
+ bp += strlen(bp) + 1;
+ }
+ }
+
+ SIMPLEQ_FOREACH(status_f, &status_funcs, f_next)
+ (*status_f->f_func)(env, oenv);
+
+ print_link_addresses(env, true);
+
+ estrlcpy(ifdrv.ifd_name, ifname, sizeof(ifdrv.ifd_name));
+ ifdrv.ifd_cmd = IFLINKSTR_QUERYLEN;
+ ifdrv.ifd_len = 0;
+ ifdrv.ifd_data = NULL;
+ /* interface supports linkstr? */
+ if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) != -1) {
+ char *p;
+
+ p = malloc(ifdrv.ifd_len);
+ if (p == NULL)
+ err(EXIT_FAILURE, "malloc linkstr buf failed");
+ ifdrv.ifd_data = p;
+ ifdrv.ifd_cmd = 0;
+ if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) == -1)
+ err(EXIT_FAILURE, "failed to query linkstr");
+ printf("\tlinkstr: %s\n", (char *)ifdrv.ifd_data);
+ free(p);
+ }
+
+ media_status(env, oenv);
+
+ if (!vflag && !zflag)
+ goto proto_status;
+
+ estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name));
+
+ if (prog_ioctl(s, zflag ? SIOCZIFDATA : SIOCGIFDATA, &ifdr) == -1)
+ err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
+
+ ifi = &ifdr.ifdr_data;
+
+ print_plural("\tinput: ", ifi->ifi_ipackets, "packet");
+ print_human_bytes(hflag, ifi->ifi_ibytes);
+ if (ifi->ifi_imcasts)
+ print_plural(", ", ifi->ifi_imcasts, "multicast");
+ if (ifi->ifi_ierrors)
+ print_plural(", ", ifi->ifi_ierrors, "error");
+ if (ifi->ifi_iqdrops)
+ print_plural(", ", ifi->ifi_iqdrops, "queue drop");
+ if (ifi->ifi_noproto)
+ printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto);
+ print_plural("\n\toutput: ", ifi->ifi_opackets, "packet");
+ print_human_bytes(hflag, ifi->ifi_obytes);
+ if (ifi->ifi_omcasts)
+ print_plural(", ", ifi->ifi_omcasts, "multicast");
+ if (ifi->ifi_oerrors)
+ print_plural(", ", ifi->ifi_oerrors, "error");
+ if (ifi->ifi_collisions)
+ print_plural(", ", ifi->ifi_collisions, "collision");
+ printf("\n");
+
+ SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next)
+ (*statistics_f->f_func)(env);
+
+ proto_status:
+
+ if (afp != NULL)
+ (*afp->af_status)(env, oenv, true);
+ else SIMPLEQ_FOREACH(afp, &aflist, af_next)
+ (*afp->af_status)(env, oenv, false);
+}
+
+static int
+setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ bool rc;
+ int64_t plen;
+ int af;
+ struct paddr_prefix *pfx;
+ prop_data_t d;
+
+ if ((af = getaf(env)) == -1)
+ af = AF_INET;
+
+ rc = prop_dictionary_get_int64(env, "prefixlen", &plen);
+ assert(rc);
+
+ pfx = prefixlen_to_mask(af, plen);
+ if (pfx == NULL)
+ err(EXIT_FAILURE, "prefixlen_to_mask");
+
+ d = prop_data_create_data(pfx, paddr_prefix_size(pfx));
+ if (d == NULL)
+ err(EXIT_FAILURE, "%s: prop_data_create_data", __func__);
+
+ if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d))
+ err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
+
+ free(pfx);
+ return 0;
+}
+
+static int
+setlinkstr(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifdrv ifdrv;
+ size_t linkstrlen;
+ prop_data_t data;
+ char *linkstr;
+
+ data = (prop_data_t)prop_dictionary_get(env, "linkstr");
+ if (data == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+ linkstrlen = prop_data_size(data)+1;
+
+ linkstr = malloc(linkstrlen);
+ if (linkstr == NULL)
+ err(EXIT_FAILURE, "malloc linkstr space");
+ if (getargstr(env, "linkstr", linkstr, linkstrlen) == -1)
+ errx(EXIT_FAILURE, "getargstr linkstr failed");
+
+ ifdrv.ifd_cmd = 0;
+ ifdrv.ifd_len = linkstrlen;
+ ifdrv.ifd_data = __UNCONST(linkstr);
+
+ if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1)
+ err(EXIT_FAILURE, "SIOCSLINKSTR");
+ free(linkstr);
+
+ return 0;
+}
+
+static int
+unsetlinkstr(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifdrv ifdrv;
+
+ memset(&ifdrv, 0, sizeof(ifdrv));
+ ifdrv.ifd_cmd = IFLINKSTR_UNSET;
+
+ if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1)
+ err(EXIT_FAILURE, "SIOCSLINKSTR");
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ const char *progname = getprogname();
+ usage_func_t *usage_f;
+ prop_dictionary_t env;
+
+ if ((env = prop_dictionary_create()) == NULL)
+ err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
+
+ fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n"
+ "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
+ "\t\t[ alias | -alias ] ]\n"
+ "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname,
+ flag_is_registered(gflags, 'm') ? "[-m] " : "",
+ flag_is_registered(gflags, 'L') ? "[-L] " : "");
+
+ SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next)
+ (*usage_f->f_func)(env);
+
+ fprintf(stderr,
+ "\t[ arp | -arp ]\n"
+ "\t[ preference n ]\n"
+ "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
+ " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n"
+ " %s -l [-b] [-d] [-s] [-u]\n"
+ " %s -C\n"
+ " %s -w n\n"
+ " %s interface create\n"
+ " %s interface destroy\n",
+ progname, flag_is_registered(gflags, 'm') ? "[-m] " : "",
+ progname, progname, progname, progname, progname);
+
+ prop_object_release((prop_object_t)env);
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/* $NetBSD: ifconfig_hostops.c,v 1.1 2010/12/13 17:35:08 pooka Exp $ */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * 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 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ifconfig_hostops.c,v 1.1 2010/12/13 17:35:08 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <unistd.h>
+
+#include "prog_ops.h"
+
+const struct prog_ops prog_ops = {
+ .op_socket = socket,
+ .op_ioctl = ioctl,
+ .op_read = read,
+ .op_close = close,
+};
--- /dev/null
+/* $NetBSD: ifconfig_rumpops.c,v 1.1 2010/12/13 17:35:08 pooka Exp $ */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * 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 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ifconfig_rumpops.c,v 1.1 2010/12/13 17:35:08 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/rumpclient.h>
+
+#include "prog_ops.h"
+
+const struct prog_ops prog_ops = {
+ .op_init = rumpclient_init,
+
+ .op_socket = rump_sys_socket,
+ .op_ioctl = rump_sys_ioctl,
+ .op_read = rump_sys_read,
+ .op_close = rump_sys_close,
+};
--- /dev/null
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: media.c,v 1.6 2011/08/29 14:35:00 joerg Exp $");
+#endif /* not lint */
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <util.h>
+
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <prop/proplib.h>
+
+#include "env.h"
+#include "extern.h"
+#include "media.h"
+#include "parse.h"
+#include "util.h"
+#include "prog_ops.h"
+
+static void init_current_media(prop_dictionary_t, prop_dictionary_t);
+static void media_constructor(void) __attribute__((constructor));
+static int setmedia(prop_dictionary_t, prop_dictionary_t);
+static int setmediainst(prop_dictionary_t, prop_dictionary_t);
+static int setmediamode(prop_dictionary_t, prop_dictionary_t);
+static int setmediaopt(prop_dictionary_t, prop_dictionary_t);
+static int unsetmediaopt(prop_dictionary_t, prop_dictionary_t);
+
+/*
+ * Media stuff. Whenever a media command is first performed, the
+ * currently select media is grabbed for this interface. If `media'
+ * is given, the current media word is modifed. `mediaopt' commands
+ * only modify the set and clear words. They then operate on the
+ * current media word later.
+ */
+static int media_current;
+static int mediaopt_set;
+static int mediaopt_clear;
+
+static struct usage_func usage;
+
+static const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
+
+static const struct ifmedia_status_description ifm_status_descriptions[] =
+ IFM_STATUS_DESCRIPTIONS;
+
+static struct pstr mediamode = PSTR_INITIALIZER1(&mediamode, "mediamode",
+ setmediamode, "mediamode", false, &command_root.pb_parser);
+
+static struct pinteger mediainst = PINTEGER_INITIALIZER1(&mediainst,
+ "mediainst", 0, IFM_INST_MAX, 10, setmediainst, "mediainst",
+ &command_root.pb_parser);
+
+static struct pstr unmediaopt = PSTR_INITIALIZER1(&unmediaopt, "-mediaopt",
+ unsetmediaopt, "unmediaopt", false, &command_root.pb_parser);
+
+static struct pstr mediaopt = PSTR_INITIALIZER1(&mediaopt, "mediaopt",
+ setmediaopt, "mediaopt", false, &command_root.pb_parser);
+
+static struct pstr media = PSTR_INITIALIZER1(&media, "media", setmedia, "media",
+ false, &command_root.pb_parser);
+
+static const struct kwinst mediakw[] = {
+ {.k_word = "instance", .k_key = "anymedia", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_act = "media", .k_deact = "mediainst",
+ .k_nextparser = &mediainst.pi_parser}
+ , {.k_word = "inst", .k_key = "anymedia", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_act = "media", .k_deact = "mediainst",
+ .k_nextparser = &mediainst.pi_parser}
+ , {.k_word = "media", .k_key = "anymedia", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_deact = "media", .k_altdeact = "anymedia",
+ .k_nextparser = &media.ps_parser}
+ , {.k_word = "mediaopt", .k_key = "anymedia", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_deact = "mediaopt", .k_altdeact = "instance",
+ .k_nextparser = &mediaopt.ps_parser}
+ , {.k_word = "-mediaopt", .k_key = "anymedia", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_deact = "unmediaopt", .k_altdeact = "media",
+ .k_nextparser = &unmediaopt.ps_parser}
+ , {.k_word = "mode", .k_key = "anymedia", .k_type = KW_T_BOOL,
+ .k_bool = true, .k_deact = "mode",
+ .k_nextparser = &mediamode.ps_parser}
+};
+
+struct pkw kwmedia = PKW_INITIALIZER(&kwmedia, "media keywords", NULL, NULL,
+ mediakw, __arraycount(mediakw), NULL);
+
+__dead static void
+media_error(int type, const char *val, const char *opt)
+{
+ errx(EXIT_FAILURE, "unknown %s media %s: %s",
+ get_media_type_string(type), opt, val);
+}
+
+void
+init_current_media(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const char *ifname;
+ struct ifmediareq ifmr;
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "getifname");
+
+ /*
+ * If we have not yet done so, grab the currently-selected
+ * media.
+ */
+
+ if (prop_dictionary_get(env, "initmedia") == NULL) {
+ memset(&ifmr, 0, sizeof(ifmr));
+
+ if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) {
+ /*
+ * If we get E2BIG, the kernel is telling us
+ * that there are more, so we can ignore it.
+ */
+ if (errno != E2BIG)
+ err(EXIT_FAILURE, "SIOCGIFMEDIA");
+ }
+
+ if (!prop_dictionary_set_bool(oenv, "initmedia", true)) {
+ err(EXIT_FAILURE, "%s: prop_dictionary_set_bool",
+ __func__);
+ }
+ media_current = ifmr.ifm_current;
+ }
+
+ /* Sanity. */
+ if (IFM_TYPE(media_current) == 0)
+ errx(EXIT_FAILURE, "%s: no link type?", ifname);
+}
+
+void
+process_media_commands(prop_dictionary_t env)
+{
+ struct ifreq ifr;
+
+ if (prop_dictionary_get(env, "media") == NULL &&
+ prop_dictionary_get(env, "mediaopt") == NULL &&
+ prop_dictionary_get(env, "unmediaopt") == NULL &&
+ prop_dictionary_get(env, "mediamode") == NULL) {
+ /* Nothing to do. */
+ return;
+ }
+
+ /*
+ * Media already set up, and commands sanity-checked. Set/clear
+ * any options, and we're ready to go.
+ */
+ media_current |= mediaopt_set;
+ media_current &= ~mediaopt_clear;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_media = media_current;
+
+ if (direct_ioctl(env, SIOCSIFMEDIA, &ifr) == -1)
+ err(EXIT_FAILURE, "SIOCSIFMEDIA");
+}
+
+static int
+setmedia(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int type, subtype, inst;
+ prop_data_t data;
+ char *val;
+
+ init_current_media(env, oenv);
+
+ data = (prop_data_t)prop_dictionary_get(env, "media");
+ assert(data != NULL);
+
+ /* Only one media command may be given. */
+ /* Must not come after mode commands */
+ /* Must not come after mediaopt commands */
+
+ /*
+ * No need to check if `instance' has been issued; setmediainst()
+ * craps out if `media' has not been specified.
+ */
+
+ type = IFM_TYPE(media_current);
+ inst = IFM_INST(media_current);
+
+ val = strndup(prop_data_data_nocopy(data), prop_data_size(data));
+ if (val == NULL)
+ return -1;
+
+ /* Look up the subtype. */
+ subtype = get_media_subtype(type, val);
+ if (subtype == -1)
+ media_error(type, val, "subtype");
+
+ /* Build the new current media word. */
+ media_current = IFM_MAKEWORD(type, subtype, 0, inst);
+
+ /* Media will be set after other processing is complete. */
+ return 0;
+}
+
+static int
+setmediaopt(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ char *invalid;
+ prop_data_t data;
+ char *val;
+
+ init_current_media(env, oenv);
+
+ data = (prop_data_t)prop_dictionary_get(env, "mediaopt");
+ assert(data != NULL);
+
+ /* Can only issue `mediaopt' once. */
+ /* Can't issue `mediaopt' if `instance' has already been issued. */
+
+ val = strndup(prop_data_data_nocopy(data), prop_data_size(data));
+ if (val == NULL)
+ return -1;
+
+ mediaopt_set = get_media_options(media_current, val, &invalid);
+ free(val);
+ if (mediaopt_set == -1)
+ media_error(media_current, invalid, "option");
+
+ /* Media will be set after other processing is complete. */
+ return 0;
+}
+
+static int
+unsetmediaopt(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ char *invalid, *val;
+ prop_data_t data;
+
+ init_current_media(env, oenv);
+
+ data = (prop_data_t)prop_dictionary_get(env, "unmediaopt");
+ if (data == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ val = strndup(prop_data_data_nocopy(data), prop_data_size(data));
+ if (val == NULL)
+ return -1;
+
+ /*
+ * No need to check for A_MEDIAINST, since the test for A_MEDIA
+ * implicitly checks for A_MEDIAINST.
+ */
+
+ mediaopt_clear = get_media_options(media_current, val, &invalid);
+ free(val);
+ if (mediaopt_clear == -1)
+ media_error(media_current, invalid, "option");
+
+ /* Media will be set after other processing is complete. */
+ return 0;
+}
+
+static int
+setmediainst(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int type, subtype, options;
+ int64_t inst;
+ bool rc;
+
+ init_current_media(env, oenv);
+
+ rc = prop_dictionary_get_int64(env, "mediainst", &inst);
+ assert(rc);
+
+ /* Can only issue `instance' once. */
+ /* Must have already specified `media' */
+
+ type = IFM_TYPE(media_current);
+ subtype = IFM_SUBTYPE(media_current);
+ options = IFM_OPTIONS(media_current);
+
+ media_current = IFM_MAKEWORD(type, subtype, options, inst);
+
+ /* Media will be set after other processing is complete. */
+ return 0;
+}
+
+static int
+setmediamode(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ int type, subtype, options, inst, mode;
+ prop_data_t data;
+ char *val;
+
+ init_current_media(env, oenv);
+
+ data = (prop_data_t)prop_dictionary_get(env, "mediamode");
+ assert(data != NULL);
+
+ type = IFM_TYPE(media_current);
+ subtype = IFM_SUBTYPE(media_current);
+ options = IFM_OPTIONS(media_current);
+ inst = IFM_INST(media_current);
+
+ val = strndup(prop_data_data_nocopy(data), prop_data_size(data));
+ if (val == NULL)
+ return -1;
+
+ mode = get_media_mode(type, val);
+ if (mode == -1)
+ media_error(type, val, "mode");
+
+ free(val);
+
+ media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
+
+ /* Media will be set after other processing is complete. */
+ return 0;
+}
+
+void
+print_media_word(int ifmw, const char *opt_sep)
+{
+ const char *str;
+
+ printf("%s", get_media_subtype_string(ifmw));
+
+ /* Find mode. */
+ if (IFM_MODE(ifmw) != 0) {
+ str = get_media_mode_string(ifmw);
+ if (str != NULL)
+ printf(" mode %s", str);
+ }
+
+ /* Find options. */
+ for (; (str = get_media_option_string(&ifmw)) != NULL; opt_sep = ",")
+ printf("%s%s", opt_sep, str);
+
+ if (IFM_INST(ifmw) != 0)
+ printf(" instance %d", IFM_INST(ifmw));
+}
+
+void
+media_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct ifmediareq ifmr;
+ int af, i, s;
+ int *media_list;
+ const char *ifname;
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "getifname");
+ if ((af = getaf(env)) == -1)
+ af = AF_UNSPEC;
+
+ /* get out early if the family is unsupported by the kernel */
+ if ((s = getsock(af)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ estrlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+
+ if (prog_ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
+ /*
+ * Interface doesn't support SIOC{G,S}IFMEDIA.
+ */
+ return;
+ }
+
+ if (ifmr.ifm_count == 0) {
+ warnx("%s: no media types?", ifname);
+ return;
+ }
+
+ media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+ if (media_list == NULL)
+ err(EXIT_FAILURE, "malloc");
+ ifmr.ifm_ulist = media_list;
+
+ if (prog_ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
+ err(EXIT_FAILURE, "SIOCGIFMEDIA");
+
+ printf("\tmedia: %s ", get_media_type_string(ifmr.ifm_current));
+ print_media_word(ifmr.ifm_current, " ");
+ if (ifmr.ifm_active != ifmr.ifm_current) {
+ printf(" (");
+ print_media_word(ifmr.ifm_active, " ");
+ printf(")");
+ }
+ printf("\n");
+
+ if (ifmr.ifm_status & IFM_STATUS_VALID) {
+ const struct ifmedia_status_description *ifms;
+ int bitno, found = 0;
+
+ printf("\tstatus: ");
+ for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
+ for (ifms = ifm_status_descriptions;
+ ifms->ifms_valid != 0; ifms++) {
+ if (ifms->ifms_type !=
+ IFM_TYPE(ifmr.ifm_current) ||
+ ifms->ifms_valid !=
+ ifm_status_valid_list[bitno])
+ continue;
+ printf("%s%s", found ? ", " : "",
+ IFM_STATUS_DESC(ifms, ifmr.ifm_status));
+ found = 1;
+
+ /*
+ * For each valid indicator bit, there's
+ * only one entry for each media type, so
+ * terminate the inner loop now.
+ */
+ break;
+ }
+ }
+
+ if (found == 0)
+ printf("unknown");
+ printf("\n");
+ }
+
+ if (get_flag('m')) {
+ int type, printed_type;
+
+ for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
+ for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
+ if (IFM_TYPE(media_list[i]) != type)
+ continue;
+ if (printed_type == 0) {
+ printf("\tsupported %s media:\n",
+ get_media_type_string(type));
+ printed_type = 1;
+ }
+ printf("\t\tmedia ");
+ print_media_word(media_list[i], " mediaopt ");
+ printf("\n");
+ }
+ }
+ }
+
+ free(media_list);
+}
+
+static void
+media_usage(prop_dictionary_t env)
+{
+ fprintf(stderr,
+ "\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
+ "[ instance minst ]\n");
+}
+
+static void
+media_constructor(void)
+{
+ if (register_flag('m') != 0)
+ err(EXIT_FAILURE, __func__);
+ usage_func_init(&usage, media_usage);
+ register_usage(&usage);
+}
--- /dev/null
+/* $NetBSD: media.h,v 1.1 2008/07/02 07:44:15 dyoung Exp $ */
+
+#ifndef _IFCONFIG_MEDIA_H
+#define _IFCONFIG_MEDIA_H
+
+#include <prop/proplib.h>
+
+#include "parse.h"
+
+extern struct pkw kwmedia;
+
+void print_media_word(int, const char *);
+void process_media_commands(prop_dictionary_t);
+void media_status(prop_dictionary_t, prop_dictionary_t);
+
+#endif /* _IFCONFIG_MEDIA_H */
--- /dev/null
+/* $NetBSD: parse.c,v 1.18 2013/07/17 15:42:03 christos Exp $ */
+
+/*-
+ * Copyright (c) 2008 David Young. 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: parse.c,v 1.18 2013/07/17 15:42:03 christos Exp $");
+#endif /* not lint */
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <sys/param.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netatalk/at.h>
+
+#include "env.h"
+#include "parse.h"
+#include "util.h"
+
+#ifdef DEBUG
+#define dbg_warnx(__fmt, ...) warnx(__fmt, __VA_ARGS__)
+#else
+#define dbg_warnx(__fmt, ...) /* empty */
+#endif
+
+static int parser_default_init(struct parser *);
+static int pbranch_init(struct parser *);
+static int pkw_init(struct parser *);
+
+static int pterm_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+static int paddr_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+static int pbranch_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+static int piface_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+static int pstr_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+static int pinteger_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+static int pkw_match(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+
+const struct parser_methods pterm_methods = {
+ .pm_match = pterm_match
+ , .pm_init = NULL
+};
+
+const struct parser_methods pstr_methods = {
+ .pm_match = pstr_match
+ , .pm_init = parser_default_init
+};
+
+const struct parser_methods pinteger_methods = {
+ .pm_match = pinteger_match
+ , .pm_init = parser_default_init
+};
+
+const struct parser_methods paddr_methods = {
+ .pm_match = paddr_match
+ , .pm_init = parser_default_init
+};
+
+const struct parser_methods piface_methods = {
+ .pm_match = piface_match
+ , .pm_init = parser_default_init
+};
+
+const struct parser_methods pbranch_methods = {
+ .pm_match = pbranch_match
+ , .pm_init = pbranch_init
+};
+
+const struct parser_methods pkw_methods = {
+ .pm_match = pkw_match
+ , .pm_init = pkw_init
+};
+
+static int
+match_setenv(const struct match *im, struct match *om, const char *key,
+ prop_object_t o)
+{
+ if (im == NULL)
+ om->m_env = prop_dictionary_create();
+ else
+ om->m_env = prop_dictionary_copy(im->m_env);
+
+ if (om->m_env == NULL)
+ goto delobj;
+
+ if (key != NULL && !prop_dictionary_set(om->m_env, key, o))
+ goto deldict;
+
+ if (o != NULL)
+ prop_object_release((prop_object_t)o);
+
+ return 0;
+deldict:
+ prop_object_release((prop_object_t)om->m_env);
+ om->m_env = NULL;
+delobj:
+ prop_object_release((prop_object_t)o);
+ errno = ENOMEM;
+ return -1;
+}
+
+int
+pstr_match(const struct parser *p, const struct match *im, struct match *om,
+ int argidx, const char *arg)
+{
+ prop_object_t o;
+ const struct pstr *ps = (const struct pstr *)p;
+ uint8_t buf[128];
+ int len;
+
+ if (arg == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ len = (int)sizeof(buf);
+ if (get_string(arg, NULL, buf, &len, ps->ps_hexok) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ o = (prop_object_t)prop_data_create_data(buf, len);
+
+ if (o == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (match_setenv(im, om, ps->ps_key, o) == -1)
+ return -1;
+
+ om->m_argidx = argidx;
+ om->m_parser = p;
+ om->m_nextparser = p->p_nextparser;
+
+ return 0;
+}
+
+int
+pinteger_match(const struct parser *p, const struct match *im, struct match *om,
+ int argidx, const char *arg)
+{
+ prop_object_t o;
+ const struct pinteger *pi = (const struct pinteger *)p;
+ char *end;
+ int64_t val;
+
+ if (arg == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ val = strtoimax(arg, &end, pi->pi_base);
+ if ((val == INTMAX_MIN || val == INTMAX_MAX) && errno == ERANGE)
+ return -1;
+
+ if (*end != '\0') {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (val < pi->pi_min || val > pi->pi_max) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ o = (prop_object_t)prop_number_create_integer(val);
+
+ if (o == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (match_setenv(im, om, pi->pi_key, o) == -1)
+ return -1;
+
+ om->m_argidx = argidx;
+ om->m_parser = p;
+ om->m_nextparser = p->p_nextparser;
+
+ return 0;
+}
+
+static int
+parse_linkaddr(const char *addr, struct sockaddr_storage *ss)
+{
+ static const size_t maxlen =
+ sizeof(*ss) - offsetof(struct sockaddr_dl, sdl_data[0]);
+ enum {
+ LLADDR_S_INITIAL = 0,
+ LLADDR_S_ONE_OCTET = 1,
+ LLADDR_S_TWO_OCTETS = 2,
+ LLADDR_S_COLON = 3
+ } state = LLADDR_S_INITIAL;
+ uint8_t octet = 0, val;
+ struct sockaddr_dl *sdl;
+ const char *p;
+ size_t i;
+
+ memset(ss, 0, sizeof(*ss));
+ ss->ss_family = AF_LINK;
+ sdl = (struct sockaddr_dl *)ss;
+
+ for (i = 0, p = addr; i < maxlen; p++) {
+ dbg_warnx("%s.%d: *p == %c, state %d", __func__, __LINE__, *p,
+ state);
+ if (*p == '\0') {
+ dbg_warnx("%s.%d", __func__, __LINE__);
+ if (state != LLADDR_S_ONE_OCTET &&
+ state != LLADDR_S_TWO_OCTETS)
+ return -1;
+ dbg_warnx("%s.%d", __func__, __LINE__);
+ sdl->sdl_data[i++] = octet;
+ sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data)
+ + i * sizeof(sdl->sdl_data[0]);
+ sdl->sdl_alen = i;
+ return 0;
+ }
+ if (*p == ':') {
+ dbg_warnx("%s.%d", __func__, __LINE__);
+ if (state != LLADDR_S_ONE_OCTET &&
+ state != LLADDR_S_TWO_OCTETS)
+ return -1;
+ dbg_warnx("%s.%d", __func__, __LINE__);
+ sdl->sdl_data[i++] = octet;
+ state = LLADDR_S_COLON;
+ continue;
+ }
+ if ('a' <= *p && *p <= 'f')
+ val = 10 + *p - 'a';
+ else if ('A' <= *p && *p <= 'F')
+ val = 10 + *p - 'A';
+ else if ('0' <= *p && *p <= '9')
+ val = *p - '0';
+ else
+ return -1;
+
+ dbg_warnx("%s.%d", __func__, __LINE__);
+ if (state == LLADDR_S_ONE_OCTET) {
+ state = LLADDR_S_TWO_OCTETS;
+ octet <<= 4;
+ octet |= val;
+ } else if (state != LLADDR_S_INITIAL && state != LLADDR_S_COLON)
+ return -1;
+ else {
+ state = LLADDR_S_ONE_OCTET;
+ octet = val;
+ }
+ dbg_warnx("%s.%d", __func__, __LINE__);
+ }
+ return -1;
+}
+
+static int
+paddr_match(const struct parser *p, const struct match *im, struct match *om,
+ int argidx, const char *arg0)
+{
+ unsigned int net, node;
+ int nread;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_at sat;
+ struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ } u;
+ const struct paddr *pa = (const struct paddr *)p;
+ prop_data_t d;
+ prop_object_t o;
+ int64_t af0;
+ int af, rc;
+ struct paddr_prefix *pfx, *mask;
+ const struct sockaddr *sa = NULL;
+ struct addrinfo hints, *result = NULL;
+ char *arg, *end, *plen = NULL, *servname0;
+ const char *servname;
+ long prefixlen = -1;
+ size_t len;
+
+ if (arg0 == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (pa->pa_activator != NULL &&
+ prop_dictionary_get(im->m_env, pa->pa_activator) == NULL)
+ return -1;
+
+ if (pa->pa_deactivator != NULL &&
+ prop_dictionary_get(im->m_env, pa->pa_deactivator) != NULL)
+ return -1;
+
+ if (!prop_dictionary_get_int64(im->m_env, "af", &af0))
+ af = AF_UNSPEC;
+ else
+ af = af0;
+
+ memset(&u, 0, sizeof(u));
+
+ switch (af) {
+ case AF_UNSPEC:
+ case AF_INET:
+ case AF_INET6:
+ if ((arg = strdup(arg0)) == NULL)
+ return -1;
+
+ servname0 = arg;
+ (void)strsep(&servname0, ",");
+ servname = (servname0 == NULL) ? "0" : servname0;
+
+ if (pa->pa_maskkey == NULL)
+ ;
+ else if ((plen = strrchr(arg, '/')) != NULL)
+ *plen++ = '\0';
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ for (;;) {
+ rc = getaddrinfo(arg, servname, &hints, &result);
+ if (rc == 0) {
+ if (result->ai_next == NULL)
+ sa = result->ai_addr;
+ else
+ errno = EMLINK;
+ break;
+ } else if ((hints.ai_flags & AI_NUMERICHOST) != 0 &&
+ (af == AF_INET || af == AF_UNSPEC) &&
+ inet_aton(arg, &u.sin.sin_addr) == 1) {
+ u.sin.sin_family = AF_INET;
+ u.sin.sin_len = sizeof(u.sin);
+ sa = &u.sa;
+ break;
+ } else if ((hints.ai_flags & AI_NUMERICHOST) == 0 ||
+ rc != EAI_NONAME) {
+ errno = ENOENT;
+ break;
+ }
+ hints.ai_flags &= ~AI_NUMERICHOST;
+ }
+
+
+ if (plen == NULL)
+ prefixlen = -1;
+ else {
+ prefixlen = strtol(plen, &end, 10);
+ if (end != NULL && *end != '\0')
+ sa = NULL;
+ if (prefixlen < 0 || prefixlen >= UINT8_MAX) {
+ errno = ERANGE;
+ sa = NULL;
+ }
+ }
+
+ free(arg);
+ if (sa != NULL || af != AF_UNSPEC)
+ break;
+ /*FALLTHROUGH*/
+ case AF_APPLETALK:
+ if (sscanf(arg0, "%u.%u%n", &net, &node, &nread) == 2 &&
+ net != 0 && net <= 0xffff && node != 0 && node <= 0xfe &&
+ arg0[nread] == '\0') {
+ u.sat.sat_family = AF_APPLETALK;
+ u.sat.sat_len = sizeof(u.sat);
+ u.sat.sat_addr.s_net = htons(net);
+ u.sat.sat_addr.s_node = node;
+ sa = &u.sa;
+ }
+ break;
+ case AF_LINK:
+ if (parse_linkaddr(arg0, &u.ss) == -1)
+ sa = NULL;
+ else
+ sa = &u.sa;
+ break;
+ }
+
+ if (sa == NULL)
+ return -1;
+
+ len = offsetof(struct paddr_prefix, pfx_addr) + sa->sa_len;
+
+ if ((pfx = malloc(len)) == NULL)
+ return -1;
+
+#if 0
+ {
+ int i;
+
+ for (i = 0; i < sa->sa_len; i++)
+ printf(" %02x", ((const uint8_t *)sa)[i]);
+ printf("\n");
+ }
+#endif
+
+ pfx->pfx_len = (int16_t)prefixlen;
+ memcpy(&pfx->pfx_addr, sa, sa->sa_len);
+ af = sa->sa_family;
+
+ if (result != NULL)
+ freeaddrinfo(result);
+
+ o = (prop_object_t)prop_data_create_data(pfx, len);
+
+ free(pfx);
+
+ if (o == NULL)
+ return -1;
+
+ if (match_setenv(im, om, pa->pa_addrkey, o) == -1)
+ return -1;
+
+ if (pa->pa_maskkey != NULL && plen != NULL) {
+ size_t masklen;
+
+ if ((mask = prefixlen_to_mask(af, prefixlen)) == NULL) {
+ err(EXIT_FAILURE, "%s: prefixlen_to_mask(%d, %ld)",
+ __func__, af, prefixlen);
+ return -1;
+ }
+
+ masklen = paddr_prefix_size(mask);
+
+ d = prop_data_create_data(mask, masklen);
+ free(mask);
+
+ if (d == NULL) {
+ err(EXIT_FAILURE, "%s: prop_data_create_data",
+ __func__);
+ return -1;
+ }
+
+ rc = prop_dictionary_set(om->m_env, pa->pa_maskkey,
+ (prop_object_t)d) ? 0 : -1;
+
+ prop_object_release((prop_object_t)d);
+
+ if (rc != 0) {
+ err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
+ return rc;
+ }
+ }
+
+ om->m_argidx = argidx;
+ om->m_parser = p;
+ om->m_nextparser = p->p_nextparser;
+ return 0;
+}
+
+static int
+pterm_match(const struct parser *p, const struct match *im,
+ struct match *om, int argidx, const char *arg)
+{
+ const struct pterm *pt = (const struct pterm *)p;
+ prop_bool_t b;
+
+ if (arg != NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ b = prop_bool_create(true);
+
+ if (match_setenv(im, om, pt->pt_key, (prop_object_t)b) == -1)
+ return -1;
+
+ om->m_argidx = argidx;
+ om->m_parser = p;
+ om->m_nextparser = NULL;
+ return 0;
+}
+
+static int
+piface_match(const struct parser *p, const struct match *im,
+ struct match *om, int argidx, const char *arg)
+{
+ const struct piface *pif = (const struct piface *)p;
+ prop_object_t o;
+
+ if (arg == NULL || strlen(arg) > IFNAMSIZ) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((o = (prop_object_t)prop_string_create_cstring(arg)) == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (match_setenv(im, om, pif->pif_key, o) == -1)
+ return -1;
+
+ om->m_argidx = argidx;
+ om->m_parser = p;
+ om->m_nextparser = p->p_nextparser;
+ return 0;
+}
+
+static void
+match_cleanup(struct match *dst)
+{
+ if (dst->m_env != NULL)
+ prop_object_release((prop_object_t)dst->m_env);
+ memset(dst, 0, sizeof(*dst));
+}
+
+static void
+match_copy(struct match *dst, const struct match *src)
+{
+ match_cleanup(dst);
+
+ prop_object_retain((prop_object_t)src->m_env);
+ *dst = *src;
+}
+
+static int
+pbranch_match(const struct parser *p, const struct match *im,
+ struct match *om, int argidx, const char *arg)
+{
+ const struct parser *nextp;
+ struct branch *b;
+ const struct pbranch *pb = (const struct pbranch *)p;
+ struct match tmpm;
+ int nforbid = 0, nmatch = 0, rc;
+ parser_match_t matchfunc;
+
+ memset(&tmpm, 0, sizeof(tmpm));
+
+ SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
+ nextp = b->b_nextparser;
+ dbg_warnx("%s: b->b_nextparser %p [%s]", __func__,
+ nextp, nextp ? nextp->p_name : "(null)");
+ if (nextp == NULL) {
+ if (arg == NULL) {
+ nmatch++;
+ match_setenv(im, om, NULL, NULL);
+ om->m_nextparser = NULL;
+ om->m_parser = p;
+ om->m_argidx = argidx;
+ }
+ continue;
+ }
+ matchfunc = nextp->p_methods->pm_match;
+ rc = (*matchfunc)(nextp, im, &tmpm, argidx, arg);
+ if (rc == 0) {
+ match_copy(om, &tmpm);
+ match_cleanup(&tmpm);
+ nmatch++;
+ dbg_warnx("%s: branch %s ok", __func__, nextp->p_name);
+ if (pb->pb_match_first)
+ break;
+ } else if (rc == 1) {
+ nforbid++;
+ if (pb->pb_match_first)
+ break;
+ } else {
+ dbg_warnx("%s: fail branch %s", __func__,
+ nextp->p_name);
+ }
+ }
+ switch (nmatch) {
+ case 0:
+ errno = ENOENT;
+ return (nforbid == 0) ? -1 : 1;
+ case 1:
+ dbg_warnx("%s: branch ok", __func__);
+ return 0;
+ default:
+ match_cleanup(om);
+ errno = EMLINK;
+ return -1;
+ }
+}
+
+static int
+pkw_match(const struct parser *p, const struct match *im,
+ struct match *om, int argidx, const char *arg)
+{
+ prop_object_t o = NULL;
+ struct kwinst *k;
+ union kwval *u = NULL;
+ const struct pkw *pk = (const struct pkw *)p;
+
+ if (arg == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
+ if (k->k_act != NULL &&
+ prop_dictionary_get(im->m_env, k->k_act) == NULL)
+ continue;
+
+ if (k->k_neg && arg[0] == '-' &&
+ strcmp(k->k_word, arg + 1) == 0)
+ u = &k->k_negu;
+ else if (strcmp(k->k_word, arg) == 0)
+ u = &k->k_u;
+ else
+ continue;
+
+ if (k->k_altdeact != NULL &&
+ prop_dictionary_get(im->m_env, k->k_altdeact) != NULL)
+ return 1;
+
+ if (k->k_deact != NULL &&
+ prop_dictionary_get(im->m_env, k->k_deact) != NULL)
+ return 1;
+ break;
+ }
+ if (k == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+ switch (k->k_type) {
+ case KW_T_NONE:
+ break;
+ case KW_T_BOOL:
+ o = (prop_object_t)prop_bool_create(u->u_bool);
+ if (o == NULL)
+ goto err;
+ break;
+ case KW_T_INT:
+ o = (prop_object_t)prop_number_create_integer(u->u_sint);
+ if (o == NULL)
+ goto err;
+ break;
+ case KW_T_UINT:
+ o = (prop_object_t)prop_number_create_unsigned_integer(
+ u->u_uint);
+ if (o == NULL)
+ goto err;
+ break;
+ case KW_T_OBJ:
+ o = u->u_obj;
+ break;
+ case KW_T_STR:
+ o = (prop_object_t)prop_string_create_cstring_nocopy(u->u_str);
+ if (o == NULL)
+ goto err;
+ break;
+ default:
+ errx(EXIT_FAILURE, "unknown keyword type %d", k->k_type);
+ }
+
+ if (match_setenv(im, om, (o == NULL) ? NULL : k->k_key, o) == -1)
+ return -1;
+
+ om->m_argidx = argidx;
+ om->m_parser = p;
+ om->m_nextparser = k->k_nextparser;
+ om->m_exec = k->k_exec;
+ return 0;
+err:
+ errno = ENOMEM;
+ return -1;
+}
+
+struct paddr *
+paddr_create(const char *name, parser_exec_t pexec, const char *addrkey,
+ const char *maskkey, struct parser *next)
+{
+ struct paddr *pa;
+
+ if ((pa = calloc(sizeof(*pa), 1)) == NULL)
+ return NULL;
+
+ pa->pa_parser.p_methods = &paddr_methods;
+ pa->pa_parser.p_exec = pexec;
+ pa->pa_parser.p_name = name;
+ pa->pa_parser.p_nextparser = next;
+
+ pa->pa_addrkey = addrkey;
+ pa->pa_maskkey = maskkey;
+
+ return pa;
+}
+
+struct piface *
+piface_create(const char *name, parser_exec_t pexec, const char *defkey,
+ struct parser *defnext)
+{
+ struct piface *pif;
+
+ if ((pif = calloc(sizeof(*pif), 1)) == NULL)
+ return NULL;
+
+ pif->pif_parser.p_methods = &piface_methods;
+ pif->pif_parser.p_exec = pexec;
+ pif->pif_parser.p_name = name;
+ pif->pif_parser.p_nextparser = defnext;
+
+ pif->pif_key = defkey;
+
+ return pif;
+}
+
+int
+pbranch_addbranch(struct pbranch *pb, struct parser *p)
+{
+ struct branch *b;
+
+ if ((b = malloc(sizeof(*b))) == NULL)
+ return -1;
+ b->b_nextparser = p;
+ SIMPLEQ_INSERT_HEAD(&pb->pb_branches, b, b_next);
+ pb->pb_parser.p_initialized = false;
+ return parser_init(&pb->pb_parser);
+}
+
+int
+pbranch_setbranches(struct pbranch *pb, const struct branch *brs, size_t nbr)
+{
+ struct branch *b;
+ size_t i;
+
+ dbg_warnx("%s: nbr %zu", __func__, nbr);
+
+ while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
+ free(b);
+ }
+
+ for (i = 0; i < nbr; i++) {
+ if ((b = malloc(sizeof(*b))) == NULL)
+ goto err;
+ *b = brs[i];
+ dbg_warnx("%s: b->b_nextparser %p [%s]", __func__,
+ b->b_nextparser, b->b_nextparser ? b->b_nextparser->p_name
+ : "(null)");
+ SIMPLEQ_INSERT_TAIL(&pb->pb_branches, b, b_next);
+ }
+
+ return 0;
+err:
+ while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
+ free(b);
+ }
+ return -1;
+}
+
+static int
+pbranch_init(struct parser *p)
+{
+ struct branch *b;
+ struct pbranch *pb = (struct pbranch *)p;
+ struct parser *np;
+
+ if (pb->pb_nbrinit == 0)
+ ;
+ else if (pbranch_setbranches(pb, pb->pb_brinit, pb->pb_nbrinit) == -1)
+ return -1;
+
+ pb->pb_nbrinit = 0;
+
+ SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
+ np = b->b_nextparser;
+ if (np != NULL && parser_init(np) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+struct pbranch *
+pbranch_create(const char *name, const struct branch *brs, size_t nbr,
+ bool match_first)
+{
+ struct pbranch *pb;
+
+ dbg_warnx("%s: nbr %zu", __func__, nbr);
+
+ if ((pb = calloc(1, sizeof(*pb))) == NULL)
+ return NULL;
+
+ pb->pb_parser.p_methods = &pbranch_methods;
+ pb->pb_parser.p_name = name;
+
+ SIMPLEQ_INIT(&pb->pb_branches);
+
+ if (pbranch_setbranches(pb, brs, nbr) == -1)
+ goto post_pb_err;
+
+ pb->pb_match_first = match_first;
+ return pb;
+post_pb_err:
+ free(pb);
+ return NULL;
+}
+
+static int
+parser_default_init(struct parser *p)
+{
+ struct parser *np;
+
+ np = p->p_nextparser;
+ if (np != NULL && parser_init(np) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+pkw_setwords(struct pkw *pk, parser_exec_t defexec, const char *defkey,
+ const struct kwinst *kws, size_t nkw, struct parser *defnext)
+{
+ struct kwinst *k;
+ size_t i;
+
+ for (i = 0; i < nkw; i++) {
+ if (kws[i].k_word == NULL)
+ continue;
+ if ((k = malloc(sizeof(*k))) == NULL)
+ goto post_pk_err;
+ *k = kws[i];
+ if (k->k_nextparser == NULL)
+ k->k_nextparser = defnext;
+ if (k->k_key == NULL)
+ k->k_key = defkey;
+ if (k->k_exec == NULL)
+ k->k_exec = defexec;
+ SIMPLEQ_INSERT_TAIL(&pk->pk_keywords, k, k_next);
+ }
+ return 0;
+
+post_pk_err:
+ while ((k = SIMPLEQ_FIRST(&pk->pk_keywords)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pk->pk_keywords, k_next);
+ free(k);
+ }
+ return -1;
+}
+
+static int
+pkw_init(struct parser *p)
+{
+ struct kwinst *k;
+ struct pkw *pk = (struct pkw *)p;
+ struct parser *np;
+
+ if (pk->pk_nkwinit == 0)
+ ;
+ else if (pkw_setwords(pk, pk->pk_execinit, pk->pk_keyinit,
+ pk->pk_kwinit, pk->pk_nkwinit, pk->pk_nextinit) == -1)
+ return -1;
+
+ pk->pk_nkwinit = 0;
+
+ SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
+ np = k->k_nextparser;
+ if (np != NULL && parser_init(np) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+struct pkw *
+pkw_create(const char *name, parser_exec_t defexec, const char *defkey,
+ const struct kwinst *kws, size_t nkw, struct parser *defnext)
+{
+ struct pkw *pk;
+
+ if ((pk = calloc(1, sizeof(*pk))) == NULL)
+ return NULL;
+
+ pk->pk_parser.p_methods = &pkw_methods;
+ pk->pk_parser.p_exec = defexec;
+ pk->pk_parser.p_name = name;
+
+ SIMPLEQ_INIT(&pk->pk_keywords);
+
+ if (pkw_setwords(pk, defexec, defkey, kws, nkw, defnext) == -1)
+ goto err;
+
+ return pk;
+err:
+ free(pk);
+ return NULL;
+}
+
+int
+parse(int argc, char **argv, const struct parser *p0, struct match *matches,
+ size_t *nmatch, int *narg)
+{
+ int i, rc = 0;
+ struct match *lastm = NULL, *m = matches;
+ const struct parser *p = p0;
+
+ for (i = 0; i < argc && p != NULL; i++) {
+ if ((size_t)(m - matches) >= *nmatch) {
+ errno = EFBIG;
+ rc = -1;
+ break;
+ }
+ rc = (*p->p_methods->pm_match)(p, lastm, m, i, argv[i]);
+ if (rc != 0)
+ goto out;
+ p = m->m_nextparser;
+ lastm = m++;
+ }
+ for (; (size_t)(m - matches) < *nmatch && p != NULL; ) {
+ rc = (*p->p_methods->pm_match)(p, lastm, m, i, NULL);
+ if (rc != 0)
+ break;
+ p = m->m_nextparser;
+ lastm = m++;
+ }
+out:
+ *nmatch = m - matches;
+ *narg = i;
+ return rc;
+}
+
+int
+matches_exec(const struct match *matches, prop_dictionary_t oenv, size_t nmatch)
+{
+ size_t i;
+ int rc = 0;
+ const struct match *m;
+ parser_exec_t pexec;
+ prop_dictionary_t d;
+
+ for (i = 0; i < nmatch; i++) {
+ m = &matches[i];
+ dbg_warnx("%s.%d: i %zu", __func__, __LINE__, i);
+ pexec = (m->m_parser->p_exec != NULL)
+ ? m->m_parser->p_exec : m->m_exec;
+ if (pexec == NULL)
+ continue;
+ dbg_warnx("%s.%d: m->m_parser->p_name %s", __func__, __LINE__,
+ m->m_parser->p_name);
+ d = prop_dictionary_augment(m->m_env, oenv);
+ rc = (*pexec)(d, oenv);
+ prop_object_release((prop_object_t)d);
+ if (rc == -1)
+ break;
+ }
+ return rc;
+}
+
+int
+parser_init(struct parser *p)
+{
+ if (p->p_initialized)
+ return 0;
+ p->p_initialized = true;
+ if (p->p_methods->pm_init == NULL)
+ return 0;
+ return (*p->p_methods->pm_init)(p);
+}
--- /dev/null
+#ifndef _IFCONFIG_PARSE_H
+#define _IFCONFIG_PARSE_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/queue.h>
+#include <prop/proplib.h>
+#include <sys/socket.h>
+
+struct match;
+struct parser;
+
+extern struct pbranch command_root;
+
+typedef int (*parser_exec_t)(prop_dictionary_t, prop_dictionary_t);
+typedef int (*parser_match_t)(const struct parser *, const struct match *,
+ struct match *, int, const char *);
+typedef int (*parser_init_t)(struct parser *);
+
+struct match {
+ prop_dictionary_t m_env;
+ const struct parser *m_nextparser;
+ const struct parser *m_parser;
+ int m_argidx;
+ parser_exec_t m_exec;
+};
+
+/* method table */
+struct parser_methods {
+ parser_match_t pm_match;
+ parser_init_t pm_init;
+};
+
+struct parser {
+ const struct parser_methods *p_methods;
+ parser_exec_t p_exec;
+ const char *p_name;
+ struct parser *p_nextparser;
+ bool p_initialized;
+};
+
+struct branch {
+ SIMPLEQ_ENTRY(branch) b_next;
+ struct parser *b_nextparser;
+};
+
+struct pbranch {
+ struct parser pb_parser;
+ SIMPLEQ_HEAD(, branch) pb_branches;
+ bool pb_match_first;
+ const struct branch *pb_brinit;
+ size_t pb_nbrinit;
+};
+
+struct pterm {
+ struct parser pt_parser;
+ const char *pt_key;
+};
+
+extern const struct parser_methods paddr_methods;
+extern const struct parser_methods pbranch_methods;
+extern const struct parser_methods piface_methods;
+extern const struct parser_methods pinteger_methods;
+extern const struct parser_methods pstr_methods;
+extern const struct parser_methods pkw_methods;
+extern const struct parser_methods pterm_methods;
+
+#define PTERM_INITIALIZER(__pt, __name, __exec, __key) \
+{ \
+ .pt_parser = {.p_name = (__name), .p_methods = &pterm_methods, \
+ .p_exec = (__exec)}, \
+ .pt_key = (__key) \
+}
+
+#define PBRANCH_INITIALIZER(__pb, __name, __brs, __nbr, __match_first) \
+{ \
+ .pb_parser = {.p_name = (__name), .p_methods = &pbranch_methods},\
+ .pb_branches = SIMPLEQ_HEAD_INITIALIZER((__pb)->pb_branches), \
+ .pb_brinit = (__brs), \
+ .pb_nbrinit = (__nbr), \
+ .pb_match_first = (__match_first) \
+}
+
+#define PSTR_INITIALIZER(__ps, __name, __defexec, __defkey, __defnext) \
+ PSTR_INITIALIZER1((__ps), (__name), (__defexec), (__defkey), \
+ true, (__defnext))
+
+#define PSTR_INITIALIZER1(__ps, __name, __defexec, __defkey, __defhexok,\
+ __defnext) \
+{ \
+ .ps_parser = {.p_name = (__name), .p_methods = &pstr_methods, \
+ .p_exec = (__defexec), \
+ .p_nextparser = (__defnext)}, \
+ .ps_key = (__defkey), \
+ .ps_hexok = (__defhexok) \
+}
+
+#define PADDR_INITIALIZER(__pa, __name, __defexec, __addrkey, \
+ __maskkey, __activator, __deactivator, __defnext) \
+{ \
+ .pa_parser = {.p_name = (__name), .p_methods = &paddr_methods, \
+ .p_exec = (__defexec), \
+ .p_nextparser = (__defnext)}, \
+ .pa_addrkey = (__addrkey), \
+ .pa_maskkey = (__maskkey), \
+ .pa_activator = (__activator), \
+ .pa_deactivator = (__deactivator), \
+}
+
+#define PIFACE_INITIALIZER(__pif, __name, __defexec, __defkey, __defnext)\
+{ \
+ .pif_parser = {.p_name = (__name), .p_methods = &piface_methods,\
+ .p_exec = (__defexec), \
+ .p_nextparser = (__defnext)}, \
+ .pif_key = (__defkey) \
+}
+
+#define PINTEGER_INITIALIZER1(__pi, __name, __min, __max, __base, \
+ __defexec, __defkey, __defnext) \
+{ \
+ .pi_parser = {.p_name = (__name), .p_methods = &pinteger_methods,\
+ .p_exec = (__defexec), \
+ .p_nextparser = (__defnext), \
+ .p_initialized = false}, \
+ .pi_min = (__min), \
+ .pi_max = (__max), \
+ .pi_base = (__base), \
+ .pi_key = (__defkey) \
+}
+
+#define PINTEGER_INITIALIZER(__pi, __name, __base, __defexec, __defkey, \
+ __defnext) \
+ PINTEGER_INITIALIZER1(__pi, __name, INTMAX_MIN, INTMAX_MAX, \
+ __base, __defexec, __defkey, __defnext)
+
+#define PKW_INITIALIZER(__pk, __name, __defexec, __defkey, __kws, __nkw,\
+ __defnext) \
+{ \
+ .pk_parser = {.p_name = (__name), \
+ .p_exec = (__defexec), \
+ .p_methods = &pkw_methods, \
+ .p_initialized = false}, \
+ .pk_keywords = SIMPLEQ_HEAD_INITIALIZER((__pk)->pk_keywords), \
+ .pk_kwinit = (__kws), \
+ .pk_nkwinit = (__nkw), \
+ .pk_keyinit = (__defkey), \
+ .pk_nextinit = (__defnext) \
+}
+
+#define IFKW(__word, __flag) \
+{ \
+ .k_word = (__word), .k_neg = true, .k_type = KW_T_INT, \
+ .k_int = (__flag), \
+ .k_negint = -(__flag) \
+}
+
+#define KW_T_NONE 0
+#define KW_T_OBJ 1
+#define KW_T_INT 2
+#define KW_T_STR 3
+#define KW_T_BOOL 4
+#define KW_T_UINT 5
+
+struct kwinst {
+ SIMPLEQ_ENTRY(kwinst) k_next;
+ int k_type;
+ const char *k_word;
+ const char *k_key;
+ const char *k_act;
+ const char *k_deact;
+ const char *k_altdeact;
+ parser_exec_t k_exec;
+ union kwval {
+ int64_t u_sint;
+ uint64_t u_uint;
+ const char *u_str;
+ prop_object_t u_obj;
+ bool u_bool;
+ } k_u, k_negu;
+#define k_int k_u.u_sint
+#define k_uint k_u.u_uint
+#define k_str k_u.u_str
+#define k_obj k_u.u_obj
+#define k_bool k_u.u_bool
+
+#define k_negint k_negu.u_sint
+#define k_neguint k_negu.u_uint
+#define k_negstr k_negu.u_str
+#define k_negobj k_negu.u_obj
+#define k_negbool k_negu.u_bool
+
+ bool k_neg; /* allow negative form, -keyword */
+ struct parser *k_nextparser;
+};
+
+struct pkw {
+ struct parser pk_parser;
+ const char *pk_key;
+ const char *pk_keyinit;
+ const struct kwinst *pk_kwinit;
+ size_t pk_nkwinit;
+ SIMPLEQ_HEAD(, kwinst) pk_keywords;
+};
+
+#define pk_nextinit pk_parser.p_nextparser
+#define pk_execinit pk_parser.p_exec
+
+struct pstr {
+ struct parser ps_parser;
+ const char *ps_key;
+ bool ps_hexok;
+};
+
+struct pinteger {
+ struct parser pi_parser;
+ int64_t pi_min;
+ int64_t pi_max;
+ int pi_base;
+ const char *pi_key;
+};
+
+struct intrange {
+ SIMPLEQ_ENTRY(intrange) r_next;
+ int64_t r_bottom;
+ int64_t r_top;
+ struct parser *r_nextparser;
+};
+
+struct pranges {
+ struct parser pr_parser;
+ SIMPLEQ_HEAD(, intrange) pr_ranges;
+};
+
+struct paddr_prefix {
+ int16_t pfx_len;
+ struct sockaddr pfx_addr;
+};
+
+static inline size_t
+paddr_prefix_size(const struct paddr_prefix *pfx)
+{
+ return offsetof(struct paddr_prefix, pfx_addr) + pfx->pfx_addr.sa_len;
+}
+
+struct paddr {
+ struct parser pa_parser;
+ const char *pa_addrkey;
+ const char *pa_maskkey;
+ const char *pa_activator;
+ const char *pa_deactivator;
+};
+
+struct piface {
+ struct parser pif_parser;
+ const char *pif_key;
+};
+
+struct prest {
+ struct parser pr_parser;
+};
+
+struct prest *prest_create(const char *);
+struct paddr *paddr_create(const char *, parser_exec_t, const char *,
+ const char *, struct parser *);
+struct pstr *pstr_create(const char *, parser_exec_t, const char *,
+ bool, struct parser *);
+struct piface *piface_create(const char *, parser_exec_t, const char *,
+ struct parser *);
+struct pkw *pkw_create(const char *, parser_exec_t,
+ const char *, const struct kwinst *, size_t, struct parser *);
+struct pranges *pranges_create(const char *, parser_exec_t, const char *,
+ const struct intrange *, size_t, struct parser *);
+struct pbranch *pbranch_create(const char *, const struct branch *, size_t,
+ bool);
+int pbranch_addbranch(struct pbranch *, struct parser *);
+int pbranch_setbranches(struct pbranch *, const struct branch *, size_t);
+
+int parse(int, char **, const struct parser *, struct match *, size_t *, int *);
+
+int matches_exec(const struct match *, prop_dictionary_t, size_t);
+int parser_init(struct parser *);
+
+#endif /* _IFCONFIG_PARSE_H */
--- /dev/null
+/* $NetBSD: pfsync.c,v 1.1 2009/09/14 10:36:49 degroote Exp $ */
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * 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 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: pfsync.c,v 1.1 2009/09/14 10:36:49 degroote Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/pfvar.h>
+#include <net/if_pfsync.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <util.h>
+
+#include "env.h"
+#include "parse.h"
+#include "extern.h"
+
+static status_func_t status;
+static usage_func_t usage;
+static cmdloop_branch_t branch;
+
+static void pfsync_constructor(void) __attribute__((constructor));
+static void pfsync_status(prop_dictionary_t, prop_dictionary_t);
+static int setpfsync_maxupd(prop_dictionary_t, prop_dictionary_t);
+static int setpfsync_peer(prop_dictionary_t, prop_dictionary_t);
+static int setpfsyncdev(prop_dictionary_t, prop_dictionary_t);
+
+struct pinteger parse_maxupd = PINTEGER_INITIALIZER1(&parse_maxupd, "maxupd",
+ 0, 255, 10, setpfsync_maxupd, "maxupd", &command_root.pb_parser);
+
+struct piface pfsyncdev = PIFACE_INITIALIZER(&pfsyncdev, "syncdev", setpfsyncdev,
+ "syncdev", &command_root.pb_parser);
+
+struct paddr parse_sync_peer = PADDR_INITIALIZER(&parse_sync_peer, "syncpeer",
+ setpfsync_peer, "syncpeer", NULL, NULL, NULL, &command_root.pb_parser);
+
+static const struct kwinst pfsynckw[] = {
+ {.k_word = "maxupd", .k_nextparser = &parse_maxupd.pi_parser},
+ {.k_word = "syncdev", .k_nextparser = &pfsyncdev.pif_parser},
+ {.k_word = "-syncdev", .k_key = "syncdev", .k_type = KW_T_STR,
+ .k_str = "", .k_exec = setpfsyncdev,
+ .k_nextparser = &command_root.pb_parser},
+ {.k_word = "syncpeer", .k_nextparser = &parse_sync_peer.pa_parser},
+ {.k_word = "-syncpeer", .k_key = "syncpeer", .k_type = KW_T_STR,
+ .k_str = "", .k_exec = setpfsync_peer,
+ .k_nextparser = &command_root.pb_parser}
+};
+
+struct pkw pfsync = PKW_INITIALIZER(&pfsync, "pfsync", NULL, NULL,
+ pfsynckw, __arraycount(pfsynckw), NULL);
+
+static void
+pfsync_set(prop_dictionary_t env, struct pfsyncreq *pfsyncr)
+{
+ if (indirect_ioctl(env, SIOCSETPFSYNC, pfsyncr) == -1)
+ err(EXIT_FAILURE, "SIOCSETPFSYNC");
+}
+
+static int
+pfsync_get1(prop_dictionary_t env, struct pfsyncreq *pfsyncr)
+{
+ memset(pfsyncr, 0, sizeof(*pfsyncr));
+
+ return indirect_ioctl(env, SIOCGETPFSYNC, pfsyncr);
+}
+
+static void
+pfsync_get(prop_dictionary_t env, struct pfsyncreq *pfsyncr)
+{
+ if (pfsync_get1(env, pfsyncr) == -1)
+ err(EXIT_FAILURE, "SIOCGETPFSYNC");
+}
+
+static void
+pfsync_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct pfsyncreq pfsyncr;
+
+ if (pfsync_get1(env, &pfsyncr) == -1)
+ return;
+
+ if (pfsyncr.pfsyncr_syncdev[0] != '\0') {
+ printf("\tpfsync: syncdev: %s ", pfsyncr.pfsyncr_syncdev);
+ if (pfsyncr.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
+ printf("syncpeer: %s ",
+ inet_ntoa(pfsyncr.pfsyncr_syncpeer));
+ printf("maxupd: %d\n", pfsyncr.pfsyncr_maxupdates);
+ }
+}
+
+/* ARGSUSED */
+int
+setpfsync_maxupd(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct pfsyncreq pfsyncr;
+ uint8_t maxupd;
+
+ if (!prop_dictionary_get_uint8(env, "maxupd", &maxupd)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ pfsync_get(env, &pfsyncr);
+
+ pfsyncr.pfsyncr_maxupdates = maxupd;
+
+ pfsync_set(env, &pfsyncr);
+ return 0;
+}
+
+
+/* ARGSUSED */
+int
+setpfsyncdev(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct pfsyncreq pfsyncr;
+ const char *dev;
+
+ if (!prop_dictionary_get_cstring_nocopy(env, "syncdev", &dev)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ pfsync_get(env, &pfsyncr);
+
+ strlcpy(pfsyncr.pfsyncr_syncdev, dev, sizeof(pfsyncr.pfsyncr_syncdev));
+
+ pfsync_set(env, &pfsyncr);
+ return 0;
+}
+
+/* ARGSUSED */
+int
+setpfsync_peer(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct pfsyncreq pfsyncr;
+ prop_data_t data;
+ const struct paddr_prefix *peerpfx;
+ const struct sockaddr_in *s;
+
+ data = (prop_data_t)prop_dictionary_get(env, "syncpeer");
+ if (data == NULL) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ pfsync_get(env, &pfsyncr);
+
+ peerpfx = prop_data_data_nocopy(data);
+
+ if (peerpfx != NULL) {
+ // Only AF_INET is supported for now
+ if (peerpfx->pfx_addr.sa_family != AF_INET) {
+ errno = ENOENT;
+ return -1;
+ }
+
+
+ s = (const struct sockaddr_in*)&peerpfx->pfx_addr;
+
+ memcpy(&pfsyncr.pfsyncr_syncpeer.s_addr, &s->sin_addr,
+ MIN(sizeof(pfsyncr.pfsyncr_syncpeer.s_addr),
+ peerpfx->pfx_addr.sa_len));
+ } else {
+ memset(&pfsyncr.pfsyncr_syncpeer.s_addr, 0,
+ sizeof(pfsyncr.pfsyncr_syncpeer.s_addr));
+ }
+
+ pfsync_set(env, &pfsyncr);
+
+ return 0;
+}
+
+static void
+pfsync_usage(prop_dictionary_t env)
+{
+ fprintf(stderr,
+ "\t[ maxupd n ] [ syncdev iface ] [syncpeer peer_addr]\n");
+}
+
+static void
+pfsync_constructor(void)
+{
+ cmdloop_branch_init(&branch, &pfsync.pk_parser);
+ register_cmdloop_branch(&branch);
+ status_func_init(&status, pfsync_status);
+ usage_func_init(&usage, pfsync_usage);
+ register_status(&status);
+ register_usage(&usage);
+}
--- /dev/null
+/* $NetBSD: prog_ops.h,v 1.3 2010/12/13 21:48:01 pooka Exp $ */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * 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 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.
+ */
+
+#ifndef _PROG_OPS_H_
+#define _PROG_OPS_H_
+
+#include <sys/types.h>
+
+/* ifconfig is compiled outside of src/sbin/ifconfig too */
+#ifndef CRUNCHOPS
+struct prog_ops {
+ int (*op_init)(void);
+
+ int (*op_socket)(int, int, int);
+
+ int (*op_ioctl)(int, unsigned long, ...);
+ ssize_t (*op_read)(int, void *, size_t);
+
+ int (*op_close)(int);
+};
+extern const struct prog_ops prog_ops;
+
+#define prog_init prog_ops.op_init
+#define prog_socket prog_ops.op_socket
+#define prog_ioctl prog_ops.op_ioctl
+#define prog_read prog_ops.op_read
+#define prog_close prog_ops.op_close
+#else
+#define prog_init ((int (*)(void))NULL)
+#define prog_socket socket
+#define prog_ioctl ioctl
+#define prog_read read
+#define prog_close close
+#endif
+
+#endif /* _PROG_OPS_H_ */
--- /dev/null
+/* $NetBSD: tunnel.c,v 1.20 2013/10/19 15:59:15 christos Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: tunnel.c,v 1.20 2013/10/19 15:59:15 christos Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#ifdef INET6
+#include <netinet/in.h>
+#endif
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "parse.h"
+#include "util.h"
+
+static status_func_t status;
+static usage_func_t usage;
+static cmdloop_branch_t branch;
+
+static void tunnel_constructor(void) __attribute__((constructor));
+static int settunnel(prop_dictionary_t, prop_dictionary_t);
+static int deletetunnel(prop_dictionary_t, prop_dictionary_t);
+static void tunnel_status(prop_dictionary_t, prop_dictionary_t);
+
+struct paddr tundst = PADDR_INITIALIZER(&tundst, "tundst", settunnel,
+ "tundst", NULL, NULL, NULL, &command_root.pb_parser);
+
+struct paddr tunsrc = PADDR_INITIALIZER(&tunsrc, "tunsrc", NULL,
+ "tunsrc", NULL, NULL, NULL, &tundst.pa_parser);
+
+static const struct kwinst tunnelkw[] = {
+ {.k_word = "deletetunnel", .k_exec = deletetunnel,
+ .k_nextparser = &command_root.pb_parser}
+ , {.k_word = "tunnel", .k_nextparser = &tunsrc.pa_parser}
+};
+
+struct pkw tunnel = PKW_INITIALIZER(&tunnel, "tunnel", NULL, NULL,
+ tunnelkw, __arraycount(tunnelkw), NULL);
+
+static int
+settunnel(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ const struct paddr_prefix *srcpfx, *dstpfx;
+ struct if_laddrreq req;
+ prop_data_t srcdata, dstdata;
+
+ srcdata = (prop_data_t)prop_dictionary_get(env, "tunsrc");
+ dstdata = (prop_data_t)prop_dictionary_get(env, "tundst");
+
+ if (srcdata == NULL || dstdata == NULL) {
+ warnx("%s.%d", __func__, __LINE__);
+ errno = ENOENT;
+ return -1;
+ }
+
+ srcpfx = prop_data_data_nocopy(srcdata);
+ dstpfx = prop_data_data_nocopy(dstdata);
+
+ if (srcpfx->pfx_addr.sa_family != dstpfx->pfx_addr.sa_family)
+ errx(EXIT_FAILURE,
+ "source and destination address families do not match");
+
+ memset(&req, 0, sizeof(req));
+ memcpy(&req.addr, &srcpfx->pfx_addr,
+ MIN(sizeof(req.addr), srcpfx->pfx_addr.sa_len));
+ memcpy(&req.dstaddr, &dstpfx->pfx_addr,
+ MIN(sizeof(req.dstaddr), dstpfx->pfx_addr.sa_len));
+
+#ifdef INET6
+ if (req.addr.ss_family == AF_INET6) {
+ struct sockaddr_in6 *s6, *d;
+
+ s6 = (struct sockaddr_in6 *)&req.addr;
+ d = (struct sockaddr_in6 *)&req.dstaddr;
+ if (s6->sin6_scope_id != d->sin6_scope_id) {
+ errx(EXIT_FAILURE, "scope mismatch");
+ /* NOTREACHED */
+ }
+ if (IN6_IS_ADDR_MULTICAST(&d->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&s6->sin6_addr))
+ errx(EXIT_FAILURE, "tunnel src/dst is multicast");
+ /* embed scopeid */
+ inet6_putscopeid(s6, INET6_IS_ADDR_LINKLOCAL);
+ inet6_putscopeid(d, INET6_IS_ADDR_LINKLOCAL);
+ }
+#endif /* INET6 */
+
+ if (direct_ioctl(env, SIOCSLIFPHYADDR, &req) == -1)
+ warn("SIOCSLIFPHYADDR");
+ return 0;
+}
+
+static int
+deletetunnel(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ if (indirect_ioctl(env, SIOCDIFPHYADDR, NULL) == -1)
+ err(EXIT_FAILURE, "SIOCDIFPHYADDR");
+ return 0;
+}
+
+static void
+tunnel_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ char dstserv[sizeof(",65535")];
+ char srcserv[sizeof(",65535")];
+ char psrcaddr[NI_MAXHOST];
+ char pdstaddr[NI_MAXHOST];
+ const int niflag = Nflag ? 0 : (NI_NUMERICHOST|NI_NUMERICSERV);
+ struct if_laddrreq req;
+ const struct afswtch *afp;
+
+ psrcaddr[0] = pdstaddr[0] = '\0';
+
+ memset(&req, 0, sizeof(req));
+ if (direct_ioctl(env, SIOCGLIFPHYADDR, &req) == -1)
+ return;
+ afp = lookup_af_bynum(req.addr.ss_family);
+#ifdef INET6
+ if (req.addr.ss_family == AF_INET6)
+ inet6_getscopeid((struct sockaddr_in6 *)&req.addr,
+ INET6_IS_ADDR_LINKLOCAL);
+#endif /* INET6 */
+ getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
+ psrcaddr, sizeof(psrcaddr), &srcserv[1], sizeof(srcserv) - 1,
+ niflag);
+
+#ifdef INET6
+ if (req.dstaddr.ss_family == AF_INET6)
+ inet6_getscopeid((struct sockaddr_in6 *)&req.dstaddr,
+ INET6_IS_ADDR_LINKLOCAL);
+#endif
+ getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
+ pdstaddr, sizeof(pdstaddr), &dstserv[1], sizeof(dstserv) - 1,
+ niflag);
+
+ srcserv[0] = (strcmp(&srcserv[1], "0") == 0) ? '\0' : ',';
+ dstserv[0] = (strcmp(&dstserv[1], "0") == 0) ? '\0' : ',';
+
+ printf("\ttunnel %s %s%s --> %s%s\n", afp ? afp->af_name : "???",
+ psrcaddr, srcserv, pdstaddr, dstserv);
+}
+
+static void
+tunnel_usage(prop_dictionary_t env)
+{
+ fprintf(stderr,
+ "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n");
+}
+
+static void
+tunnel_constructor(void)
+{
+ cmdloop_branch_init(&branch, &tunnel.pk_parser);
+ register_cmdloop_branch(&branch);
+ status_func_init(&status, tunnel_status);
+ usage_func_init(&usage, tunnel_usage);
+ register_status(&status);
+ register_usage(&usage);
+}
--- /dev/null
+/* $NetBSD: util.c,v 1.17 2013/10/19 00:35:30 christos Exp $ */
+
+/*-
+ * Copyright (c) 2008 David Young. 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: util.c,v 1.17 2013/10/19 00:35:30 christos Exp $");
+#endif /* not lint */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <netinet/in.h> /* XXX */
+
+#include "env.h"
+#include "extern.h"
+#include "util.h"
+#include "prog_ops.h"
+
+int
+getsock(int naf)
+{
+ static int oaf = -1, s;
+
+ if (oaf == naf || (oaf != -1 && naf == AF_UNSPEC))
+ return s;
+
+ if (oaf != -1)
+ prog_close(s);
+
+ if (naf == AF_UNSPEC)
+ naf = AF_INET;
+
+ s = prog_socket(naf, SOCK_DGRAM, 0);
+ if (s == -1)
+ oaf = -1;
+ else
+ oaf = naf;
+ return s;
+}
+
+const char *
+get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp,
+ bool hexok)
+{
+ int len;
+ bool hexstr;
+ u_int8_t *p;
+
+ len = *lenp;
+ p = buf;
+ hexstr = hexok && 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]) ||
+ !isxdigit((u_char)val[1])) {
+ warnx("bad hexadecimal digits");
+ return NULL;
+ }
+ }
+ if (p >= buf + len) {
+ if (hexstr)
+ warnx("hexadecimal digits too long");
+ else
+ warnx("strings 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;
+ if (len < *lenp)
+ memset(p, 0, *lenp - len);
+ *lenp = len;
+ return val;
+}
+
+void
+print_string(const u_int8_t *buf, int len)
+{
+ int i;
+ bool hasspc;
+
+ i = 0;
+ hasspc = false;
+ if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
+ for (; i < len; i++) {
+ if (!isprint(buf[i]))
+ break;
+ if (isspace(buf[i]))
+ hasspc = true;
+ }
+ }
+ if (i == len) {
+ if (hasspc || len == 0)
+ printf("\"%.*s\"", len, buf);
+ else
+ printf("%.*s", len, buf);
+ } else {
+ printf("0x");
+ for (i = 0; i < len; i++)
+ printf("%02x", buf[i]);
+ }
+}
+
+struct paddr_prefix *
+prefixlen_to_mask(int af, int plen)
+{
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } u;
+ struct paddr_prefix *pfx;
+ size_t addrlen;
+ uint8_t *addr;
+ int nbit;
+
+ memset(&u, 0, sizeof(u));
+
+ switch (af) {
+ case AF_INET:
+ addrlen = sizeof(u.sin.sin_addr);
+ addr = (uint8_t *)&u.sin.sin_addr;
+ u.sa.sa_len = sizeof(u.sin);
+ break;
+ case AF_INET6:
+ addrlen = sizeof(u.sin6.sin6_addr);
+ addr = (uint8_t *)&u.sin6.sin6_addr;
+ u.sa.sa_len = sizeof(u.sin6);
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+ u.sa.sa_family = af;
+
+ if (plen < 0 || (size_t)plen > addrlen * NBBY) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (plen == 0)
+ plen = addrlen * NBBY;
+
+ memset(addr, 0xff, (plen + NBBY - 1) / NBBY);
+
+ nbit = plen % NBBY;
+ if (nbit != 0)
+ addr[plen / NBBY] &= ~((uint8_t)0xff >> nbit);
+ pfx = malloc(offsetof(struct paddr_prefix, pfx_addr) + u.sa.sa_len);
+ if (pfx == NULL)
+ return NULL;
+ pfx->pfx_len = plen;
+ memcpy(&pfx->pfx_addr, &u.sa, u.sa.sa_len);
+
+ return pfx;
+}
+
+int
+direct_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
+{
+ const char *ifname;
+ int s;
+
+ if ((s = getsock(AF_UNSPEC)) == -1)
+ err(EXIT_FAILURE, "getsock");
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "getifname");
+
+ estrlcpy(data, ifname, IFNAMSIZ);
+
+ return prog_ioctl(s, cmd, data);
+}
+
+int
+indirect_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ ifr.ifr_data = data;
+
+ return direct_ioctl(env, cmd, &ifr);
+}
+
+void
+print_link_addresses(prop_dictionary_t env, bool print_active_only)
+{
+ char hbuf[NI_MAXHOST];
+ const char *ifname;
+ int s;
+ struct ifaddrs *ifa, *ifap;
+ const struct sockaddr_dl *sdl;
+ struct if_laddrreq iflr;
+
+ if ((ifname = getifname(env)) == NULL)
+ err(EXIT_FAILURE, "%s: getifname", __func__);
+
+ if ((s = getsock(AF_LINK)) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+
+ if (getifaddrs(&ifap) == -1)
+ err(EXIT_FAILURE, "%s: getifaddrs", __func__);
+
+ memset(&iflr, 0, sizeof(iflr));
+
+ strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ sdl = satocsdl(ifa->ifa_addr);
+
+ memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len,
+ sizeof(iflr.addr)));
+ iflr.flags = IFLR_PREFIX;
+ iflr.prefixlen = sdl->sdl_alen * NBBY;
+
+ if (prog_ioctl(s, SIOCGLIFADDR, &iflr) == -1)
+ err(EXIT_FAILURE, "%s: ioctl", __func__);
+
+ if (((iflr.flags & IFLR_ACTIVE) != 0) != print_active_only)
+ continue;
+
+ if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
+ hbuf, sizeof(hbuf), NULL, 0,
+ Nflag ? 0 : NI_NUMERICHOST) == 0 &&
+ hbuf[0] != '\0') {
+ printf("\t%s %s\n",
+ print_active_only ? "address:" : "link", hbuf);
+ }
+ }
+ freeifaddrs(ifap);
+}
+
+int16_t
+ifa_get_preference(const char *ifname, const struct sockaddr *sa)
+{
+ struct if_addrprefreq ifap;
+ int s;
+
+ if ((s = getsock(sa->sa_family)) == -1) {
+ if (errno == EPROTONOSUPPORT)
+ return 0;
+ err(EXIT_FAILURE, "socket");
+ }
+ memset(&ifap, 0, sizeof(ifap));
+ estrlcpy(ifap.ifap_name, ifname, sizeof(ifap.ifap_name));
+ memcpy(&ifap.ifap_addr, sa, MIN(sizeof(ifap.ifap_addr), sa->sa_len));
+ if (prog_ioctl(s, SIOCGIFADDRPREF, &ifap) == -1) {
+ if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
+ return 0;
+ warn("SIOCGIFADDRPREF");
+ }
+ return ifap.ifap_preference;
+}
+
+void
+ifa_print_preference(const char *ifname, const struct sockaddr *sa)
+{
+ int16_t preference;
+
+ if (lflag)
+ return;
+
+ preference = ifa_get_preference(ifname, sa);
+ printf(" preference %" PRId16, preference);
+}
+
+bool
+ifa_any_preferences(const char *ifname, struct ifaddrs *ifap, int family)
+{
+ struct ifaddrs *ifa;
+
+ /* Print address preference numbers if any address has a non-zero
+ * preference assigned.
+ */
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != family)
+ continue;
+ if (ifa_get_preference(ifa->ifa_name, ifa->ifa_addr) != 0)
+ return true;
+ }
+ return false;
+}
--- /dev/null
+#ifndef _IFCONFIG_UTIL_H
+#define _IFCONFIG_UTIL_H
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+
+#include "parse.h"
+
+struct afswtch {
+ const char *af_name;
+ short af_af;
+ void (*af_status)(prop_dictionary_t, prop_dictionary_t, bool);
+ void (*af_addr_commit)(prop_dictionary_t, prop_dictionary_t);
+ bool (*af_addr_tentative)(struct ifaddrs *);
+ SIMPLEQ_ENTRY(afswtch) af_next;
+};
+
+void print_link_addresses(prop_dictionary_t, bool);
+const char *get_string(const char *, const char *, u_int8_t *, int *, bool);
+const struct afswtch *lookup_af_byname(const char *);
+const struct afswtch *lookup_af_bynum(int);
+void print_string(const u_int8_t *, int);
+int getsock(int);
+struct paddr_prefix *prefixlen_to_mask(int, int);
+int direct_ioctl(prop_dictionary_t, unsigned long, void *);
+int indirect_ioctl(prop_dictionary_t, unsigned long, void *);
+bool ifa_any_preferences(const char *, struct ifaddrs *, int);
+void ifa_print_preference(const char *, const struct sockaddr *);
+int16_t ifa_get_preference(const char *, const struct sockaddr *);
+
+#endif /* _IFCONFIG_UTIL_H */
--- /dev/null
+/* $NetBSD: vlan.c,v 1.14 2014/09/15 06:46:04 ozaki-r Exp $ */
+
+/*
+ * 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. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: vlan.c,v 1.14 2014/09/15 06:46:04 ozaki-r Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_vlanvar.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <util.h>
+
+#include "env.h"
+#include "extern.h"
+#include "util.h"
+
+static status_func_t status;
+static usage_func_t usage;
+static cmdloop_branch_t branch;
+
+static void vlan_constructor(void) __attribute__((constructor));
+static void vlan_status(prop_dictionary_t, prop_dictionary_t);
+
+static int setvlan(prop_dictionary_t, prop_dictionary_t);
+static int setvlanif(prop_dictionary_t, prop_dictionary_t);
+
+struct pinteger vlantag = PINTEGER_INITIALIZER1(&vlantag, "VLAN tag",
+ 0, USHRT_MAX, 10, setvlan, "vlantag", &command_root.pb_parser);
+
+struct piface vlanif = PIFACE_INITIALIZER(&vlanif, "vlanif", setvlanif,
+ "vlanif", &command_root.pb_parser);
+
+static const struct kwinst vlankw[] = {
+ {.k_word = "vlan", .k_nextparser = &vlantag.pi_parser}
+ , {.k_word = "vlanif", .k_act = "vlantag",
+ .k_nextparser = &vlanif.pif_parser}
+ , {.k_word = "-vlanif", .k_key = "vlanif", .k_type = KW_T_STR,
+ .k_str = "", .k_exec = setvlanif}
+};
+
+struct pkw vlan = PKW_INITIALIZER(&vlan, "vlan", NULL, NULL,
+ vlankw, __arraycount(vlankw), NULL);
+
+static int
+checkifname(prop_dictionary_t env)
+{
+ const char *ifname;
+
+ if ((ifname = getifname(env)) == NULL)
+ return 1;
+
+ return strncmp(ifname, "vlan", 4) != 0 ||
+ !isdigit((unsigned char)ifname[4]);
+}
+
+static int
+getvlan(prop_dictionary_t env, struct vlanreq *vlr, bool quiet)
+{
+ memset(vlr, 0, sizeof(*vlr));
+
+ if (checkifname(env)) {
+ if (quiet)
+ return -1;
+ errx(EXIT_FAILURE, "valid only with vlan(4) interfaces");
+ }
+
+ if (indirect_ioctl(env, SIOCGETVLAN, vlr) == -1)
+ return -1;
+
+ return 0;
+}
+
+int
+setvlan(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct vlanreq vlr;
+ int64_t tag;
+
+ if (getvlan(env, &vlr, false) == -1)
+ err(EXIT_FAILURE, "%s: getvlan", __func__);
+
+ if (!prop_dictionary_get_int64(env, "vlantag", &tag)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ vlr.vlr_tag = tag;
+
+ if (indirect_ioctl(env, SIOCSETVLAN, &vlr) == -1)
+ err(EXIT_FAILURE, "SIOCSETVLAN");
+ return 0;
+}
+
+int
+setvlanif(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct vlanreq vlr;
+ const char *parent;
+ int64_t tag;
+
+ if (getvlan(env, &vlr, false) == -1)
+ err(EXIT_FAILURE, "%s: getsock", __func__);
+
+ if (!prop_dictionary_get_cstring_nocopy(env, "vlanif", &parent)) {
+ errno = ENOENT;
+ return -1;
+ }
+ strlcpy(vlr.vlr_parent, parent, sizeof(vlr.vlr_parent));
+ if (strcmp(parent, "") == 0)
+ ;
+ else if (!prop_dictionary_get_int64(env, "vlantag", &tag)) {
+ errno = ENOENT;
+ return -1;
+ } else
+ vlr.vlr_tag = (unsigned short)tag;
+
+ if (indirect_ioctl(env, SIOCSETVLAN, &vlr) == -1)
+ err(EXIT_FAILURE, "SIOCSETVLAN");
+ return 0;
+}
+
+static void
+vlan_status(prop_dictionary_t env, prop_dictionary_t oenv)
+{
+ struct vlanreq vlr;
+
+ if (getvlan(env, &vlr, true) == -1)
+ return;
+
+ if (vlr.vlr_tag || vlr.vlr_parent[0] != '\0')
+ printf("\tvlan: %d parent: %s\n",
+ vlr.vlr_tag, vlr.vlr_parent[0] == '\0' ?
+ "<none>" : vlr.vlr_parent);
+}
+
+static void
+vlan_usage(prop_dictionary_t env)
+{
+ fprintf(stderr, "\t[ vlan n vlanif i ] [ -vlanif i ]\n");
+}
+
+static void
+vlan_constructor(void)
+{
+ cmdloop_branch_init(&branch, &vlan.pk_parser);
+ register_cmdloop_branch(&branch);
+ status_func_init(&status, vlan_status);
+ usage_func_init(&usage, vlan_usage);
+ register_status(&status);
+ register_usage(&usage);
+}