Bring in new ifconfig(8) from FreeBSD6. It is more modular and flexible with
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 2 Apr 2006 03:33:59 +0000 (03:33 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 2 Apr 2006 03:33:59 +0000 (03:33 +0000)
respect to supporting interface specific functionality.

Thank Sam Leffler and many other people for their work on ifconfig(8)

NOTE:
- There is no noticeable changes from users' point of view
- Three files have been left out: ifmac.c, ifcarp.c, ifpfsync.c
- Old ifieee80211.c is adapted to fit in the new ifconfig(8), newer one will
  be imported with the updating of netproto/802_11

Submitted-by: Andrew Atrens <atrens@nortel.com>
      Adrian Michael Nida <nida@musc.edu>

14 files changed:
sbin/ifconfig/Makefile
sbin/ifconfig/af_atalk.c [new file with mode: 0644]
sbin/ifconfig/af_inet.c [new file with mode: 0644]
sbin/ifconfig/af_inet6.c [new file with mode: 0644]
sbin/ifconfig/af_ipx.c [new file with mode: 0644]
sbin/ifconfig/af_link.c [new file with mode: 0644]
sbin/ifconfig/ifbridge.c [new file with mode: 0644]
sbin/ifconfig/ifclone.c [new file with mode: 0644]
sbin/ifconfig/ifconfig.c
sbin/ifconfig/ifconfig.h
sbin/ifconfig/ifieee80211.c
sbin/ifconfig/ifmedia.c
sbin/ifconfig/ifvlan.c
sys/net/if_media.h

index f3faff5..06e94cb 100644 (file)
@@ -1,33 +1,45 @@
 #      From: @(#)Makefile      8.1 (Berkeley) 6/5/93
-# $FreeBSD: src/sbin/ifconfig/Makefile,v 1.14.2.7 2002/02/15 03:58:37 luigi Exp $
-# $DragonFly: src/sbin/ifconfig/Makefile,v 1.3 2005/03/04 02:29:19 cpressey Exp $
+# $FreeBSD: src/sbin/ifconfig/Makefile,v 1.29 2005/06/05 03:32:51 thompsa Exp $
+# $DragonFly: src/sbin/ifconfig/Makefile,v 1.4 2006/04/02 03:33:59 sephe Exp $
 
 PROG=  ifconfig
-WARNS?=        6
-SRCS=  ifconfig.c
 
-#comment out to exclude SIOC[GS]IFMEDIA support
-SRCS+= ifmedia.c
-CFLAGS+=-DUSE_IF_MEDIA
-CFLAGS+=-DINET6
-
-#comment out to exclude SIOC[GS]ETVLAN support
-SRCS+= ifvlan.c
-CFLAGS+=-DUSE_VLANS
-
-#comment out to exclude SIOC[GS]IEEE80211 support
-SRCS+= ifieee80211.c
-CFLAGS+=-DUSE_IEEE80211
-
-MAN=   ifconfig.8
-
-.if defined(RELEASE_CRUNCH)
-CFLAGS+=-DNO_IPX
-.else
+SRCS=  ifconfig.c              # base support
+
+#
+# NB: The order here defines the order in which the constructors
+#     are called.  This in turn defines the default order in which
+#     status is displayed.  Probably should add a priority mechanism
+#     to the registration process so we don't depend on this aspect
+#     of the toolchain.
+#
+SRCS+= af_link.c               # LLC support
+SRCS+= af_inet.c               # IPv4 support
+SRCS+= af_inet6.c              # IPv6 support
+SRCS+= af_atalk.c              # AppleTalk support
+
+SRCS+= ifclone.c               # clone device support
+#SRCS+=        ifmac.c                 # MAC support
+SRCS+= ifmedia.c               # SIOC[GS]IFMEDIA support
+SRCS+= ifvlan.c                # SIOC[GS]ETVLAN support
+SRCS+= ifieee80211.c           # SIOC[GS]IEEE80211 support
+
+#SRCS+=        ifcarp.c                # SIOC[GS]VH support
+#SRCS+=        ifpfsync.c              # pfsync(4) support
+
+SRCS+= ifbridge.c              # bridge support
+
+.ifndef RELEASE_CRUNCH
+SRCS+= af_ipx.c                # IPX support
 DPADD= ${LIBIPX}
 LDADD= -lipx
+.else
+CFLAGS+= -DNO_IPX
 .endif
 
-CFLAGS+=-DNS -I..
+MAN=   ifconfig.8
+
+CFLAGS+= -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wnested-externs
+WARNS= 0
 
 .include <bsd.prog.mk>
diff --git a/sbin/ifconfig/af_atalk.c b/sbin/ifconfig/af_atalk.c
new file mode 100644 (file)
index 0000000..305c598
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/af_atalk.c,v 1.1 2004/12/08 19:18:07 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/af_atalk.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>         /* for RTX_IFA */
+
+#include <netatalk/at.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include "ifconfig.h"
+
+static struct netrange at_nr;          /* AppleTalk net range */
+static struct ifaliasreq at_addreq;
+
+/* XXX  FIXME -- should use strtoul for better parsing. */
+static void
+setatrange(const char *range, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+       u_int   first = 123, last = 123;
+
+       if (sscanf(range, "%u-%u", &first, &last) != 2
+           || first == 0 || first > 0xffff
+           || last == 0 || last > 0xffff || first > last)
+               errx(1, "%s: illegal net range: %u-%u", range, first, last);
+       at_nr.nr_firstnet = htons(first);
+       at_nr.nr_lastnet = htons(last);
+}
+
+static void
+setatphase(const char *phase, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+       if (!strcmp(phase, "1"))
+               at_nr.nr_phase = 1;
+       else if (!strcmp(phase, "2"))
+               at_nr.nr_phase = 2;
+       else
+               errx(1, "%s: illegal phase", phase);
+}
+
+static void
+at_status(int s __unused, const struct rt_addrinfo * info)
+{
+       struct sockaddr_at *sat, null_sat;
+       struct netrange *nr;
+
+       memset(&null_sat, 0, sizeof(null_sat));
+
+       sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
+       if (sat == NULL)
+               return;
+       nr = &sat->sat_range.r_netrange;
+       printf("\tatalk %d.%d range %d-%d phase %d",
+               ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
+               ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
+       if (flags & IFF_POINTOPOINT) {
+               /* note RTAX_BRD overlap with IFF_BROADCAST */
+               sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
+               if (!sat)
+                       sat = &null_sat;
+               printf("--> %d.%d",
+                       ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
+       }
+       if (flags & IFF_BROADCAST) {
+               /* note RTAX_BRD overlap with IFF_POINTOPOINT */
+               sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
+               if (sat)
+                       printf(" broadcast %d.%d",
+                               ntohs(sat->sat_addr.s_net),
+                               sat->sat_addr.s_node);
+       }
+
+       putchar('\n');
+}
+
+static void
+at_getaddr(const char *addr, int which)
+{
+       struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
+       u_int net, node;
+
+       sat->sat_family = AF_APPLETALK;
+       sat->sat_len = sizeof(*sat);
+       if (which == MASK)
+               errx(1, "AppleTalk does not use netmasks");
+       if (sscanf(addr, "%u.%u", &net, &node) != 2
+           || net > 0xffff || node > 0xfe)
+               errx(1, "%s: illegal address", addr);
+       sat->sat_addr.s_net = htons(net);
+       sat->sat_addr.s_node = node;
+}
+
+static void
+at_postproc(int s, const struct afswtch *afp)
+{
+       struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
+
+       if (at_nr.nr_phase == 0)
+               at_nr.nr_phase = 2;     /* Default phase 2 */
+       if (at_nr.nr_firstnet == 0)
+               at_nr.nr_firstnet =     /* Default range of one */
+               at_nr.nr_lastnet = sat->sat_addr.s_net;
+       printf("\tatalk %d.%d range %d-%d phase %d\n",
+               ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
+               ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet),
+               at_nr.nr_phase);
+       if ((u_short) ntohs(at_nr.nr_firstnet) >
+                       (u_short) ntohs(sat->sat_addr.s_net)
+                   || (u_short) ntohs(at_nr.nr_lastnet) <
+                       (u_short) ntohs(sat->sat_addr.s_net))
+               errx(1, "AppleTalk address is not in range");
+       sat->sat_range.r_netrange = at_nr;
+}
+
+static struct cmd atalk_cmds[] = {
+       DEF_CMD_ARG("range",    setatrange),
+       DEF_CMD_ARG("phase",    setatphase),
+};
+
+static struct afswtch af_atalk = {
+       .af_name        = "atalk",
+       .af_af          = AF_APPLETALK,
+       .af_status      = at_status,
+       .af_getaddr     = at_getaddr,
+       .af_postproc    = at_postproc,
+       .af_difaddr     = SIOCDIFADDR,
+       .af_aifaddr     = SIOCAIFADDR,
+       .af_ridreq      = &at_addreq,
+       .af_addreq      = &at_addreq,
+};
+
+static __constructor void
+atalk_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(atalk_cmds);  i++)
+               cmd_register(&atalk_cmds[i]);
+       af_register(&af_atalk);
+#undef N
+}
diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c
new file mode 100644 (file)
index 0000000..6e2823b
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/af_inet.c,v 1.2 2005/06/16 19:37:09 ume Exp $
+ * $DragonFly: src/sbin/ifconfig/af_inet.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>         /* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h>                /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq in_addreq;
+static struct ifreq in_ridreq;
+
+static void
+in_status(int s __unused, const struct rt_addrinfo * info)
+{
+       struct sockaddr_in *sin, null_sin;
+       
+       memset(&null_sin, 0, sizeof(null_sin));
+
+       sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
+       if (sin == NULL)
+               return;
+
+       printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+
+       if (flags & IFF_POINTOPOINT) {
+               /* note RTAX_BRD overlap with IFF_BROADCAST */
+               sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
+               if (!sin)
+                       sin = &null_sin;
+               printf("--> %s ", inet_ntoa(sin->sin_addr));
+       }
+
+       sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
+       if (!sin)
+               sin = &null_sin;
+       printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+
+       if (flags & IFF_BROADCAST) {
+               /* note RTAX_BRD overlap with IFF_POINTOPOINT */
+               sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
+               if (sin && sin->sin_addr.s_addr != 0)
+                       printf("broadcast %s", inet_ntoa(sin->sin_addr));
+       }
+       putchar('\n');
+}
+
+#define SIN(x) ((struct sockaddr_in *) &(x))
+static struct sockaddr_in *sintab[] = {
+       SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
+       SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
+};
+
+static void
+in_getaddr(const char *s, int which)
+{
+#define        MIN(a,b)        ((a)<(b)?(a):(b))
+       struct sockaddr_in *sin = sintab[which];
+       struct hostent *hp;
+       struct netent *np;
+
+       sin->sin_len = sizeof(*sin);
+       if (which != MASK)
+               sin->sin_family = AF_INET;
+
+       if (which == ADDR) {
+               char *p = NULL;
+
+               if((p = strrchr(s, '/')) != NULL) {
+                       /* address is `name/masklen' */
+                       int masklen;
+                       int ret;
+                       struct sockaddr_in *min = sintab[MASK];
+                       *p = '\0';
+                       ret = sscanf(p+1, "%u", &masklen);
+                       if(ret != 1 || (masklen < 0 || masklen > 32)) {
+                               *p = '/';
+                               errx(1, "%s: bad value", s);
+                       }
+                       min->sin_len = sizeof(*min);
+                       min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 
+                                             0xffffffff);
+               }
+       }
+
+       if (inet_aton(s, &sin->sin_addr))
+               return;
+       if ((hp = gethostbyname(s)) != 0)
+               bcopy(hp->h_addr, (char *)&sin->sin_addr, 
+                   MIN(hp->h_length, sizeof(sin->sin_addr)));
+       else if ((np = getnetbyname(s)) != 0)
+               sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
+       else
+               errx(1, "%s: bad value", s);
+#undef MIN
+}
+
+static void
+in_status_tunnel(int s)
+{
+       char src[NI_MAXHOST];
+       char dst[NI_MAXHOST];
+       struct ifreq ifr;
+       const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+       if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
+               return;
+       if (sa->sa_family != AF_INET)
+               return;
+       if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
+               src[0] = '\0';
+
+       if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
+               return;
+       if (sa->sa_family != AF_INET)
+               return;
+       if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
+               dst[0] = '\0';
+
+       printf("\ttunnel inet %s --> %s\n", src, dst);
+}
+
+static void
+in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+       struct ifaliasreq addreq;
+
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy(addreq.ifra_name, name, IFNAMSIZ);
+       memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+       memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
+
+       if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
+               warn("SIOCSIFPHYADDR");
+}
+
+static struct afswtch af_inet = {
+       .af_name        = "inet",
+       .af_af          = AF_INET,
+       .af_status      = in_status,
+       .af_getaddr     = in_getaddr,
+       .af_status_tunnel = in_status_tunnel,
+       .af_settunnel   = in_set_tunnel,
+       .af_difaddr     = SIOCDIFADDR,
+       .af_aifaddr     = SIOCAIFADDR,
+       .af_ridreq      = &in_ridreq,
+       .af_addreq      = &in_addreq,
+};
+
+static __constructor void
+inet_ctor(void)
+{
+       af_register(&af_inet);
+}
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
new file mode 100644 (file)
index 0000000..f550f3b
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/af_inet6.c,v 1.3 2005/06/16 19:37:09 ume Exp $
+ * $DragonFly: src/sbin/ifconfig/af_inet6.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>         /* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h>                /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <netinet6/nd6.h>      /* Define ND6_INFINITE_LIFETIME */
+
+#include "ifconfig.h"
+
+static struct in6_ifreq in6_ridreq;
+static struct in6_aliasreq in6_addreq = 
+  { { 0 }, 
+    { 0 }, 
+    { 0 }, 
+    { 0 }, 
+    0, 
+    { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
+static int ip6lifetime;
+
+static void in6_fillscopeid(struct sockaddr_in6 *sin6);
+static int prefix(void *, int);
+static char *sec2str(time_t);
+static int explicit_prefix = 0;
+
+static char addr_buf[MAXHOSTNAMELEN *2 + 1];   /*for getnameinfo()*/
+
+static void
+setifprefixlen(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+        if (afp->af_getprefix != NULL)
+                afp->af_getprefix(addr, MASK);
+       explicit_prefix = 1;
+}
+
+static void
+setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
+    const struct afswtch *afp)
+{
+       if (afp->af_af != AF_INET6)
+               err(1, "address flags can be set only for inet6 addresses");
+
+       if (flag < 0)
+               in6_addreq.ifra_flags &= ~(-flag);
+       else
+               in6_addreq.ifra_flags |= flag;
+}
+
+static void
+setip6lifetime(const char *cmd, const char *val, int s, 
+    const struct afswtch *afp)
+{
+       time_t newval, t;
+       char *ep;
+
+       t = time(NULL);
+       newval = (time_t)strtoul(val, &ep, 0);
+       if (val == ep)
+               errx(1, "invalid %s", cmd);
+       if (afp->af_af != AF_INET6)
+               errx(1, "%s not allowed for the AF", cmd);
+       if (strcmp(cmd, "vltime") == 0) {
+               in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
+               in6_addreq.ifra_lifetime.ia6t_vltime = newval;
+       } else if (strcmp(cmd, "pltime") == 0) {
+               in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
+               in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+       }
+}
+
+static void
+setip6pltime(const char *seconds, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+       setip6lifetime("pltime", seconds, s, afp);
+}
+
+static void
+setip6vltime(const char *seconds, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+       setip6lifetime("vltime", seconds, s, afp);
+}
+
+static void
+setip6eui64(const char *cmd, int dummy __unused, int s,
+    const struct afswtch *afp)
+{
+       struct ifaddrs *ifap, *ifa;
+       const struct sockaddr_in6 *sin6 = NULL;
+       const struct in6_addr *lladdr = NULL;
+       struct in6_addr *in6;
+
+       if (afp->af_af != AF_INET6)
+               errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
+       in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+       if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
+               errx(EXIT_FAILURE, "interface index is already filled");
+       if (getifaddrs(&ifap) != 0)
+               err(EXIT_FAILURE, "getifaddrs");
+       for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr->sa_family == AF_INET6 &&
+                   strcmp(ifa->ifa_name, name) == 0) {
+                       sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
+                       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+                               lladdr = &sin6->sin6_addr;
+                               break;
+                       }
+               }
+       }
+       if (!lladdr)
+               errx(EXIT_FAILURE, "could not determine link local address"); 
+
+       memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
+
+       freeifaddrs(ifap);
+}
+
+static void
+in6_fillscopeid(struct sockaddr_in6 *sin6)
+{
+#if defined(__KAME__) && defined(KAME_SCOPEID)
+       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+               sin6->sin6_scope_id =
+                       ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+               sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
+       }
+#endif
+}
+
+static void
+in6_status(int s __unused, const struct rt_addrinfo * info)
+{
+       struct sockaddr_in6 *sin, null_sin;
+       struct in6_ifreq ifr6;
+       int s6;
+       u_int32_t flags6;
+       struct in6_addrlifetime lifetime;
+       time_t t = time(NULL);
+       int error;
+       u_int32_t scopeid;
+
+       memset(&null_sin, 0, sizeof(null_sin));
+
+       sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+       if (sin == NULL)
+               return;
+
+       strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+       if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+               warn("socket(AF_INET6,SOCK_DGRAM)");
+               return;
+       }
+       ifr6.ifr_addr = *sin;
+       if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+               warn("ioctl(SIOCGIFAFLAG_IN6)");
+               close(s6);
+               return;
+       }
+       flags6 = ifr6.ifr_ifru.ifru_flags6;
+       memset(&lifetime, 0, sizeof(lifetime));
+       ifr6.ifr_addr = *sin;
+       if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
+               warn("ioctl(SIOCGIFALIFETIME_IN6)");
+               close(s6);
+               return;
+       }
+       lifetime = ifr6.ifr_ifru.ifru_lifetime;
+       close(s6);
+
+       /* XXX: embedded link local addr check */
+       if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+           *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+               u_short index;
+
+               index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+               *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+               if (sin->sin6_scope_id == 0)
+                       sin->sin6_scope_id = ntohs(index);
+       }
+       scopeid = sin->sin6_scope_id;
+
+       error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
+                           sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
+       if (error != 0)
+               inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+                         sizeof(addr_buf));
+       printf("\tinet6 %s ", addr_buf);
+
+       if (flags & IFF_POINTOPOINT) {
+               /* note RTAX_BRD overlap with IFF_BROADCAST */
+               sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+               /*
+                * some of the interfaces do not have valid destination
+                * address.
+                */
+               if (sin && sin->sin6_family == AF_INET6) {
+                       int error;
+
+                       /* XXX: embedded link local addr check */
+                       if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+                           *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+                               u_short index;
+
+                               index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+                               *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+                               if (sin->sin6_scope_id == 0)
+                                       sin->sin6_scope_id = ntohs(index);
+                       }
+
+                       error = getnameinfo((struct sockaddr *)sin,
+                                           sin->sin6_len, addr_buf,
+                                           sizeof(addr_buf), NULL, 0,
+                                           NI_NUMERICHOST);
+                       if (error != 0)
+                               inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+                                         sizeof(addr_buf));
+                       printf("--> %s ", addr_buf);
+               }
+       }
+
+       sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
+       if (!sin)
+               sin = &null_sin;
+       printf("prefixlen %d ", prefix(&sin->sin6_addr,
+               sizeof(struct in6_addr)));
+
+       if ((flags6 & IN6_IFF_ANYCAST) != 0)
+               printf("anycast ");
+       if ((flags6 & IN6_IFF_TENTATIVE) != 0)
+               printf("tentative ");
+       if ((flags6 & IN6_IFF_DUPLICATED) != 0)
+               printf("duplicated ");
+       if ((flags6 & IN6_IFF_DETACHED) != 0)
+               printf("detached ");
+       if ((flags6 & IN6_IFF_DEPRECATED) != 0)
+               printf("deprecated ");
+       if ((flags6 & IN6_IFF_AUTOCONF) != 0)
+               printf("autoconf ");
+       if ((flags6 & IN6_IFF_TEMPORARY) != 0)
+               printf("temporary ");
+
+        if (scopeid)
+               printf("scopeid 0x%x ", scopeid);
+
+       if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+               printf("pltime ");
+               if (lifetime.ia6t_preferred) {
+                       printf("%s ", lifetime.ia6t_preferred < t
+                               ? "0" : sec2str(lifetime.ia6t_preferred - t));
+               } else
+                       printf("infty ");
+
+               printf("vltime ");
+               if (lifetime.ia6t_expire) {
+                       printf("%s ", lifetime.ia6t_expire < t
+                               ? "0" : sec2str(lifetime.ia6t_expire - t));
+               } else
+                       printf("infty ");
+       }
+
+       putchar('\n');
+}
+
+#define        SIN6(x) ((struct sockaddr_in6 *) &(x))
+static struct  sockaddr_in6 *sin6tab[] = {
+       SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+       SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
+};
+
+static void
+in6_getprefix(const char *plen, int which)
+{
+       struct sockaddr_in6 *sin = sin6tab[which];
+       u_char *cp;
+       int len = atoi(plen);
+
+       if ((len < 0) || (len > 128))
+               errx(1, "%s: bad value", plen);
+       sin->sin6_len = sizeof(*sin);
+       if (which != MASK)
+               sin->sin6_family = AF_INET6;
+       if ((len == 0) || (len == 128)) {
+               memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
+               return;
+       }
+       memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
+       for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+               *cp++ = 0xff;
+       *cp = 0xff << (8 - len);
+}
+
+static void
+in6_getaddr(const char *s, int which)
+{
+       struct sockaddr_in6 *sin = sin6tab[which];
+       struct addrinfo hints, *res;
+       int error = -1;
+
+       newaddr &= 1;
+
+       sin->sin6_len = sizeof(*sin);
+       if (which != MASK)
+               sin->sin6_family = AF_INET6;
+
+       if (which == ADDR) {
+               char *p = NULL;
+               if((p = strrchr(s, '/')) != NULL) {
+                       *p = '\0';
+                       in6_getprefix(p + 1, MASK);
+                       explicit_prefix = 1;
+               }
+       }
+
+       if (sin->sin6_family == AF_INET6) {
+               bzero(&hints, sizeof(struct addrinfo));
+               hints.ai_family = AF_INET6;
+               error = getaddrinfo(s, NULL, &hints, &res);
+       }
+       if (error != 0) {
+               if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+                       errx(1, "%s: bad value", s);
+       } else
+               bcopy(res->ai_addr, sin, res->ai_addrlen);
+}
+
+static int
+prefix(void *val, int size)
+{
+        u_char *name = (u_char *)val;
+        int byte, bit, plen = 0;
+
+        for (byte = 0; byte < size; byte++, plen += 8)
+                if (name[byte] != 0xff)
+                        break;
+       if (byte == size)
+               return (plen);
+       for (bit = 7; bit != 0; bit--, plen++)
+                if (!(name[byte] & (1 << bit)))
+                        break;
+        for (; bit != 0; bit--)
+                if (name[byte] & (1 << bit))
+                        return(0);
+        byte++;
+        for (; byte < size; byte++)
+                if (name[byte])
+                        return(0);
+        return (plen);
+}
+
+static char *
+sec2str(time_t total)
+{
+       static char result[256];
+       int days, hours, mins, secs;
+       int first = 1;
+       char *p = result;
+
+       if (0) {
+               days = total / 3600 / 24;
+               hours = (total / 3600) % 24;
+               mins = (total / 60) % 60;
+               secs = total % 60;
+
+               if (days) {
+                       first = 0;
+                       p += sprintf(p, "%dd", days);
+               }
+               if (!first || hours) {
+                       first = 0;
+                       p += sprintf(p, "%dh", hours);
+               }
+               if (!first || mins) {
+                       first = 0;
+                       p += sprintf(p, "%dm", mins);
+               }
+               sprintf(p, "%ds", secs);
+       } else
+               sprintf(result, "%lu", (unsigned long)total);
+
+       return(result);
+}
+
+static void
+in6_postproc(int s, const struct afswtch *afp)
+{
+       if (explicit_prefix == 0) {
+               /* Aggregatable address architecture defines all prefixes
+                  are 64. So, it is convenient to set prefixlen to 64 if
+                  it is not specified. */
+               setifprefixlen("64", 0, s, afp);
+               /* in6_getprefix("64", MASK) if MASK is available here... */
+       }
+}
+
+static void
+in6_status_tunnel(int s)
+{
+       char src[NI_MAXHOST];
+       char dst[NI_MAXHOST];
+       struct in6_ifreq in6_ifr;
+       const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
+
+       memset(&in6_ifr, 0, sizeof(in6_ifr));
+       strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
+
+       if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
+               return;
+       if (sa->sa_family != AF_INET6)
+               return;
+       in6_fillscopeid(&in6_ifr.ifr_addr);
+       if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
+           NI_NUMERICHOST) != 0)
+               src[0] = '\0';
+
+       if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
+               return;
+       if (sa->sa_family != AF_INET6)
+               return;
+       in6_fillscopeid(&in6_ifr.ifr_addr);
+       if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
+           NI_NUMERICHOST) != 0)
+               dst[0] = '\0';
+
+       printf("\ttunnel inet6 %s --> %s\n", src, dst);
+}
+
+static void
+in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+       struct in6_aliasreq in6_addreq; 
+
+       memset(&in6_addreq, 0, sizeof(in6_addreq));
+       strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
+       memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+       memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
+           dstres->ai_addr->sa_len);
+
+       if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
+               warn("SIOCSIFPHYADDR_IN6");
+}
+
+static struct cmd inet6_cmds[] = {
+       DEF_CMD_ARG("prefixlen",                        setifprefixlen),
+       DEF_CMD("anycast",      IN6_IFF_ANYCAST,        setip6flags),
+       DEF_CMD("tentative",    IN6_IFF_TENTATIVE,      setip6flags),
+       DEF_CMD("-tentative",   -IN6_IFF_TENTATIVE,     setip6flags),
+       DEF_CMD("deprecated",   IN6_IFF_DEPRECATED,     setip6flags),
+       DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED,     setip6flags),
+       DEF_CMD("autoconf",     IN6_IFF_AUTOCONF,       setip6flags),
+       DEF_CMD("-autoconf",    -IN6_IFF_AUTOCONF,      setip6flags),
+       DEF_CMD_ARG("pltime",                           setip6pltime),
+       DEF_CMD_ARG("vltime",                           setip6vltime),
+       DEF_CMD("eui64",        0,                      setip6eui64),
+};
+
+static struct afswtch af_inet6 = {
+       .af_name        = "inet6",
+       .af_af          = AF_INET6,
+       .af_status      = in6_status,
+       .af_getaddr     = in6_getaddr,
+       .af_getprefix   = in6_getprefix,
+       .af_postproc    = in6_postproc,
+       .af_status_tunnel = in6_status_tunnel,
+       .af_settunnel   = in6_set_tunnel,
+       .af_difaddr     = SIOCDIFADDR_IN6,
+       .af_aifaddr     = SIOCAIFADDR_IN6,
+       .af_ridreq      = &in6_addreq,
+       .af_addreq      = &in6_addreq,
+};
+
+static void
+in6_Lopt_cb(const char *optarg __unused)
+{
+       ip6lifetime++;  /* print IPv6 address lifetime */
+}
+static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
+
+static __constructor void
+inet6_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(inet6_cmds);  i++)
+               cmd_register(&inet6_cmds[i]);
+       af_register(&af_inet6);
+       opt_register(&in6_Lopt);
+#undef N
+}
diff --git a/sbin/ifconfig/af_ipx.c b/sbin/ifconfig/af_ipx.c
new file mode 100644 (file)
index 0000000..94906af
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/af_ipx.c,v 1.1 2004/12/08 19:18:07 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/af_ipx.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if_var.h>
+#define        IPXIP
+#define IPTUNNEL
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq ipx_addreq;
+static struct ifreq ipx_ridreq;
+
+static void
+ipx_status(int s __unused, const struct rt_addrinfo * info)
+{
+       struct sockaddr_ipx *sipx, null_sipx;
+
+       sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
+       if (sipx == NULL)
+               return;
+
+       printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
+
+       if (flags & IFF_POINTOPOINT) {
+               sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
+               if (!sipx) {
+                       memset(&null_sipx, 0, sizeof(null_sipx));
+                       sipx = &null_sipx;
+               }
+               printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
+       }
+       putchar('\n');
+}
+
+#define SIPX(x) ((struct sockaddr_ipx *) &(x))
+struct sockaddr_ipx *sipxtab[] = {
+       SIPX(ipx_ridreq.ifr_addr), SIPX(ipx_addreq.ifra_addr),
+       SIPX(ipx_addreq.ifra_mask), SIPX(ipx_addreq.ifra_broadaddr)
+};
+
+static void
+ipx_getaddr(const char *addr, int which)
+{
+       struct sockaddr_ipx *sipx = sipxtab[which];
+
+       sipx->sipx_family = AF_IPX;
+       sipx->sipx_len = sizeof(*sipx);
+       sipx->sipx_addr = ipx_addr(addr);
+       if (which == MASK)
+               printf("Attempt to set IPX netmask will be ineffectual\n");
+}
+
+static void
+ipx_postproc(int s, const struct afswtch *afp)
+{
+       if (setipdst) {
+               struct ipxip_req rq;
+               int size = sizeof(rq);
+
+               rq.rq_ipx = ipx_addreq.ifra_addr;
+               rq.rq_ip = ipx_addreq.ifra_dstaddr;
+
+               if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
+                       Perror("Encapsulation Routing");
+       }
+}
+
+static struct afswtch af_ipx = {
+       .af_name        = "ipx",
+       .af_af          = AF_IPX,
+       .af_status      = ipx_status,
+       .af_getaddr     = ipx_getaddr,
+       .af_postproc    = ipx_postproc,
+       .af_difaddr     = SIOCDIFADDR,
+       .af_aifaddr     = SIOCAIFADDR,
+       .af_ridreq      = &ipx_ridreq,
+       .af_addreq      = &ipx_addreq,
+};
+
+static __constructor void
+ipx_ctor(void)
+{
+       af_register(&af_ipx);
+}
diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c
new file mode 100644 (file)
index 0000000..939897c
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/af_link.c,v 1.2 2004/12/31 19:46:27 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/af_link.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>         /* for RTX_IFA */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include "ifconfig.h"
+
+static struct ifreq link_ridreq;
+
+static void
+link_status(int s __unused, const struct rt_addrinfo *info)
+{
+       const struct sockaddr_dl *sdl =
+               (const struct sockaddr_dl *) info->rti_info[RTAX_IFA];
+
+       if (sdl != NULL && sdl->sdl_alen > 0) {
+               if (sdl->sdl_type == IFT_ETHER &&
+                   sdl->sdl_alen == ETHER_ADDR_LEN)
+                       printf("\tether %s\n",
+                           ether_ntoa((const struct ether_addr *)LLADDR(sdl)));
+               else {
+                       int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+                       printf("\tlladdr %s\n", link_ntoa(sdl) + n);
+               }
+       }
+}
+
+static void
+link_getaddr(const char *addr, int which)
+{
+       char *temp;
+       struct sockaddr_dl sdl;
+       struct sockaddr *sa = &link_ridreq.ifr_addr;
+
+       if (which != ADDR)
+               errx(1, "can't set link-level netmask or broadcast");
+       if ((temp = malloc(strlen(addr) + 1)) == NULL)
+               errx(1, "malloc failed");
+       temp[0] = ':';
+       strcpy(temp + 1, addr);
+       sdl.sdl_len = sizeof(sdl);
+       link_addr(temp, &sdl);
+       free(temp);
+       if (sdl.sdl_alen > sizeof(sa->sa_data))
+               errx(1, "malformed link-level address");
+       sa->sa_family = AF_LINK;
+       sa->sa_len = sdl.sdl_alen;
+       bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
+}
+
+static struct afswtch af_link = {
+       .af_name        = "link",
+       .af_af          = AF_LINK,
+       .af_status      = link_status,
+       .af_getaddr     = link_getaddr,
+       .af_aifaddr     = SIOCSIFLLADDR,
+       .af_addreq      = &link_ridreq,
+};
+static struct afswtch af_ether = {
+       .af_name        = "ether",
+       .af_af          = AF_LINK,
+       .af_status      = link_status,
+       .af_getaddr     = link_getaddr,
+       .af_aifaddr     = SIOCSIFLLADDR,
+       .af_addreq      = &link_ridreq,
+};
+static struct afswtch af_lladdr = {
+       .af_name        = "lladdr",
+       .af_af          = AF_LINK,
+       .af_status      = link_status,
+       .af_getaddr     = link_getaddr,
+       .af_aifaddr     = SIOCSIFLLADDR,
+       .af_addreq      = &link_ridreq,
+};
+
+static __constructor void
+link_ctor(void)
+{
+       af_register(&af_link);
+       af_register(&af_ether);
+       af_register(&af_lladdr);
+}
diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c
new file mode 100644 (file)
index 0000000..3dc2180
--- /dev/null
@@ -0,0 +1,566 @@
+/*-
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed for the NetBSD Project by
+ *     Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/ifbridge.c,v 1.1.2.2 2005/12/28 04:12:58 thompsa Exp $
+ * $DragonFly: src/sbin/ifconfig/ifbridge.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/bridge/if_bridgevar.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static int
+get_val(const char *cp, u_long *valp)
+{
+       char *endptr;
+       u_long val;
+
+       errno = 0;
+       val = strtoul(cp, &endptr, 0);
+       if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
+               return (-1);
+
+       *valp = val;
+       return (0);
+}
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+       struct ifdrv ifd;
+
+       memset(&ifd, 0, sizeof(ifd));
+
+       strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+       ifd.ifd_cmd = op;
+       ifd.ifd_len = argsize;
+       ifd.ifd_data = arg;
+
+       return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static void
+do_bridgeflag(int sock, const char *ifs, int flag, int set)
+{
+       struct ifbreq req;
+
+       strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
+
+       if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
+               err(1, "unable to get bridge flags");
+
+       if (set)
+               req.ifbr_ifsflags |= flag;
+       else
+               req.ifbr_ifsflags &= ~flag;
+
+       if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
+               err(1, "unable to set bridge flags");
+}
+
+static void
+bridge_interfaces(int s, const char *prefix)
+{
+       static const char *stpstates[] = {
+               "disabled",
+               "listening",
+               "learning",
+               "forwarding",
+               "blocking",
+       };
+       struct ifbifconf bifc;
+       struct ifbreq *req;
+       char *inbuf = NULL, *ninbuf;
+       char *p, *pad;
+       int i, len = 8192;
+
+       pad = strdup(prefix);
+       if (pad == NULL)
+               err(1, "strdup");
+       /* replace the prefix with whitespace */
+       for (p = pad; *p != '\0'; p++) {
+               if(isprint(*p))
+                       *p = ' ';
+       }
+
+       for (;;) {
+               ninbuf = realloc(inbuf, len);
+               if (ninbuf == NULL)
+                       err(1, "unable to allocate interface buffer");
+               bifc.ifbic_len = len;
+               bifc.ifbic_buf = inbuf = ninbuf;
+               if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
+                       err(1, "unable to get interface list");
+               if ((bifc.ifbic_len + sizeof(*req)) < len)
+                       break;
+               len *= 2;
+       }
+
+       for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
+               req = bifc.ifbic_req + i;
+               printf("%s%s ", prefix, req->ifbr_ifsname);
+               printb("flags", req->ifbr_ifsflags, IFBIFBITS);
+               printf("\n");
+               
+               if (req->ifbr_ifsflags & IFBIF_STP) {
+                       printf("%s", pad);
+                       printf("port %u priority %u",
+                           req->ifbr_portno, req->ifbr_priority);
+                       printf(" path cost %u", req->ifbr_path_cost);
+                       if (req->ifbr_state <
+                           sizeof(stpstates) / sizeof(stpstates[0]))
+                               printf(" %s", stpstates[req->ifbr_state]);
+                       else
+                               printf(" <unknown state %d>",
+                                   req->ifbr_state);
+                       printf("\n");
+               }
+       }
+
+       free(inbuf);
+}
+
+static void
+bridge_addresses(int s, const char *prefix)
+{
+       struct ifbaconf ifbac;
+       struct ifbareq *ifba;
+       char *inbuf = NULL, *ninbuf;
+       int i, len = 8192;
+       struct ether_addr ea;
+
+       for (;;) {
+               ninbuf = realloc(inbuf, len);
+               if (ninbuf == NULL)
+                       err(1, "unable to allocate address buffer");
+               ifbac.ifbac_len = len;
+               ifbac.ifbac_buf = inbuf = ninbuf;
+               if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
+                       err(1, "unable to get address cache");
+               if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
+                       break;
+               len *= 2;
+       }
+
+       for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
+               ifba = ifbac.ifbac_req + i;
+               memcpy(ea.octet, ifba->ifba_dst,
+                   sizeof(ea.octet));
+               printf("%s%s %s %lu ", prefix, ether_ntoa(&ea),
+                   ifba->ifba_ifsname, ifba->ifba_expire);
+               printb("flags", ifba->ifba_flags, IFBAFBITS);
+               printf("\n");
+       }
+
+       free(inbuf);
+}
+
+static void
+bridge_status(int s)
+{
+       struct ifbrparam param;
+       u_int16_t pri;
+       u_int8_t ht, fd, ma;
+
+       if (do_cmd(s, BRDGGPRI, &param, sizeof(param), 0) < 0)
+               return;
+       pri = param.ifbrp_prio;
+
+       if (do_cmd(s, BRDGGHT, &param, sizeof(param), 0) < 0)
+               return;
+       ht = param.ifbrp_hellotime;
+
+       if (do_cmd(s, BRDGGFD, &param, sizeof(param), 0) < 0)
+               return;
+       fd = param.ifbrp_fwddelay;
+
+       if (do_cmd(s, BRDGGMA, &param, sizeof(param), 0) < 0)
+               return;
+       ma = param.ifbrp_maxage;
+
+       printf("\tpriority %u hellotime %u fwddelay %u maxage %u\n",
+           pri, ht, fd, ma);
+
+       bridge_interfaces(s, "\tmember: ");
+
+       return;
+
+}
+
+static void
+setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbreq req;
+
+       memset(&req, 0, sizeof(req));
+       strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+       if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGADD %s",  val);
+}
+
+static void
+setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbreq req;
+
+       memset(&req, 0, sizeof(req));
+       strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+       if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGDEL %s",  val);
+}
+
+static void
+setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+       do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
+}
+
+static void
+unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+       do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
+}
+
+static void
+setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+       do_bridgeflag(s, val, IFBIF_LEARNING,  1);
+}
+
+static void
+unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+       do_bridgeflag(s, val, IFBIF_LEARNING,  0);
+}
+
+#ifdef notyet
+static void
+setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbreq req;
+
+       memset(&req, 0, sizeof(req));
+       strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+       if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGADDS %s",  val);
+}
+
+static void
+unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbreq req;
+
+       memset(&req, 0, sizeof(req));
+       strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+       if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGDELS %s",  val);
+}
+#endif
+
+static void
+setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+       do_bridgeflag(s, val, IFBIF_STP, 1);
+}
+
+static void
+unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+       do_bridgeflag(s, val, IFBIF_STP, 0);
+}
+
+static void
+setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbreq req;
+
+       memset(&req, 0, sizeof(req));
+       req.ifbr_ifsflags = IFBF_FLUSHDYN;
+       if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbreq req;
+
+       memset(&req, 0, sizeof(req));
+       req.ifbr_ifsflags = IFBF_FLUSHALL;
+       if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_static(const char *val, const char *mac, int s,
+    const struct afswtch *afp)
+{
+       struct ifbareq req;
+       struct ether_addr *ea;
+
+       memset(&req, 0, sizeof(req));
+       strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
+
+       ea = ether_aton(mac);
+       if (ea == NULL)
+               errx(1, "%s: invalid address: %s", val, mac);
+
+       memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+       req.ifba_flags = IFBAF_STATIC;
+
+       if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGSADDR %s",  val);
+}
+
+static void
+setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifbareq req;
+       struct ether_addr *ea;
+
+       memset(&req, 0, sizeof(req));
+
+       ea = ether_aton(val);
+       if (ea == NULL)
+               errx(1, "invalid address: %s",  val);
+
+       memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+
+       if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGDADDR %s",  val);
+}
+
+static void
+getbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
+{
+       bridge_addresses(s, "");
+}
+
+static void
+setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
+{
+       struct ifbrparam param;
+       u_long val;
+
+       if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+               errx(1, "invalid value: %s",  arg);
+
+       param.ifbrp_csize = val & 0xffffffff;
+
+       if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
+               err(1, "BRDGSCACHE %s",  arg);
+}
+
+static void
+setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
+{
+       struct ifbrparam param;
+       u_long val;
+
+       if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+               errx(1, "invalid value: %s",  arg);
+
+       param.ifbrp_hellotime = val & 0xff;
+
+       if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
+               err(1, "BRDGSHT %s",  arg);
+}
+
+static void
+setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
+{
+       struct ifbrparam param;
+       u_long val;
+
+       if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+               errx(1, "invalid value: %s",  arg);
+
+       param.ifbrp_fwddelay = val & 0xff;
+
+       if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
+               err(1, "BRDGSFD %s",  arg);
+}
+
+static void
+setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
+{
+       struct ifbrparam param;
+       u_long val;
+
+       if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+               errx(1, "invalid value: %s",  arg);
+
+       param.ifbrp_maxage = val & 0xff;
+
+       if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
+               err(1, "BRDGSMA %s",  arg);
+}
+
+static void
+setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
+{
+       struct ifbrparam param;
+       u_long val;
+
+       if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
+               errx(1, "invalid value: %s",  arg);
+
+       param.ifbrp_prio = val & 0xffff;
+
+       if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
+               err(1, "BRDGSPRI %s",  arg);
+}
+
+static void
+setbridge_ifpriority(const char *ifn, const char *pri, int s,
+    const struct afswtch *afp)
+{
+       struct ifbreq req;
+       u_long val;
+
+       memset(&req, 0, sizeof(req));
+
+       if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
+               errx(1, "invalid value: %s",  pri);
+
+       strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+       req.ifbr_priority = val & 0xff;
+
+       if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGSIFPRIO %s",  pri);
+}
+
+static void
+setbridge_ifpathcost(const char *ifn, const char *cost, int s,
+    const struct afswtch *afp)
+{
+       struct ifbreq req;
+       u_long val;
+
+       memset(&req, 0, sizeof(req));
+
+       if (get_val(cost, &val) < 0 || (val & ~0xff) != 0)
+               errx(1, "invalid value: %s",  cost);
+
+       strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+       req.ifbr_path_cost = val & 0xffff;
+
+       if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
+               err(1, "BRDGSIFCOST %s",  cost);
+}
+
+static void
+setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
+{
+       struct ifbrparam param;
+       u_long val;
+
+       if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+               errx(1, "invalid value: %s",  arg);
+
+       param.ifbrp_ctime = val & 0xffffffff;
+
+       if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
+               err(1, "BRDGSTO %s",  arg);
+}
+
+static struct cmd bridge_cmds[] = {
+       DEF_CMD_ARG("addm",             setbridge_add),
+       DEF_CMD_ARG("deletem",          setbridge_delete),
+       DEF_CMD_ARG("discover",         setbridge_discover),
+       DEF_CMD_ARG("-discover",        unsetbridge_discover),
+       DEF_CMD_ARG("learn",            setbridge_learn),
+       DEF_CMD_ARG("-learn",           unsetbridge_learn),
+#ifdef notyet
+       DEF_CMD_ARG("span",             setbridge_span),
+       DEF_CMD_ARG("-span",            unsetbridge_span),
+#endif
+       DEF_CMD_ARG("stp",              setbridge_stp),
+       DEF_CMD_ARG("-stp",             unsetbridge_stp),
+       DEF_CMD("flush", 0,             setbridge_flush),
+       DEF_CMD("flushall", 0,          setbridge_flushall),
+       DEF_CMD_ARG2("static",          setbridge_static),
+       DEF_CMD_ARG("deladdr",          setbridge_deladdr),
+       DEF_CMD("addr",  1,             getbridge_addr),
+       DEF_CMD_ARG("maxaddr",          setbridge_maxaddr),
+       DEF_CMD_ARG("hellotime",        setbridge_hellotime),
+       DEF_CMD_ARG("fwddelay",         setbridge_fwddelay),
+       DEF_CMD_ARG("maxage",           setbridge_maxage),
+       DEF_CMD_ARG("priority",         setbridge_priority),
+       DEF_CMD_ARG2("ifpriority",      setbridge_ifpriority),
+       DEF_CMD_ARG2("ifpathcost",      setbridge_ifpathcost),
+       DEF_CMD_ARG("timeout",          setbridge_timeout),
+};
+static struct afswtch af_bridge = {
+       .af_name        = "af_bridge",
+       .af_af          = AF_UNSPEC,
+       .af_other_status = bridge_status,
+};
+
+static __constructor void
+bridge_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(bridge_cmds);  i++)
+               cmd_register(&bridge_cmds[i]);
+       af_register(&af_bridge);
+#undef N
+}
diff --git a/sbin/ifconfig/ifclone.c b/sbin/ifconfig/ifclone.c
new file mode 100644 (file)
index 0000000..76ae3a7
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sbin/ifconfig/ifclone.c,v 1.1 2004/12/08 19:18:07 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/ifclone.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void
+list_cloners(void)
+{
+       struct if_clonereq ifcr;
+       char *cp, *buf;
+       int idx;
+       int s;
+
+       s = socket(AF_INET, SOCK_DGRAM, 0);
+       if (s == -1)
+               err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+       memset(&ifcr, 0, sizeof(ifcr));
+
+       if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+               err(1, "SIOCIFGCLONERS for count");
+
+       buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
+       if (buf == NULL)
+               err(1, "unable to allocate cloner name buffer");
+
+       ifcr.ifcr_count = ifcr.ifcr_total;
+       ifcr.ifcr_buffer = buf;
+
+       if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+               err(1, "SIOCIFGCLONERS for names");
+
+       /*
+        * In case some disappeared in the mean time, clamp it down.
+        */
+       if (ifcr.ifcr_count > ifcr.ifcr_total)
+               ifcr.ifcr_count = ifcr.ifcr_total;
+
+       for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
+               if (idx > 0)
+                       putchar(' ');
+               printf("%s", cp);
+       }
+
+       putchar('\n');
+       free(buf);
+}
+
+void
+clone_create(void)
+{
+       int s;
+
+       s = socket(AF_INET, SOCK_DGRAM, 0);
+       if (s == -1)
+               err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+       memset(&ifr, 0, sizeof(ifr));
+       (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
+               err(1, "SIOCIFCREATE");
+
+       /*
+        * If we get a different name back then we put in, we probably
+        * want to print it out, but we might change our mind later so
+        * we just signal our interest and leave the printout for later.
+        */
+       if (strcmp(name, ifr.ifr_name) != 0) {
+               printname = 1;
+               strlcpy(name, ifr.ifr_name, sizeof(name));
+       }
+
+       close(s);
+}
+
+static void
+clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+       (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+               err(1, "SIOCIFDESTROY");
+       /*
+        * If we create and destroy an interface in the same command,
+        * there isn't any reason to print it's name.
+        */
+       printname = 0;
+}
+
+static struct cmd clone_cmds[] = {
+       DEF_CMD("destroy",      0,      clone_destroy),
+       DEF_CMD("unplumb",      0,      clone_destroy),
+};
+
+static void
+clone_Copt_cb(const char *optarg __unused)
+{
+       list_cloners();
+       exit(0);
+}
+static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+
+static __constructor void
+clone_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(clone_cmds);  i++)
+               cmd_register(&clone_cmds[i]);
+       opt_register(&clone_Copt);
+#undef N
+}
index 2e4beff..2de7409 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#) Copyright (c) 1983, 1993 The Regents of the University of California.  All rights reserved.
- * @(#)ifconfig.c      8.2 (Berkeley) 2/16/94
- * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.96 2004/02/27 06:43:14 kan Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.25 2005/11/06 12:21:42 swildner Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.113.2.4 2006/02/09 10:48:43 yar Exp $
+ * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.26 2006/04/02 03:33:59 sephe Exp $
  */
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
-#include <sys/sockio.h>
 #include <sys/sysctl.h>
 #include <sys/time.h>
 #include <sys/module.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 
-#ifdef INET6
-#include <netinet6/nd6.h>      /* Define ND6_INFINITE_LIFETIME */
-#endif
-
-#ifndef NO_IPX
-/* IPX */
-#define        IPXIP
-#define IPTUNNEL
-#include <netipx/ipx.h>
-#include <netipx/ipx_if.h>
-#endif
-
-/* Appletalk */
-#include <netatalk/at.h>
-
-/* XNS */
-#ifdef NS
-#define        NSIP
-#include <netns/ns.h>
-#include <netns/ns_if.h>
-#endif
-
-/* OSI */
-
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <ifaddrs.h>
 
 #include "ifconfig.h"
 
-/* wrapper for KAME-special getnameinfo() */
-#ifndef NI_WITHSCOPEID
-#define        NI_WITHSCOPEID  0
-#endif
+/*
+ * This macro returns the size of a struct sockaddr when passed
+ * through a routing socket. Basically we round up sa_len to
+ * a multiple of sizeof(long), with a minimum of sizeof(long).
+ * The check for a NULL pointer is just a convenience, probably never used.
+ * The case sa_len == 0 should only apply to empty structures.
+ */     
+#define SA_SIZE(sa)                                             \
+    (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
+       sizeof(long)            :                               \
+       1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
 
 /*
  * Since "struct ifreq" is composed of various union members, callers
  * should pay special attention to interprete the value.
  * (.e.g. little/big endian difference in the structure.)
  */
-struct ifreq           ifr, ridreq;
-struct ifaliasreq      addreq;
-#ifdef INET6
-struct in6_ifreq       in6_ridreq;
-struct in6_aliasreq    in6_addreq = 
-  { { 0 }, 
-    { 0, 0, 0, 0, { { { 0 } } }, 0 }, 
-    { 0, 0, 0, 0, { { { 0 } } }, 0 }, 
-    { 0, 0, 0, 0, { { { 0 } } }, 0 }, 
-    0, 
-    { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
-#endif
-struct sockaddr_in     netmask;
-struct netrange        at_nr;          /* AppleTalk net range */
+struct ifreq ifr;
 
 char   name[IFNAMSIZ];
 int    flags;
@@ -123,326 +89,79 @@ int       setmask;
 int    doalias;
 int    clearaddr;
 int    newaddr = 1;
-#ifdef INET6
-static int ip6lifetime;
-#endif
-
-struct afswtch;
+int    verbose;
 
-int supmedia = 0;
-int listcloners = 0;
-int printname = 0;             /* Print the name of the created interface. */
+int    supmedia = 0;
+int    printkeys = 0;          /* Print keying material for interfaces. */
+int    printname = 0;          /* Print the name of the created interface. */
 
-#ifdef INET6
-char   addr_buf[MAXHOSTNAMELEN *2 + 1];        /*for getnameinfo()*/
-#endif
-
-void   Perror(const char *cmd);
-void   checkatrange(struct sockaddr_at *);
-int    ifconfig(int argc, char *const *argv, const struct afswtch *afp);
-void   notealias(const char *, int, int, const struct afswtch *afp);
-void   list_cloners(void);
-void   printb(const char *s, unsigned value, const char *bits);
-void   rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
-void   status(const struct afswtch *afp, int addrcount,
+static int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
+static void status(const struct afswtch *afp, int addrcount,
                    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
                    struct ifa_msghdr *ifam);
-void   tunnel_status(int s);
-void   usage(void);
-void   ifmaybeload(char *if_nm);
-
-#ifdef INET6
-void   in6_fillscopeid(struct sockaddr_in6 *sin6);
-int    prefix(void *, int);
-static char *sec2str(time_t);
-int    explicit_prefix = 0;
-#endif
+static void tunnel_status(int s);
+static void usage(void);
 
-typedef        void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
-typedef        void c_func2(const char *arg, const char *arg2, int s, const struct afswtch *afp);
-c_func setatphase, setatrange;
-c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
-c_func2        settunnel;
-c_func deletetunnel;
-#ifdef INET6
-c_func setifprefixlen;
-c_func setip6flags;
-c_func  setip6pltime;
-c_func  setip6vltime;
-c_func2        setip6lifetime;
-c_func setip6eui64;
-#endif
-c_func setifipdst;
-c_func setifflags, setifmetric, setifmtu, setifcap;
-c_func clone_destroy;
-c_func setifname;
-
-
-void clone_create(void);
-
-
-#define        NEXTARG         0xffffff
-#define        NEXTARG2        0xfffffe
-
-const
-struct cmd {
-       const   char *c_name;
-       int     c_parameter;            /* NEXTARG means next argv */
-       void    (*c_func)(const char *, int, int, const struct afswtch *afp);
-       void    (*c_func2)(const char *, const char *, int, const struct afswtch *afp);
-} cmds[] = {
-       { "up",         IFF_UP,         setifflags,     NULL },
-       { "down",       -IFF_UP,        setifflags,     NULL },
-       { "polling",    IFF_POLLING,    setifflags,     NULL },
-       { "-polling",   -IFF_POLLING,   setifflags,     NULL },
-       { "arp",        -IFF_NOARP,     setifflags,     NULL },
-       { "-arp",       IFF_NOARP,      setifflags,     NULL },
-       { "debug",      IFF_DEBUG,      setifflags,     NULL },
-       { "-debug",     -IFF_DEBUG,     setifflags,     NULL },
-       { "promisc",    IFF_PPROMISC,   setifflags,     NULL },
-       { "-promisc",   -IFF_PPROMISC,  setifflags,     NULL },
-       { "add",        IFF_UP,         notealias,      NULL },
-       { "alias",      IFF_UP,         notealias,      NULL },
-       { "-alias",     -IFF_UP,        notealias,      NULL },
-       { "delete",     -IFF_UP,        notealias,      NULL },
-       { "remove",     -IFF_UP,        notealias,      NULL },
-#ifdef notdef
-#define        EN_SWABIPS      0x1000
-       { "swabips",    EN_SWABIPS,     setifflags,     NULL },
-       { "-swabips",   -EN_SWABIPS,    setifflags,     NULL },
-#endif
-       { "netmask",    NEXTARG,        setifnetmask,   NULL },
-#ifdef INET6
-       { "prefixlen",  NEXTARG,        setifprefixlen, NULL },
-       { "anycast",    IN6_IFF_ANYCAST, setip6flags,   NULL },
-       { "tentative",  IN6_IFF_TENTATIVE, setip6flags, NULL },
-       { "-tentative", -IN6_IFF_TENTATIVE, setip6flags, NULL },
-       { "deprecated", IN6_IFF_DEPRECATED, setip6flags, NULL },
-       { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags, NULL },
-       { "autoconf",   IN6_IFF_AUTOCONF, setip6flags,  NULL },
-       { "-autoconf",  -IN6_IFF_AUTOCONF, setip6flags, NULL },
-       { "pltime",     NEXTARG,        setip6pltime,   NULL },
-       { "vltime",     NEXTARG,        setip6vltime,   NULL },
-       { "eui64",      0,              setip6eui64,    NULL },
-#endif
-       { "range",      NEXTARG,        setatrange,     NULL },
-       { "phase",      NEXTARG,        setatphase,     NULL },
-       { "metric",     NEXTARG,        setifmetric,    NULL },
-       { "broadcast",  NEXTARG,        setifbroadaddr, NULL },
-       { "ipdst",      NEXTARG,        setifipdst,     NULL },
-       { "tunnel",     NEXTARG2,       NULL,           settunnel },
-       { "deletetunnel", 0,            deletetunnel,   NULL },
-       { "link0",      IFF_LINK0,      setifflags,     NULL },
-       { "-link0",     -IFF_LINK0,     setifflags,     NULL },
-       { "link1",      IFF_LINK1,      setifflags,     NULL },
-       { "-link1",     -IFF_LINK1,     setifflags,     NULL },
-       { "link2",      IFF_LINK2,      setifflags,     NULL },
-       { "-link2",     -IFF_LINK2,     setifflags,     NULL },
-#if notyet
-       { "monitor",    IFF_MONITOR,    setifflags,     NULL },
-       { "-monitor",   -IFF_MONITOR,   setifflags,     NULL },
-       { "staticarp",  IFF_STATICARP,  setifflags,     NULL },
-       { "-staticarp", -IFF_STATICARP, setifflags,     NULL },
-#endif
+static struct afswtch *af_getbyname(const char *name);
+static struct afswtch *af_getbyfamily(int af);
+static void af_other_status(int);
 
-#ifdef USE_IF_MEDIA
-       { "media",      NEXTARG,        setmedia,       NULL },
-       { "mode",       NEXTARG,        setmediamode,   NULL },
-       { "mediaopt",   NEXTARG,        setmediaopt,    NULL },
-       { "-mediaopt",  NEXTARG,        unsetmediaopt,  NULL },
-#endif
-#ifdef USE_VLANS
-       { "vlan",       NEXTARG,        setvlantag,     NULL },
-       { "vlandev",    NEXTARG,        setvlandev,     NULL },
-       { "-vlandev",   NEXTARG,        unsetvlandev,   NULL },
-#endif
-#if 0
-       /* XXX `create' special-cased below */
-       {"create",      0,              clone_create,   NULL },
-       {"plumb",       0,              clone_create,   NULL },
-#endif
-       {"destroy",     0,              clone_destroy,  NULL },
-       {"unplumb",     0,              clone_destroy,  NULL },
-#ifdef USE_IEEE80211
-       { "ssid",       NEXTARG,        set80211ssid,   NULL },
-       { "nwid",       NEXTARG,        set80211ssid,   NULL },
-       { "stationname", NEXTARG,       set80211stationname,    NULL },
-       { "station",    NEXTARG,        set80211stationname,    NULL }, /* BSD/OS */
-       { "channel",    NEXTARG,        set80211channel,        NULL },
-       { "authmode",   NEXTARG,        set80211authmode,       NULL },
-       { "powersavemode", NEXTARG,     set80211powersavemode,  NULL },
-       { "powersave",  1,              set80211powersave,      NULL },
-       { "-powersave", 0,              set80211powersave,      NULL },
-       { "powersavesleep", NEXTARG,    set80211powersavesleep, NULL },
-       { "wepmode",    NEXTARG,        set80211wepmode,        NULL },
-       { "wep",        1,              set80211wep,    NULL },
-       { "-wep",       0,              set80211wep,    NULL },
-       { "weptxkey",   NEXTARG,        set80211weptxkey,       NULL },
-       { "wepkey",     NEXTARG,        set80211wepkey, NULL },
-       { "nwkey",      NEXTARG,        set80211nwkey,  NULL }, /* NetBSD */
-       { "-nwkey",     0,              set80211wep,    NULL },         /* NetBSD */
-       { "rtsthreshold",NEXTARG,       set80211rtsthreshold,   NULL },
-       { "protmode",   NEXTARG,        set80211protmode,       NULL },
-       { "txpower",    NEXTARG,        set80211txpower,        NULL },
-#endif
-       { "rxcsum",     IFCAP_RXCSUM,   setifcap,       NULL },
-       { "-rxcsum",    -IFCAP_RXCSUM,  setifcap,       NULL },
-       { "txcsum",     IFCAP_TXCSUM,   setifcap,       NULL },
-       { "-txcsum",    -IFCAP_TXCSUM,  setifcap,       NULL },
-       { "netcons",    IFCAP_NETCONS,  setifcap,       NULL },
-       { "-netcons",   -IFCAP_NETCONS, setifcap,       NULL },
-       { "vlanmtu",    IFCAP_VLAN_MTU,         setifcap,       NULL },
-       { "-vlanmtu",   -IFCAP_VLAN_MTU,        setifcap,       NULL },
-       { "vlanhwtag",  IFCAP_VLAN_HWTAGGING,   setifcap,       NULL },
-       { "-vlanhwtag", -IFCAP_VLAN_HWTAGGING,  setifcap,       NULL },
-       { "normal",     -IFF_LINK0,     setifflags,     NULL },
-       { "compress",   IFF_LINK0,      setifflags,     NULL },
-       { "noicmp",     IFF_LINK1,      setifflags,     NULL },
-       { "mtu",        NEXTARG,        setifmtu,       NULL },
-       { "name",       NEXTARG,        setifname,      NULL },
-       { NULL,         0,              setifaddr,      NULL },
-       { NULL,         0,              setifdstaddr,   NULL },
-};
-
-/*
- * XNS support liberally adapted from code written at the University of
- * Maryland principally by James O'Toole and Chris Torek.
- */
-typedef        void af_status(int, struct rt_addrinfo *);
-typedef        void af_getaddr(const char *, int);
-typedef void af_getprefix(const char *, int);
-
-af_status      in_status, at_status, link_status;
-af_getaddr     in_getaddr, at_getaddr, link_getaddr;
-
-#ifndef NO_IPX
-af_status      ipx_status;
-af_getaddr     ipx_getaddr;
-#endif
-
-#ifdef INET6
-af_status      in6_status;
-af_getaddr     in6_getaddr;
-af_getprefix   in6_getprefix;
-#endif /*INET6*/
-#ifdef NS
-af_status      xns_status;
-af_getaddr     xns_getaddr;
-#endif
-
-/* Known address families */
-const
-struct afswtch {
-       const char *af_name;
-       short af_af;
-       af_status *af_status;
-       af_getaddr *af_getaddr;
-       af_getprefix *af_getprefix;
-       u_long af_difaddr;
-       u_long af_aifaddr;
-       caddr_t af_ridreq;
-       caddr_t af_addreq;
-} afs[] = {
-#define C(x) ((caddr_t) &x)
-       { "inet", AF_INET, in_status, in_getaddr, NULL,
-            SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#ifdef INET6
-       { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
-            SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
-            C(in6_ridreq), C(in6_addreq) },
-#endif /*INET6*/
-#ifndef NO_IPX
-       { "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
-            SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#endif
-       { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
-            SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
-#ifdef NS
-       { "ns", AF_NS, xns_status, xns_getaddr, NULL,
-            SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
-#endif
-       { "link", AF_LINK, link_status, link_getaddr, NULL,
-            0, SIOCSIFLLADDR, NULL, C(ridreq) },
-       { "ether", AF_LINK, link_status, link_getaddr, NULL,
-            0, SIOCSIFLLADDR, NULL, C(ridreq) },
-       { "lladdr", AF_LINK, link_status, link_getaddr, NULL,
-            0, SIOCSIFLLADDR, NULL, C(ridreq) },
-       { NULL, 0,      NULL, NULL, NULL,       0, 0,   NULL, NULL }
-};
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-
-#define ROUNDUP(a) \
-        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+static struct option *opts = NULL;
 
 void
-rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
+opt_register(struct option *p)
 {
-        struct sockaddr *sa;
-        int i;
-
-        memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-        for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-                if ((rtinfo->rti_addrs & (1 << i)) == 0)
-                        continue;
-                rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-                ADVANCE(cp, sa);
-        }
+       p->next = opts;
+       opts = p;
 }
 
-
-void
+static void
 usage(void)
 {
-#ifndef INET6
-       fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-       "usage: ifconfig interface address_family [address [dest_address]]",
-       "                [parameters]",
-       "       ifconfig -C",
-       "       ifconfig interface create",
-       "       ifconfig -a [-d] [-m] [-u] [address_family]",
-       "       ifconfig -l [-d] [-u] [address_family]",
-       "       ifconfig [-d] [-m] [-u]");
-#else
-       fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-       "usage: ifconfig [-L] interface address_family [address [dest_address]]",
-       "                [parameters]",
-       "       ifconfig -C",
-       "       ifconfig interface create",
-       "       ifconfig -a [-L] [-d] [-m] [-u] [address_family]",
-       "       ifconfig -l [-d] [-u] [address_family]",
-       "       ifconfig [-L] [-d] [-m] [-u]");
-#endif
+       char options[1024];
+       struct option *p;
+
+       /* XXX not right but close enough for now */
+       options[0] = '\0';
+       for (p = opts; p != NULL; p = p->next) {
+               strlcat(options, p->opt_usage, sizeof(options));
+               strlcat(options, " ", sizeof(options));
+       }
+
+       fprintf(stderr,
+       "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
+       "                [parameters]\n"
+       "       ifconfig interface create\n"
+       "       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
+       "       ifconfig -l [-d] [-u] [address_family]\n"
+       "       ifconfig %s[-d] [-m] [-u] [-v]\n",
+               options, options, options);
        exit(1);
 }
 
 int
-main(int argc, char * const *argv)
+main(int argc, char *argv[])
 {
-       int c;
-       int all, namesonly, downonly, uponly;
+       int c, all, namesonly, downonly, uponly;
        int need_nl = 0, count = 0;
-       const struct afswtch *afp = 0;
+       const struct afswtch *afp = NULL;
        int addrcount, ifindex;
-       struct  if_msghdr *ifm, *nextifm;
-       struct  ifa_msghdr *ifam;
-       struct  sockaddr_dl *sdl;
-       char    *buf, *lim, *next;
-
+       struct if_msghdr *ifm, *nextifm;
+       struct ifa_msghdr *ifam;
+       struct sockaddr_dl *sdl;
+       char *buf, *lim, *next;
        size_t needed;
        int mib[6];
+       char options[1024];
+       struct option *p;
+
+       all = downonly = uponly = namesonly = verbose = 0;
 
        /* Parse leading line options */
-       all = downonly = uponly = namesonly = 0;
-       while ((c = getopt(argc, argv, "adlmuC"
-#ifdef INET6
-                                       "L"
-#endif
-                       )) != -1) {
+       strlcpy(options, "adklmuv", sizeof(options));
+       for (p = opts; p != NULL; p = p->next)
+               strlcat(options, p->opt, sizeof(options));
+       while ((c = getopt(argc, argv, options)) != -1) {
                switch (c) {
                case 'a':       /* scan all interfaces */
                        all++;
@@ -450,6 +169,9 @@ main(int argc, char * const *argv)
                case 'd':       /* restrict scan to "down" interfaces */
                        downonly++;
                        break;
+               case 'k':
+                       printkeys++;
+                       break;
                case 'l':       /* scan interface names only */
                        namesonly++;
                        break;
@@ -459,32 +181,23 @@ main(int argc, char * const *argv)
                case 'u':       /* restrict scan to "up" interfaces */
                        uponly++;
                        break;
-               case 'C':
-                       listcloners = 1;
+               case 'v':
+                       verbose++;
                        break;
-#ifdef INET6
-               case 'L':
-                       ip6lifetime++;  /* print IPv6 address lifetime */
-                       break;
-#endif
                default:
-                       usage();
+                       for (p = opts; p != NULL; p = p->next)
+                               if (p->opt[0] == c) {
+                                       p->cb(optarg);
+                                       break;
+                               }
+                       if (p == NULL)
+                               usage();
                        break;
                }
        }
        argc -= optind;
        argv += optind;
 
-       if (listcloners) {
-               /* -C must be solitary */
-               if (all || supmedia || uponly || downonly || namesonly ||
-                   argc > 0)
-                       usage();
-               
-               list_cloners();
-               exit(0);
-       }
-
        /* -l cannot be used with -a or -m */
        if (namesonly && (all || supmedia))
                usage();
@@ -504,13 +217,11 @@ main(int argc, char * const *argv)
 
                ifindex = 0;
                if (argc == 1) {
-                       for (afp = afs; afp->af_name; afp++)
-                               if (strcmp(afp->af_name, *argv) == 0) {
-                                       argc--, argv++;
-                                       break;
-                               }
-                       if (afp->af_name == NULL)
+                       afp = af_getbyname(*argv);
+                       if (afp == NULL)
                                usage();
+                       if (afp->af_name != NULL)
+                               argc--, argv++;
                        /* leave with afp non-zero */
                }
        } else {
@@ -543,13 +254,9 @@ main(int argc, char * const *argv)
 
        /* Check for address family */
        if (argc > 0) {
-               for (afp = afs; afp->af_name; afp++)
-                       if (strcmp(afp->af_name, *argv) == 0) {
-                               argc--, argv++;
-                               break;
-                       }
-               if (afp->af_name == NULL)
-                       afp = NULL;     /* not a family, NULL */
+               afp = af_getbyname(*argv);
+               if (afp != NULL)
+                       argc--, argv++;
        }
 
 retry:
@@ -561,7 +268,7 @@ retry:
        mib[5] = ifindex;               /* interface index */
 
        /* if particular family specified, only ask about it */
-       if (afp)
+       if (afp != NULL)
                mib[3] = afp->af_af;
 
        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
@@ -585,13 +292,13 @@ retry:
                ifm = (struct if_msghdr *)next;
                
                if (ifm->ifm_type == RTM_IFINFO) {
-#if  notyet
+#ifdef notyet
                        if (ifm->ifm_data.ifi_datalen == 0)
                                ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
                        sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
-                            sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
+                           sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
 #else
-                       sdl = (struct sockaddr_dl *)(ifm + 1);
+                       sdl = (struct sockaddr_dl *)(ifm + 1);
 #endif
                        flags = ifm->ifm_flags;
                } else {
@@ -627,14 +334,6 @@ retry:
                    sizeof(name)-1 : sdl->sdl_nlen] = '\0';
 
                if (all || namesonly) {
-                       size_t len;
-
-                       /* sdl_data may not be terminated, don't use strlcpy */
-                       if ((len = sdl->sdl_nlen) > sizeof(name) - 1)
-                               len = sizeof(name) - 1;
-                       bcopy(sdl->sdl_data, name, len);
-                       name[len] = 0;
-
                        if (uponly)
                                if ((flags & IFF_UP) == 0)
                                        continue; /* not up */
@@ -642,9 +341,8 @@ retry:
                                if (flags & IFF_UP)
                                        continue; /* not down */
                        if (namesonly) {
-                               if (afp == NULL ||
-                                       afp->af_status != link_status ||
-                                       sdl->sdl_type == IFT_ETHER) {
+                               if (afp == NULL || afp->af_af != AF_LINK ||
+                                   sdl->sdl_type == IFT_ETHER) {
                                        if (need_nl)
                                                putchar(' ');
                                        fputs(name, stdout);
@@ -670,92 +368,198 @@ end:
        exit (0);
 }
 
+static struct afswtch *afs = NULL;
 
-int
+void
+af_register(struct afswtch *p)
+{
+       p->af_next = afs;
+       afs = p;
+}
+
+static struct afswtch *
+af_getbyname(const char *name)
+{
+       struct afswtch *afp;
+
+       for (afp = afs; afp !=  NULL; afp = afp->af_next)
+               if (strcmp(afp->af_name, name) == 0)
+                       return afp;
+       return NULL;
+}
+
+static struct afswtch *
+af_getbyfamily(int af)
+{
+       struct afswtch *afp;
+
+       for (afp = afs; afp != NULL; afp = afp->af_next)
+               if (afp->af_af == af)
+                       return afp;
+       return NULL;
+}
+
+static void
+af_other_status(int s)
+{
+       struct afswtch *afp;
+       uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+       memset(afmask, 0, sizeof(afmask));
+       for (afp = afs; afp != NULL; afp = afp->af_next) {
+               if (afp->af_other_status == NULL)
+                       continue;
+               if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+                       continue;
+               afp->af_other_status(s);
+               setbit(afmask, afp->af_af);
+       }
+}
+
+static void
+af_all_tunnel_status(int s)
+{
+       struct afswtch *afp;
+       uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+       memset(afmask, 0, sizeof(afmask));
+       for (afp = afs; afp != NULL; afp = afp->af_next) {
+               if (afp->af_status_tunnel == NULL)
+                       continue;
+               if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+                       continue;
+               afp->af_status_tunnel(s);
+               setbit(afmask, afp->af_af);
+       }
+}
+
+static struct cmd *cmds = NULL;
+
+void
+cmd_register(struct cmd *p)
+{
+       p->c_next = cmds;
+       cmds = p;
+}
+
+static const struct cmd *
+cmd_lookup(const char *name)
+{
+#define        N(a)    (sizeof(a)/sizeof(a[0]))
+       const struct cmd *p;
+
+       for (p = cmds; p != NULL; p = p->c_next)
+               if (strcmp(name, p->c_name) == 0)
+                       return p;
+       return NULL;
+#undef N
+}
+
+struct callback {
+       callback_func *cb_func;
+       void    *cb_arg;
+       struct callback *cb_next;
+};
+static struct callback *callbacks = NULL;
+
+void
+callback_register(callback_func *func, void *arg)
+{
+       struct callback *cb;
+
+       cb = malloc(sizeof(struct callback));
+       if (cb == NULL)
+               errx(1, "unable to allocate memory for callback");
+       cb->cb_func = func;
+       cb->cb_arg = arg;
+       cb->cb_next = callbacks;
+       callbacks = cb;
+}
+
+/* specially-handled commands */
+static void setifaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
+
+static void setifdstaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifdstaddr_cmd =
+       DEF_CMD("ifdstaddr", 0, setifdstaddr);
+
+static int
 ifconfig(int argc, char *const *argv, const struct afswtch *afp)
 {
+       struct callback *cb;
        int s;
 
        if (afp == NULL)
-               afp = &afs[0];
-       ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
+               afp = af_getbyname("inet");
+       ifr.ifr_addr.sa_family =
+               afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
+               AF_INET : afp->af_af;
        strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
 
        if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
-               err(1, "socket");
+               err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
 
        while (argc > 0) {
                const struct cmd *p;
 
-               for (p = cmds; p->c_name; p++)
-                       if (strcmp(*argv, p->c_name) == 0)
-                               break;
-               if (p->c_name == 0 && setaddr)
-                       p++;    /* got src, do dst */
-               if (p->c_func || p->c_func2) {
+               p = cmd_lookup(*argv);
+               if (p == NULL) {
+                       /*
+                        * Not a recognized command, choose between setting
+                        * the interface address and the dst address.
+                        */
+                       p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
+               }
+               if (p->c_u.c_func || p->c_u.c_func2) {
                        if (p->c_parameter == NEXTARG) {
                                if (argv[1] == NULL)
                                        errx(1, "'%s' requires argument",
                                            p->c_name);
-                               (*p->c_func)(argv[1], 0, s, afp);
+                               p->c_u.c_func(argv[1], 0, s, afp);
                                argc--, argv++;
+                       } else if (p->c_parameter == OPTARG) {
+                               p->c_u.c_func(argv[1], 0, s, afp);
+                               if (argv[1] != NULL)
+                                       argc--, argv++;
                        } else if (p->c_parameter == NEXTARG2) {
                                if (argc < 3)
                                        errx(1, "'%s' requires 2 arguments",
                                            p->c_name);
-                               (*p->c_func2)(argv[1], argv[2], s, afp);
+                               p->c_u.c_func2(argv[1], argv[2], s, afp);
                                argc -= 2, argv += 2;
                        } else
-                               (*p->c_func)(*argv, p->c_parameter, s, afp);
+                               p->c_u.c_func(*argv, p->c_parameter, s, afp);
                }
                argc--, argv++;
        }
-#ifdef INET6
-       if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) {
-               /* Aggregatable address architecture defines all prefixes
-                  are 64. So, it is convenient to set prefixlen to 64 if
-                  it is not specified. */
-               setifprefixlen("64", 0, s, afp);
-               /* in6_getprefix("64", MASK) if MASK is available here... */
-       }
-#endif
-#ifndef NO_IPX
-       if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
-               struct ipxip_req rq;
-               int size = sizeof(rq);
 
-               rq.rq_ipx = addreq.ifra_addr;
-               rq.rq_ip = addreq.ifra_dstaddr;
-
-               if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
-                       Perror("Encapsulation Routing");
-       }
-#endif
-       if (ifr.ifr_addr.sa_family == AF_APPLETALK)
-               checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
-#ifdef NS
-       if (setipdst && ifr.ifr_addr.sa_family == AF_NS) {
-               struct nsip_req rq;
-               int size = sizeof(rq);
-
-               rq.rq_ns = addreq.ifra_addr;
-               rq.rq_ip = addreq.ifra_dstaddr;
-
-               if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
-                       Perror("Encapsulation Routing");
-       }
-#endif
+       /*
+        * Do any post argument processing required by the address family.
+        */
+       if (afp->af_postproc != NULL)
+               afp->af_postproc(s, afp);
+       /*
+        * Do deferred callbacks registered while processing
+        * command-line arguments.
+        */
+       for (cb = callbacks; cb != NULL; cb = cb->cb_next)
+               cb->cb_func(s, cb->cb_arg);
+       /*
+        * Do deferred operations.
+        */
        if (clearaddr) {
                if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
                        warnx("interface %s cannot change %s addresses!",
                              name, afp->af_name);
-                       clearaddr = NULL;
+                       clearaddr = 0;
                }
        }
        if (clearaddr) {
                int ret;
                strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
-               if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
+               ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
+               if (ret < 0) {
                        if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
                                /* means no previous address for interface */
                        } else
@@ -774,20 +578,16 @@ ifconfig(int argc, char *const *argv, const struct afswtch *afp)
                if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
                        Perror("ioctl (SIOCAIFADDR)");
        }
+
        close(s);
        return(0);
 }
-#define RIDADDR 0
-#define ADDR   1
-#define MASK   2
-#define DSTADDR        3
 
 /*ARGSUSED*/
-void
-setifaddr(const char *addr, int param __unused, int s __unused,
-         const struct afswtch *afp)
+static void
+setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
 {
-       if (*afp->af_getaddr == NULL)
+       if (afp->af_getaddr == NULL)
                return;
        /*
         * Delay the ioctl to set the interface addr until flags are all set.
@@ -797,21 +597,20 @@ setifaddr(const char *addr, int param __unused, int s __unused,
        setaddr++;
        if (doalias == 0 && afp->af_af != AF_LINK)
                clearaddr = 1;
-       (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
+       afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
 }
 
-void
+static void
 settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
 {
-       struct addrinfo hints, *srcres, *dstres;
-       struct ifaliasreq addr_req;
+       struct addrinfo *srcres, *dstres;
        int ecode;
-#ifdef INET6
-       struct in6_aliasreq in6_addr_req; 
-#endif
 
-       memset(&hints, 0, sizeof(hints));
-       hints.ai_family = afp->af_af;
+       if (afp->af_settunnel == NULL) {
+               warn("address family %s does not support tunnel setup",
+                       afp->af_name);
+               return;
+       }
 
        if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
                errx(1, "error in parsing address string: %s",
@@ -825,178 +624,58 @@ settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
                errx(1,
                    "source and destination address families do not match");
 
-       switch (srcres->ai_addr->sa_family) {
-       case AF_INET:
-               memset(&addr_req, 0, sizeof(addr_req));
-               strncpy(addr_req.ifra_name, name, IFNAMSIZ);
-               memcpy(&addr_req.ifra_addr, srcres->ai_addr,
-                   srcres->ai_addr->sa_len);
-               memcpy(&addr_req.ifra_dstaddr, dstres->ai_addr,
-                   dstres->ai_addr->sa_len);
-
-               if (ioctl(s, SIOCSIFPHYADDR, &addr_req) < 0)
-                       warn("SIOCSIFPHYADDR");
-               break;
-
-#ifdef INET6
-       case AF_INET6:
-               memset(&in6_addr_req, 0, sizeof(in6_addr_req));
-               strncpy(in6_addr_req.ifra_name, name, IFNAMSIZ);
-               memcpy(&in6_addr_req.ifra_addr, srcres->ai_addr,
-                   srcres->ai_addr->sa_len);
-               memcpy(&in6_addr_req.ifra_dstaddr, dstres->ai_addr,
-                   dstres->ai_addr->sa_len);
-
-               if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addr_req) < 0)
-                       warn("SIOCSIFPHYADDR_IN6");
-               break;
-#endif /* INET6 */
-
-       default:
-               warn("address family not supported");
-       }
+       afp->af_settunnel(s, srcres, dstres);
 
        freeaddrinfo(srcres);
        freeaddrinfo(dstres);
 }
 
 /* ARGSUSED */
-void
-deletetunnel(const char *vname __unused, int param __unused, int s,
-            const struct afswtch *afp __unused)
+static void
+deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
 {
+
        if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
                err(1, "SIOCDIFPHYADDR");
 }
 
-void
-setifnetmask(const char *addr, int dummy __unused, int s __unused,
-             const struct afswtch *afp)
-{
-       if (*afp->af_getaddr == NULL)
-               return;
-       setmask++;
-       (*afp->af_getaddr)(addr, MASK);
-}
-
-#ifdef INET6
-void
-setifprefixlen(const char *addr, int dummy __unused, int s __unused,
-               const struct afswtch *afp)
-{
-        if (*afp->af_getprefix)
-                (*afp->af_getprefix)(addr, MASK);
-       explicit_prefix = 1;
-}
-
-void
-setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
-            const struct afswtch *afp)
-{
-       if (afp->af_af != AF_INET6)
-               err(1, "address flags can be set only for inet6 addresses");
-
-       if (flag < 0)
-               in6_addreq.ifra_flags &= ~(-flag);
-       else
-               in6_addreq.ifra_flags |= flag;
-}
-
-void
-setip6pltime(const char *seconds, int dummy __unused, int s,
-             const struct afswtch *afp)
+static void
+setifnetmask(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
 {
-       setip6lifetime("pltime", seconds, s, afp);
-}
-
-void
-setip6vltime(const char *seconds, int dummy __unused, int s,
-             const struct afswtch *afp)
-{
-       setip6lifetime("vltime", seconds, s, afp);
-}
-
-void
-setip6lifetime(const char *cmd, const char *val, int s __unused,
-               const struct afswtch *afp)
-{
-       time_t newval, t;
-       char *ep;
-
-       t = time(NULL);
-       newval = (time_t)strtoul(val, &ep, 0);
-       if (val == ep)
-               errx(1, "invalid %s", cmd);
-       if (afp->af_af != AF_INET6)
-               errx(1, "%s not allowed for the AF", cmd);
-       if (strcmp(cmd, "vltime") == 0) {
-               in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
-               in6_addreq.ifra_lifetime.ia6t_vltime = newval;
-       } else if (strcmp(cmd, "pltime") == 0) {
-               in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
-               in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+       if (afp->af_getaddr != NULL) {
+               setmask++;
+               afp->af_getaddr(addr, MASK);
        }
 }
 
-void
-setip6eui64(const char *cmd, int dummy __unused, int s __unused,
-            const struct afswtch *afp)
+static void
+setifbroadaddr(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
 {
-       struct ifaddrs *ifap, *ifa;
-       const struct sockaddr_in6 *sin6 = NULL;
-       const struct in6_addr *lladdr = NULL;
-       struct in6_addr *in6;
-
-       if (afp->af_af != AF_INET6)
-               errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
-       in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
-       if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
-               errx(EXIT_FAILURE, "interface index is already filled");
-       if (getifaddrs(&ifap) != 0)
-               err(EXIT_FAILURE, "getifaddrs");
-       for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-               if (ifa->ifa_addr->sa_family == AF_INET6 &&
-                   strcmp(ifa->ifa_name, name) == 0) {
-                       sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
-                       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
-                               lladdr = &sin6->sin6_addr;
-                               break;
-                       }
-               }
-       }
-       if (!lladdr)
-               errx(EXIT_FAILURE, "could not determine link local address"); 
-
-       memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
-
-       freeifaddrs(ifap);
+       if (afp->af_getaddr != NULL)
+               afp->af_getaddr(addr, DSTADDR);
 }
-#endif
 
-void
-setifbroadaddr(const char *addr, int dummy __unused, int s __unused,
-               const struct afswtch *afp)
+static void
+setifipdst(const char *addr, int dummy __unused, int s,
+    const struct afswtch *afp)
 {
-       if (*afp->af_getaddr == NULL)
-               return;
-       (*afp->af_getaddr)(addr, DSTADDR);
-}
+       const struct afswtch *inet;
 
-void
-setifipdst(const char *addr, int dummy __unused, int s __unused,
-           const struct afswtch *afp __unused)
-{
-       in_getaddr(addr, DSTADDR);
+       inet = af_getbyname("inet");
+       if (inet == NULL)
+               return;
+       inet->af_getaddr(addr, DSTADDR);
        setipdst++;
        clearaddr = 0;
        newaddr = 0;
 }
-#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
 
-void
-notealias(const char *addr __unused, int param, int s __unused,
-         const struct afswtch *afp)
+static void
+notealias(const char *addr, int param, int s, const struct afswtch *afp)
 {
+#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
        if (setaddr && doalias == 0 && param < 0)
                if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
                        bcopy((caddr_t)rqtosa(af_addreq),
@@ -1008,16 +687,16 @@ notealias(const char *addr __unused, int param, int s __unused,
                newaddr = 0;
        } else
                clearaddr = 0;
+#undef rqtosa
 }
 
 /*ARGSUSED*/
-void
-setifdstaddr(const char *addr, int param __unused, int s __unused,
-             const struct afswtch *afp)
+static void
+setifdstaddr(const char *addr, int param __unused, int s
+    const struct afswtch *afp)
 {
-       if (*afp->af_getaddr == NULL)
-               return;
-       (*afp->af_getaddr)(addr, DSTADDR);
+       if (afp->af_getaddr != NULL)
+               afp->af_getaddr(addr, DSTADDR);
 }
 
 /*
@@ -1025,9 +704,8 @@ setifdstaddr(const char *addr, int param __unused, int s __unused,
  * of the ifreq structure, which may confuse other parts of ifconfig.
  * Make a private copy so we can avoid that.
  */
-void
-setifflags(const char *vname, int value, int s,
-          const struct afswtch *afp __unused)
+static void
+setifflags(const char *vname, int value, int s, const struct afswtch *afp)
 {
        struct ifreq            my_ifr;
 
@@ -1052,8 +730,7 @@ setifflags(const char *vname, int value, int s,
 }
 
 void
-setifcap(const char *vname, int value, int s,
-        const struct afswtch *afp __unused)
+setifcap(const char *vname, int value, int s, const struct afswtch *afp)
 {
 
        if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
@@ -1071,9 +748,9 @@ setifcap(const char *vname, int value, int s,
                Perror(vname);
 }
 
-void
-setifmetric(const char *val, int dummy __unused, int s,
-            const struct afswtch *afp __unused)
+static void
+setifmetric(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
 {
        strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
        ifr.ifr_metric = atoi(val);
@@ -1081,9 +758,9 @@ setifmetric(const char *val, int dummy __unused, int s,
                warn("ioctl (set metric)");
 }
 
-void
-setifmtu(const char *val, int dummy __unused, int s,
-        const struct afswtch *afp __unused)
+static void
+setifmtu(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
 {
        strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
        ifr.ifr_mtu = atoi(val);
@@ -1091,14 +768,17 @@ setifmtu(const char *val, int dummy __unused, int s,
                warn("ioctl (set mtu)");
 }
 
-void
+static void
 setifname(const char *val, int dummy __unused, int s, 
-         const struct afswtch *afp __unused)
+    const struct afswtch *afp)
 {
-       char    *newname;
+       char *newname;
 
        newname = strdup(val);
-       
+       if (newname == NULL) {
+               warn("no memory to set ifname");
+               return;
+       }
        ifr.ifr_data = newname;
        if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
                warn("ioctl (set name)");
@@ -1106,7 +786,6 @@ setifname(const char *val, int dummy __unused, int s,
                return;
        }
        strlcpy(name, newname, sizeof(name));
-
        free(newname);
 
        /*
@@ -1116,38 +795,57 @@ setifname(const char *val, int dummy __unused, int s,
        printname = 0;
 }
 
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+static void
+rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
+{
+       struct sockaddr *sa;
+       int i;
+
+       memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+       for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+               if ((rtinfo->rti_addrs & (1 << i)) == 0)
+                       continue;
+               rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+               cp += SA_SIZE(sa);
+       }
+}
+
 #define        IFFBITS \
 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
-"\20MULTICAST\21POLLING\23MONITOR\24STATICARP"
+"\20MULTICAST\21POLLING\22PPROMISC\23MONITOR\24STATICARP\25NEEDSGIANT"
 
 #define        IFCAPBITS \
 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING"
 
 /*
  * Print the status of the interface.  If an address family was
- * specified, show it and it only; otherwise, show them all.
+ * specified, show only it; otherwise, show them all.
  */
-void
-status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
-       struct if_msghdr *ifm, struct ifa_msghdr *ifam)
+static void
+status(const struct afswtch *afp, int addrcount, struct        sockaddr_dl *sdl,
+    struct if_msghdr *ifm, struct ifa_msghdr *ifam)
 {
-       const struct afswtch *p = NULL;
        struct  rt_addrinfo info;
        int allfamilies, s;
        struct ifstat ifs;
 
        if (afp == NULL) {
                allfamilies = 1;
-               afp = &afs[0];
+               afp = af_getbyname("inet");
        } else
                allfamilies = 0;
 
        ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
-       strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
 
-       if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
-               err(1, "socket");
+       s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+       if (s < 0)
+               err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
 
        printf("%s: ", name);
        printb("flags", flags, IFFBITS);
@@ -1163,8 +861,7 @@ status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
                        putchar('\n');
                }
                if (supmedia && ifr.ifr_reqcap != 0) {
-                       printf("\tcapability list:\n");
-                       printb("\t\t", ifr.ifr_reqcap, IFCAPBITS);
+                       printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
                        putchar('\n');
                }
        }
@@ -1172,395 +869,53 @@ status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl,
        tunnel_status(s);
 
        while (addrcount > 0) {
-               
                info.rti_addrs = ifam->ifam_addrs;
-
                /* Expand the compacted addresses */
                rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
                          &info);
 
-               if (!allfamilies) {
-                       if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) {
-                               p = afp;
-                               (*p->af_status)(s, &info);
-                       }
-               } else for (p = afs; p->af_name; p++) {
-                       if (p->af_af == info.rti_info[RTAX_IFA]->sa_family)
-                               (*p->af_status)(s, &info);
-               }
+               if (allfamilies) {
+                       const struct afswtch *p;
+                       p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family);
+                       if (p != NULL && p->af_status != NULL)
+                               p->af_status(s, &info);
+               } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family)
+                       afp->af_status(s, &info);
                addrcount--;
                ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
        }
-       if (allfamilies || afp->af_status == link_status)
-               link_status(s, (struct rt_addrinfo *)sdl);
-#ifdef USE_IF_MEDIA
-       if (allfamilies || afp->af_status == media_status)
-               media_status(s, NULL);
-#endif
-#ifdef USE_VLANS
-       if (allfamilies || afp->af_status == vlan_status)
-               vlan_status(s, NULL);
-#endif
-#ifdef USE_IEEE80211
-       if (allfamilies || afp->af_status == ieee80211_status)
-               ieee80211_status(s, NULL);
-#endif
-       strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
-       if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
-               printf("%s", ifs.ascii);
-
-       if (!allfamilies && !p &&
-#ifdef USE_IF_MEDIA
-           afp->af_status != media_status &&
-#endif
-           afp->af_status != link_status
-#ifdef USE_VLANS
-           && afp->af_status != vlan_status
-#endif
-               )
-               warnx("%s has no %s interface address!", name, afp->af_name);
-
-       close(s);
-       return;
-}
-
-void
-tunnel_status(int s)
-{
-       char psrcaddr[NI_MAXHOST];
-       char pdstaddr[NI_MAXHOST];
-       u_long srccmd, dstcmd;
-       struct ifreq *ifrp;
-       const char *ver = "";
-#ifdef NI_WITHSCOPEID
-       const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
-#else
-       const int niflag = NI_NUMERICHOST;
-#endif
-#ifdef INET6
-       struct in6_ifreq in6_ifr;
-       int s6;
-#endif /* INET6 */
-
-       psrcaddr[0] = pdstaddr[0] = '\0';
-
-#ifdef INET6
-       memset(&in6_ifr, 0, sizeof(in6_ifr));
-       strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
-       s6 = socket(AF_INET6, SOCK_DGRAM, 0);
-       if (s6 < 0) {
-               srccmd = SIOCGIFPSRCADDR;
-               dstcmd = SIOCGIFPDSTADDR;
-               ifrp = &ifr;
-       } else {
-               close(s6);
-               srccmd = SIOCGIFPSRCADDR_IN6;
-               dstcmd = SIOCGIFPDSTADDR_IN6;
-               ifrp = (struct ifreq *)&in6_ifr;
-       }
-#else /* INET6 */
-       srccmd = SIOCGIFPSRCADDR;
-       dstcmd = SIOCGIFPDSTADDR;
-       ifrp = &ifr;
-#endif /* INET6 */
-
-       if (ioctl(s, srccmd, (caddr_t)ifrp) < 0)
-               return;
-#if defined(INET6) && defined(__KAME__) && defined(KAME_SCOPEID)
-       if (ifrp->ifr_addr.sa_family == AF_INET6)
-               in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
-#endif
-       getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
-           psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
-#ifdef INET6
-       if (ifrp->ifr_addr.sa_family == AF_INET6)
-               ver = "6";
-#endif
-
-       if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0)
-               return;
-#if defined(INET6) && defined(__KAME__) && defined(KAME_SCOPEID)
-       if (ifrp->ifr_addr.sa_family == AF_INET6)
-               in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
-#endif
-       getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
-           pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
+       if (allfamilies || afp->af_af == AF_LINK) {
+               const struct afswtch *lafp;
 
-       printf("\ttunnel inet%s %s --> %s\n", ver,
-           psrcaddr, pdstaddr);
-}
-
-void
-in_status(int s __unused, struct rt_addrinfo *info)
-{
-       struct sockaddr_in *addr_in, null_in;
-
-       memset(&null_in, 0, sizeof(null_in));
-
-       addr_in = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
-       printf("\tinet %s ", inet_ntoa(addr_in->sin_addr));
-
-       if (flags & IFF_POINTOPOINT) {
-               /* note RTAX_BRD overlap with IFF_BROADCAST */
-               addr_in = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
-               if (!addr_in)
-                       addr_in = &null_in;
-               printf("--> %s ", inet_ntoa(addr_in->sin_addr));
-       }
-
-       addr_in = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
-       if (!addr_in)
-               addr_in = &null_in;
-       printf("netmask 0x%lx ",
-              (unsigned long)ntohl(addr_in->sin_addr.s_addr));
-
-       if (flags & IFF_BROADCAST) {
-               /* note RTAX_BRD overlap with IFF_POINTOPOINT */
-               addr_in = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
-               if (addr_in && addr_in->sin_addr.s_addr != 0)
-                       printf("broadcast %s", inet_ntoa(addr_in->sin_addr));
-       }
-       putchar('\n');
-}
-
-#ifdef INET6
-#if defined(__KAME__) && defined(KAME_SCOPEID)
-void
-in6_fillscopeid(struct sockaddr_in6 *sin6 __unused)
-{
-       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
-               sin6->sin6_scope_id =
-                       ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
-               sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
-       }
-}
-#endif /* defined(__KAME__) && defined(KAME_SCOPEID) */
-
-void
-in6_status(int s __unused, struct rt_addrinfo *info)
-{
-       struct sockaddr_in6 *addr_in, null_in;
-       struct in6_ifreq ifr6;
-       int s6;
-       u_int32_t flags6;
-       struct in6_addrlifetime lifetime;
-       time_t t = time(NULL);
-       int error;
-       u_int32_t scopeid;
-
-       memset(&null_in, 0, sizeof(null_in));
-
-       addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
-       strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
-       if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
-               perror("ifconfig: socket");
-               return;
-       }
-       ifr6.ifr_addr = *addr_in;
-       if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
-               perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)");
-               close(s6);
-               return;
-       }
-       flags6 = ifr6.ifr_ifru.ifru_flags6;
-       memset(&lifetime, 0, sizeof(lifetime));
-       ifr6.ifr_addr = *addr_in;
-       if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
-               perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)");
-               close(s6);
-               return;
-       }
-       lifetime = ifr6.ifr_ifru.ifru_lifetime;
-       close(s6);
-
-       /* XXX: embedded link local addr check */
-       if (IN6_IS_ADDR_LINKLOCAL(&addr_in->sin6_addr) &&
-           *(u_short *)&addr_in->sin6_addr.s6_addr[2] != 0) {
-               u_short idx;
-
-               idx = *(u_short *)&addr_in->sin6_addr.s6_addr[2];
-               *(u_short *)&addr_in->sin6_addr.s6_addr[2] = 0;
-               if (addr_in->sin6_scope_id == 0)
-                       addr_in->sin6_scope_id = ntohs(idx);
-       }
-       scopeid = addr_in->sin6_scope_id;
-
-       error = getnameinfo((struct sockaddr *)addr_in, addr_in->sin6_len, addr_buf,
-                           sizeof(addr_buf), NULL, 0,
-                           NI_NUMERICHOST|NI_WITHSCOPEID);
-       if (error != 0)
-               inet_ntop(AF_INET6, &addr_in->sin6_addr, addr_buf,
-                         sizeof(addr_buf));
-       printf("\tinet6 %s ", addr_buf);
-
-       if (flags & IFF_POINTOPOINT) {
-               /* note RTAX_BRD overlap with IFF_BROADCAST */
-               addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
                /*
-                * some of the interfaces do not have valid destination
-                * address.
+                * Hack; the link level address is received separately
+                * from the routing information so any address is not
+                * handled above.  Cobble together an entry and invoke
+                * the status method specially.
                 */
-               if (addr_in && addr_in->sin6_family == AF_INET6) {
-                       /* XXX: embedded link local addr check */
-                       if (IN6_IS_ADDR_LINKLOCAL(&addr_in->sin6_addr) &&
-                           *(u_short *)&addr_in->sin6_addr.s6_addr[2] != 0) {
-                               u_short idx;
-
-                               idx = *(u_short *)&addr_in->sin6_addr.s6_addr[2];
-                               *(u_short *)&addr_in->sin6_addr.s6_addr[2] = 0;
-                               if (addr_in->sin6_scope_id == 0)
-                                       addr_in->sin6_scope_id = ntohs(idx);
-                       }
-
-                       error = getnameinfo((struct sockaddr *)addr_in,
-                                           addr_in->sin6_len, addr_buf,
-                                           sizeof(addr_buf), NULL, 0,
-                                           NI_NUMERICHOST|NI_WITHSCOPEID);
-                       if (error != 0)
-                               inet_ntop(AF_INET6, &addr_in->sin6_addr, addr_buf,
-                                         sizeof(addr_buf));
-                       printf("--> %s ", addr_buf);
+               lafp = af_getbyname("lladdr");
+               if (lafp != NULL) {
+                       info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
+                       lafp->af_status(s, &info);
                }
        }
+       if (allfamilies)
+               af_other_status(s);
+       else if (afp->af_other_status != NULL)
+               afp->af_other_status(s);
 
-       addr_in = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
-       if (!addr_in)
-               addr_in = &null_in;
-       printf("prefixlen %d ", prefix(&addr_in->sin6_addr,
-               sizeof(struct in6_addr)));
-
-       if ((flags6 & IN6_IFF_ANYCAST) != 0)
-               printf("anycast ");
-       if ((flags6 & IN6_IFF_TENTATIVE) != 0)
-               printf("tentative ");
-       if ((flags6 & IN6_IFF_DUPLICATED) != 0)
-               printf("duplicated ");
-       if ((flags6 & IN6_IFF_DETACHED) != 0)
-               printf("detached ");
-       if ((flags6 & IN6_IFF_DEPRECATED) != 0)
-               printf("deprecated ");
-       if ((flags6 & IN6_IFF_AUTOCONF) != 0)
-               printf("autoconf ");
-       if ((flags6 & IN6_IFF_TEMPORARY) != 0)
-               printf("temporary ");
-
-        if (scopeid)
-               printf("scopeid 0x%x ", scopeid);
-
-       if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
-               printf("pltime ");
-               if (lifetime.ia6t_preferred) {
-                       printf("%s ", lifetime.ia6t_preferred < t
-                               ? "0" : sec2str(lifetime.ia6t_preferred - t));
-               } else
-                       printf("infty ");
-
-               printf("vltime ");
-               if (lifetime.ia6t_expire) {
-                       printf("%s ", lifetime.ia6t_expire < t
-                               ? "0" : sec2str(lifetime.ia6t_expire - t));
-               } else
-                       printf("infty ");
-       }
-
-       putchar('\n');
-}
-#endif /*INET6*/
-
-#ifndef NO_IPX
-void
-ipx_status(int s __unused, struct rt_addrinfo *info)
-{
-       struct sockaddr_ipx *sipx, null_sipx;
-
-       memset(&null_sipx, 0, sizeof(null_sipx));
-
-       sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
-       printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
-
-       if (flags & IFF_POINTOPOINT) {
-               sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
-               if (!sipx)
-                       sipx = &null_sipx;
-               printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
-       }
-       putchar('\n');
-}
-#endif
-
-void
-at_status(int s __unused, struct rt_addrinfo *info)
-{
-       struct sockaddr_at *sat, null_sat;
-       struct netrange *nr;
-
-       memset(&null_sat, 0, sizeof(null_sat));
-
-       sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
-       nr = &sat->sat_range.r_netrange;
-       printf("\tatalk %d.%d range %d-%d phase %d",
-               ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
-               ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
-       if (flags & IFF_POINTOPOINT) {
-               /* note RTAX_BRD overlap with IFF_BROADCAST */
-               sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
-               if (!sat)
-                       sat = &null_sat;
-               printf("--> %d.%d",
-                       ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
-       }
-       if (flags & IFF_BROADCAST) {
-               /* note RTAX_BRD overlap with IFF_POINTOPOINT */
-               sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
-               if (sat)
-                       printf(" broadcast %d.%d",
-                               ntohs(sat->sat_addr.s_net),
-                               sat->sat_addr.s_node);
-       }
-
-       putchar('\n');
-}
-
-#ifdef NS
-void
-xns_status(int s __unused, struct rt_addrinfo *info)
-{
-       struct sockaddr_ns *sns, null_sns;
-
-       memset(&null_sns, 0, sizeof(null_sns));
-
-       sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA];
-       printf("\tns %s ", ns_ntoa(sns->sns_addr));
-
-       if (flags & IFF_POINTOPOINT) {
-               sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD];
-               if (!sns)
-                       sns = &null_sns;
-               printf("--> %s ", ns_ntoa(sns->sns_addr));
-       }
+       strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+       if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
+               printf("%s", ifs.ascii);
 
-       putchar('\n');
        close(s);
+       return;
 }
-#endif
-
 
-void
-link_status(int s __unused, struct rt_addrinfo *info)
+static void
+tunnel_status(int s)
 {
-       struct sockaddr_dl *sdl = (struct sockaddr_dl *)info;
-
-       if (sdl->sdl_alen > 0) {
-               if (sdl->sdl_type == IFT_ETHER &&
-                   sdl->sdl_alen == ETHER_ADDR_LEN)
-                       printf("\tether %s\n",
-                           ether_ntoa((struct ether_addr *)LLADDR(sdl)));
-               else {
-                       int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
-
-                       printf("\tlladdr %s\n", link_ntoa(sdl) + n);
-               }
-       }
+       af_all_tunnel_status(s);
 }
 
 void
@@ -1581,116 +936,6 @@ Perror(const char *cmd)
        }
 }
 
-#define SIN(x) ((struct sockaddr_in *) &(x))
-struct sockaddr_in *sintab[] = {
-SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
-SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
-
-void
-in_getaddr(const char *s, int which)
-{
-       struct sockaddr_in *addr_in = sintab[which];
-       struct hostent *hp;
-       struct netent *np;
-
-       addr_in->sin_len = sizeof(*addr_in);
-       if (which != MASK)
-               addr_in->sin_family = AF_INET;
-
-       if (which == ADDR) {
-               char *p = NULL;
-
-               if((p = strrchr(s, '/')) != NULL) {
-                       /* address is `name/masklen' */
-                       int masklen;
-                       int ret;
-                       struct sockaddr_in *min = sintab[MASK];
-                       *p = '\0';
-                       ret = sscanf(p+1, "%u", &masklen);
-                       if(ret != 1 || (masklen < 0 || masklen > 32)) {
-                               *p = '/';
-                               errx(1, "%s: bad value", s);
-                       }
-                       min->sin_len = sizeof(*min);
-                       min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 
-                                             0xffffffff);
-               }
-       }
-
-       if (inet_aton(s, &addr_in->sin_addr))
-               return;
-       if ((hp = gethostbyname(s)) != 0)
-               bcopy(hp->h_addr, (char *)&addr_in->sin_addr, 
-                   MIN((size_t)hp->h_length, sizeof(addr_in->sin_addr)));
-       else if ((np = getnetbyname(s)) != 0)
-               addr_in->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
-       else
-               errx(1, "%s: bad value", s);
-}
-
-#ifdef INET6
-#define        SIN6(x) ((struct sockaddr_in6 *) &(x))
-struct sockaddr_in6 *sin6tab[] = {
-SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
-SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
-
-void
-in6_getaddr(const char *s, int which)
-{
-       struct sockaddr_in6 *addr_in = sin6tab[which];
-       struct addrinfo hints, *res;
-       int error = -1;
-
-       newaddr &= 1;
-
-       addr_in->sin6_len = sizeof(*addr_in);
-       if (which != MASK)
-               addr_in->sin6_family = AF_INET6;
-
-       if (which == ADDR) {
-               char *p = NULL;
-               if((p = strrchr(s, '/')) != NULL) {
-                       *p = '\0';
-                       in6_getprefix(p + 1, MASK);
-                       explicit_prefix = 1;
-               }
-       }
-
-       if (addr_in->sin6_family == AF_INET6) {
-               bzero(&hints, sizeof(struct addrinfo));
-               hints.ai_family = AF_INET6;
-               error = getaddrinfo(s, NULL, &hints, &res);
-       }
-       if (error != 0) {
-               if (inet_pton(AF_INET6, s, &addr_in->sin6_addr) != 1)
-                       errx(1, "%s: bad value", s);
-       } else
-               bcopy(res->ai_addr, addr_in, res->ai_addrlen);
-}
-
-void
-in6_getprefix(const char *plen, int which)
-{
-       struct sockaddr_in6 *addr_in = sin6tab[which];
-       u_char *cp;
-       int len = atoi(plen);
-
-       if ((len < 0) || (len > 128))
-               errx(1, "%s: bad value", plen);
-       addr_in->sin6_len = sizeof(*addr_in);
-       if (which != MASK)
-               addr_in->sin6_family = AF_INET6;
-       if ((len == 0) || (len == 128)) {
-               memset(&addr_in->sin6_addr, 0xff, sizeof(struct in6_addr));
-               return;
-       }
-       memset((void *)&addr_in->sin6_addr, 0x00, sizeof(addr_in->sin6_addr));
-       for (cp = (u_char *)&addr_in->sin6_addr; len > 7; len -= 8)
-               *cp++ = 0xff;
-       *cp = 0xff << (8 - len);
-}
-#endif
-
 /*
  * Print a value a la the %b format of the kernel's printf
  */
@@ -1722,200 +967,16 @@ printb(const char *s, unsigned v, const char *bits)
        }
 }
 
-#ifndef NO_IPX
-#define SIPX(x) ((struct sockaddr_ipx *) &(x))
-struct sockaddr_ipx *sipxtab[] = {
-SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
-SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
-
-void
-ipx_getaddr(const char *addr, int which)
-{
-       struct sockaddr_ipx *sipx = sipxtab[which];
-
-       sipx->sipx_family = AF_IPX;
-       sipx->sipx_len = sizeof(*sipx);
-       sipx->sipx_addr = ipx_addr(addr);
-       if (which == MASK)
-               printf("Attempt to set IPX netmask will be ineffectual\n");
-}
-#endif
-
-void
-at_getaddr(const char *addr, int which)
-{
-       struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
-       u_int net, node;
-
-       sat->sat_family = AF_APPLETALK;
-       sat->sat_len = sizeof(*sat);
-       if (which == MASK)
-               errx(1, "AppleTalk does not use netmasks");
-       if (sscanf(addr, "%u.%u", &net, &node) != 2
-           || net > 0xffff || node > 0xfe)
-               errx(1, "%s: illegal address", addr);
-       sat->sat_addr.s_net = htons(net);
-       sat->sat_addr.s_node = node;
-}
-
-void
-link_getaddr(const char *addr, int which)
-{
-       char *temp;
-       struct sockaddr_dl sdl;
-       struct sockaddr *sa = &ridreq.ifr_addr;
-
-       if (which != ADDR)
-               errx(1, "can't set link-level netmask or broadcast");
-       if ((temp = malloc(strlen(addr) + 1)) == NULL)
-               errx(1, "malloc failed");
-       temp[0] = ':';
-       strcpy(temp + 1, addr);
-       sdl.sdl_len = sizeof(sdl);
-       link_addr(temp, &sdl);
-       free(temp);
-       if (sdl.sdl_alen > sizeof(sa->sa_data))
-               errx(1, "malformed link-level address");
-       sa->sa_family = AF_LINK;
-       sa->sa_len = sdl.sdl_alen;
-       bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
-}
-
-/* XXX  FIXME -- should use strtoul for better parsing. */
-void
-setatrange(const char *range, int dummy __unused, int s __unused,
-           const struct afswtch *afp __unused)
-{
-       u_int   first = 123, last = 123;
-
-       if (sscanf(range, "%u-%u", &first, &last) != 2
-           || first == 0 || first > 0xffff
-           || last == 0 || last > 0xffff || first > last)
-               errx(1, "%s: illegal net range: %u-%u", range, first, last);
-       at_nr.nr_firstnet = htons(first);
-       at_nr.nr_lastnet = htons(last);
-}
-
-void
-setatphase(const char *phase, int dummy __unused, int s __unused,
-           const struct afswtch *afp __unused)
-{
-       if (!strcmp(phase, "1"))
-               at_nr.nr_phase = 1;
-       else if (!strcmp(phase, "2"))
-               at_nr.nr_phase = 2;
-       else
-               errx(1, "%s: illegal phase", phase);
-}
-
-void
-checkatrange(struct sockaddr_at *sat)
-{
-       if (at_nr.nr_phase == 0)
-               at_nr.nr_phase = 2;     /* Default phase 2 */
-       if (at_nr.nr_firstnet == 0)
-               at_nr.nr_firstnet =     /* Default range of one */
-               at_nr.nr_lastnet = sat->sat_addr.s_net;
-printf("\tatalk %d.%d range %d-%d phase %d\n",
-       ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
-       ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
-       if ((u_short) ntohs(at_nr.nr_firstnet) >
-                       (u_short) ntohs(sat->sat_addr.s_net)
-                   || (u_short) ntohs(at_nr.nr_lastnet) <
-                       (u_short) ntohs(sat->sat_addr.s_net))
-               errx(1, "AppleTalk address is not in range");
-       sat->sat_range.r_netrange = at_nr;
-}
-
-#ifdef NS
-#define SNS(x) ((struct sockaddr_ns *) &(x))
-struct sockaddr_ns *snstab[] = {
-SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
-SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
-
-void
-xns_getaddr(const char *addr, int which)
-{
-       struct sockaddr_ns *sns = snstab[which];
-
-       sns->sns_family = AF_NS;
-       sns->sns_len = sizeof(*sns);
-       sns->sns_addr = ns_addr(addr);
-       if (which == MASK)
-               printf("Attempt to set XNS netmask will be ineffectual\n");
-}
-#endif
-
-#ifdef INET6
-int
-prefix(void *val, int size)
-{
-       u_char *addr = (u_char *)val;
-       int byte, bit, plen = 0;
-
-        for (byte = 0; byte < size; byte++, plen += 8)
-               if (addr[byte] != 0xff)
-                        break;
-       if (byte == size)
-               return (plen);
-       for (bit = 7; bit != 0; bit--, plen++)
-                if (!(addr[byte] & (1 << bit)))
-                        break;
-        for (; bit != 0; bit--)
-                if (addr[byte] & (1 << bit))
-                        return(0);
-        byte++;
-        for (; byte < size; byte++)
-                if (addr[byte])
-                        return(0);
-        return (plen);
-}
-
-static char *
-sec2str(time_t total)
-{
-       static char result[256];
-       int days, hours, mins, secs;
-       int first = 1;
-       char *p = result;
-
-       if (0) {
-               days = total / 3600 / 24;
-               hours = (total / 3600) % 24;
-               mins = (total / 60) % 60;
-               secs = total % 60;
-
-               if (days) {
-                       first = 0;
-                       p += sprintf(p, "%dd", days);
-               }
-               if (!first || hours) {
-                       first = 0;
-                       p += sprintf(p, "%dh", hours);
-               }
-               if (!first || mins) {
-                       first = 0;
-                       p += sprintf(p, "%dm", mins);
-               }
-               sprintf(p, "%ds", secs);
-       } else
-               sprintf(result, "%lu", (unsigned long)total);
-
-       return(result);
-}
-#endif /*INET6*/
-
 void
-ifmaybeload(char *if_nm)
+ifmaybeload(char *name)
 {
        struct module_stat mstat;
        int fileid, modid;
        char ifkind[35], *cp, *dp;
 
-
        /* turn interface and unit into module name */
        strcpy(ifkind, "if_");
-       for (cp = if_nm, dp = ifkind + 3;
+       for (cp = name, dp = ifkind + 3;
            (*cp != 0) && !isdigit(*cp); cp++, dp++)
                *dp = *cp;
        *dp = 0;
@@ -1935,8 +996,8 @@ ifmaybeload(char *if_nm)
                                cp = mstat.name;
                        }
                        /* already loaded? */
-                       if (strncmp(if_nm, cp, strlen(cp)) == 0 ||
-                               strncmp(ifkind, cp, strlen(cp)) == 0)
+                       if (strncmp(name, cp, strlen(cp)) == 0 ||
+                           strncmp(ifkind, cp, strlen(cp)) == 0)
                                return;
                }
        }
@@ -1945,87 +1006,68 @@ ifmaybeload(char *if_nm)
        kldload(ifkind);
 }
 
-void
-list_cloners(void)
-{
-       struct if_clonereq ifcr;
-       char *cp, *buf;
-       int idx;
-       int s;
-
-       s = socket(AF_INET, SOCK_DGRAM, 0);
-       if (s == -1)
-               err(1, "socket");
-
-       memset(&ifcr, 0, sizeof(ifcr));
-
-       if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
-               err(1, "SIOCIFGCLONERS for count");
-
-       buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
-       if (buf == NULL)
-               err(1, "unable to allocate cloner name buffer");
-
-       ifcr.ifcr_count = ifcr.ifcr_total;
-       ifcr.ifcr_buffer = buf;
-
-       if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
-               err(1, "SIOCIFGCLONERS for names");
-
-       /*
-        * In case some disappeared in the mean time, clamp it down.
-        */
-       if (ifcr.ifcr_count > ifcr.ifcr_total)
-               ifcr.ifcr_count = ifcr.ifcr_total;
-
-       for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
-               if (idx > 0)
-                       putchar(' ');
-               printf("%s", cp);
-       }
-
-       putchar('\n');
-       free(buf);
-}
-
-void
-clone_create(void)
-{
-       int s;
-
-       s = socket(AF_INET, SOCK_DGRAM, 0);
-       if (s == -1)
-               err(1, "socket");
-
-       memset(&ifr, 0, sizeof(ifr));
-       strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
-               err(1, "SIOCIFCREATE");
-
-       /*
-        * If we get a different name back then we put in, we probably
-        * want to print it out, but we might change our mind later so
-        * we just signal our intrest and leave the printout for later.
-        */
-       if (strcmp(name, ifr.ifr_name) != 0) {
-               printname = 1;
-               strlcpy(name, ifr.ifr_name, sizeof(name));
-       }
-
-       close(s);
-}
+static struct cmd basic_cmds[] = {
+       DEF_CMD("up",           IFF_UP,         setifflags),
+       DEF_CMD("down",         -IFF_UP,        setifflags),
+       DEF_CMD("arp",          -IFF_NOARP,     setifflags),
+       DEF_CMD("-arp",         IFF_NOARP,      setifflags),
+       DEF_CMD("debug",        IFF_DEBUG,      setifflags),
+       DEF_CMD("-debug",       -IFF_DEBUG,     setifflags),
+       DEF_CMD("promisc",      IFF_PPROMISC,   setifflags),
+       DEF_CMD("-promisc",     -IFF_PPROMISC,  setifflags),
+       DEF_CMD("add",          IFF_UP,         notealias),
+       DEF_CMD("alias",        IFF_UP,         notealias),
+       DEF_CMD("-alias",       -IFF_UP,        notealias),
+       DEF_CMD("delete",       -IFF_UP,        notealias),
+       DEF_CMD("remove",       -IFF_UP,        notealias),
+#ifdef notdef
+#define        EN_SWABIPS      0x1000
+       DEF_CMD("swabips",      EN_SWABIPS,     setifflags),
+       DEF_CMD("-swabips",     -EN_SWABIPS,    setifflags),
+#endif
+       DEF_CMD_ARG("netmask",                  setifnetmask),
+       DEF_CMD_ARG("metric",                   setifmetric),
+       DEF_CMD_ARG("broadcast",                setifbroadaddr),
+#ifndef NO_IPX
+       DEF_CMD_ARG("ipdst",                    setifipdst),
+#endif
+       DEF_CMD_ARG2("tunnel",                  settunnel),
+       DEF_CMD("-tunnel", 0,                   deletetunnel),
+       DEF_CMD("deletetunnel", 0,              deletetunnel),
+       DEF_CMD("link0",        IFF_LINK0,      setifflags),
+       DEF_CMD("-link0",       -IFF_LINK0,     setifflags),
+       DEF_CMD("link1",        IFF_LINK1,      setifflags),
+       DEF_CMD("-link1",       -IFF_LINK1,     setifflags),
+       DEF_CMD("link2",        IFF_LINK2,      setifflags),
+       DEF_CMD("-link2",       -IFF_LINK2,     setifflags),
+#ifdef notyet
+       DEF_CMD("monitor",      IFF_MONITOR,    setifflags),
+       DEF_CMD("-monitor",     -IFF_MONITOR,   setifflags),
+       DEF_CMD("staticarp",    IFF_STATICARP,  setifflags),
+       DEF_CMD("-staticarp",   -IFF_STATICARP, setifflags),
+#endif
+       DEF_CMD("polling",      IFF_POLLING,    setifcap),
+       DEF_CMD("-polling",     -IFF_POLLING,   setifcap),
+       DEF_CMD("rxcsum",       IFCAP_RXCSUM,   setifcap),
+       DEF_CMD("-rxcsum",      -IFCAP_RXCSUM,  setifcap),
+       DEF_CMD("txcsum",       IFCAP_TXCSUM,   setifcap),
+       DEF_CMD("-txcsum",      -IFCAP_TXCSUM,  setifcap),
+       DEF_CMD("netcons",      IFCAP_NETCONS,  setifcap),
+       DEF_CMD("-netcons",     -IFCAP_NETCONS, setifcap),
+       DEF_CMD("normal",       -IFF_LINK0,     setifflags),
+       DEF_CMD("compress",     IFF_LINK0,      setifflags),
+       DEF_CMD("noicmp",       IFF_LINK1,      setifflags),
+       DEF_CMD_ARG("mtu",                      setifmtu),
+       DEF_CMD_ARG("name",                     setifname),
+};
 
-void
-clone_destroy(const char *val __unused, int d __unused, int s,
-             const struct afswtch *rafp __unused)
+static __constructor void
+ifconfig_ctor(void)
 {
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
 
-       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
-               err(1, "SIOCIFDESTROY");
-       /*
-        * If we create and destroy an interface in the same command,
-        * there isn't any reason to print it's name.
-        */
-       printname = 0;
+       for (i = 0; i < N(basic_cmds);  i++)
+               cmd_register(&basic_cmds[i]);
+#undef N
 }
index 73d5c14..f82f9d8 100644 (file)
  *
  * so there!
  *
- * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.12 2004/03/30 22:59:22 sam Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.h,v 1.5 2005/04/25 17:33:26 swildner Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.16.2.1 2005/07/21 12:25:40 rwatson Exp $
+ * $DragonFly: src/sbin/ifconfig/ifconfig.h,v 1.6 2006/04/02 03:33:59 sephe Exp $
  */
 
-extern struct ifreq ifr;
+#define        __constructor   __attribute__((constructor))
 
-extern char name[IFNAMSIZ];    /* name of interface */
-extern int allmedia;
-extern int supmedia;
 struct afswtch;
+struct cmd;
 
-extern void setmedia(const char *, int, int, const struct afswtch *rafp);
-extern void setmediamode(const char *, int, int, const struct afswtch *rafp);
-extern void setmediaopt(const char *, int, int, const struct afswtch *rafp);
-extern void unsetmediaopt(const char *, int, int, const struct afswtch *rafp);
-extern void media_status(int s, struct rt_addrinfo *);
-
-extern void setvlantag(const char *, int, int, const struct afswtch *rafp);
-extern void setvlandev(const char *, int, int, const struct afswtch *rafp);
-extern void unsetvlandev(const char *, int, int, const struct afswtch *rafp);
-extern void vlan_status(int s, struct rt_addrinfo *);
-
-extern void set80211ssid(const char *, int, int, const struct afswtch *rafp);
-extern void set80211stationname(const char *, int, int, const struct afswtch *rafp);
-extern void set80211channel(const char *, int, int, const struct afswtch *rafp);
-extern void set80211authmode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211powersave(const char *, int, int, const struct afswtch *rafp);
-extern void set80211powersavemode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211powersavesleep(const char *, int, int, const struct afswtch *rafp);
-extern void set80211wepmode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211wep(const char *, int, int, const struct afswtch *rafp);
-extern void set80211weptxkey(const char *, int, int, const struct afswtch *rafp);
-extern void set80211wepkey(const char *, int, int, const struct afswtch *rafp);
-extern void set80211nwkey(const char *, int, int, const struct afswtch *rafp);
-extern void set80211rtsthreshold(const char *, int, int, const struct afswtch *rafp);
-extern void set80211protmode(const char *, int, int, const struct afswtch *rafp);
-extern void set80211txpower(const char *, int, int, const struct afswtch *rafp);
-extern void ieee80211_status(int s, struct rt_addrinfo *);
+typedef        void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
+typedef        void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp);
+
+struct cmd {
+       const char *c_name;
+       int     c_parameter;
+#define        NEXTARG         0xffffff        /* has following arg */
+#define        NEXTARG2        0xfffffe        /* has 2 following args */
+#define        OPTARG          0xfffffd        /* has optional following arg */
+       union {
+               c_func  *c_func;
+               c_func2 *c_func2;
+       } c_u;
+       struct cmd *c_next;
+};
+void   cmd_register(struct cmd *);
+
+typedef        void callback_func(int s, void *);
+void   callback_register(callback_func *, void *);
+
+/*
+ * Macros for declaring command functions and initializing entries.
+ */
+#define        DECL_CMD_FUNC(name, cmd, arg)           \
+       void name(const char *cmd, int arg, int s, const struct afswtch *afp)
+#define        DECL_CMD_FUNC2(name, arg1, arg2)        \
+       void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp)
+
+#define        DEF_CMD(name, param, func)      { name, param, { .c_func = func } }
+#define        DEF_CMD_ARG(name, func)         \
+       { .c_name = name, .c_parameter = NEXTARG, .c_u = { .c_func = func } }
+#define        DEF_CMD_OPTARG(name, func)      { name, OPTARG, { .c_func = func } }
+#define        DEF_CMD_ARG2(name, func)        { name, NEXTARG2, { .c_func2 = func } }
+
+struct rt_addrinfo;
+struct addrinfo;
+
+enum {
+       RIDADDR,
+       ADDR,
+       MASK,
+       DSTADDR,
+};
+
+struct afswtch {
+       const char      *af_name;       /* as given on cmd line, e.g. "inet" */
+       short           af_af;          /* AF_* */
+       /*
+        * Status is handled one of two ways; if there is an
+        * address associated with the interface then the
+        * associated address family af_status method is invoked
+        * with the appropriate addressin info.  Otherwise, if
+        * all possible info is to be displayed and af_other_status
+        * is defined then it is invoked after all address status
+        * is presented.
+        */
+       void            (*af_status)(int, const struct rt_addrinfo *);
+       void            (*af_other_status)(int);
+                                       /* parse address method */
+       void            (*af_getaddr)(const char *, int);
+                                       /* parse prefix method (IPv6) */
+       void            (*af_getprefix)(const char *, int);
+       void            (*af_postproc)(int s, const struct afswtch *);
+       u_long          af_difaddr;     /* set dst if address ioctl */
+       u_long          af_aifaddr;     /* set if address ioctl */
+       void            *af_ridreq;     /* */
+       void            *af_addreq;     /* */
+       struct afswtch  *af_next;
+
+       /* XXX doesn't fit model */
+       void            (*af_status_tunnel)(int);
+       void            (*af_settunnel)(int s, struct addrinfo *srcres,
+                               struct addrinfo *dstres);
+};
+void   af_register(struct afswtch *);
+
+struct option {
+       const char *opt;
+       const char *opt_usage;
+       void    (*cb)(const char *arg);
+       struct option *next;
+};
+void   opt_register(struct option *);
+
+extern struct ifreq ifr;
+extern char name[IFNAMSIZ];    /* name of interface */
+extern int allmedia;
+extern int supmedia;
+extern int printkeys;
+extern int printname;
+extern int flags;
+extern int newaddr;
+extern int verbose;
+extern int setipdst;
+
+void   setifcap(const char *, int value, int s, const struct afswtch *);
+
+void   Perror(const char *cmd);
+void   printb(const char *s, unsigned value, const char *bits);
+
+void   ifmaybeload(char *);
+
+void   clone_create(void);
index 1c59b11..38d3d1e 100644 (file)
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.1.2.3 2002/02/07 15:12:37 ambrisko Exp $
- * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.9 2005/11/06 12:21:42 swildner Exp $
+ * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.10 2006/04/02 03:33:59 sephe Exp $
  */
 
 /*-
@@ -96,7 +96,7 @@ static const char *get_string(const char *val, const char *sep,
     u_int8_t *buf, int *lenp);
 static void print_string(const u_int8_t *buf, int len);
 
-void
+static void
 set80211ssid(const char *val, int d __unused, int s,
             const struct afswtch *rafp __unused)
 {
@@ -118,7 +118,7 @@ set80211ssid(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
 }
 
-void
+static void
 set80211stationname(const char *val, int d __unused, int s,
                    const struct afswtch *rafp __unused)
 {
@@ -132,7 +132,7 @@ set80211stationname(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
 }
 
-void
+static void
 set80211channel(const char *val, int d __unused, int s,
                const struct afswtch *rafp __unused)
 {
@@ -142,7 +142,7 @@ set80211channel(const char *val, int d __unused, int s,
                set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
 }
 
-void
+static void
 set80211authmode(const char *val, int d __unused, int s,
                 const struct afswtch *rafp __unused)
 {
@@ -161,7 +161,7 @@ set80211authmode(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
 }
 
-void
+static void
 set80211powersavemode(const char *val, int d __unused, int s,
                      const struct afswtch *rafp __unused)
 {
@@ -184,7 +184,7 @@ set80211powersavemode(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
 }
 
-void
+static void
 set80211powersave(const char *val __unused, int d, int s,
                  const struct afswtch *rafp __unused)
 {
@@ -196,14 +196,14 @@ set80211powersave(const char *val __unused, int d, int s,
                    0, NULL);
 }
 
-void
+static void
 set80211powersavesleep(const char *val, int d __unused, int s,
                       const struct afswtch *rafp __unused)
 {
        set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
 }
 
-void
+static void
 set80211wepmode(const char *val, int d __unused, int s,
                const struct afswtch *rafp __unused)
 {
@@ -222,21 +222,21 @@ set80211wepmode(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
 }
 
-void
+static void
 set80211wep(const char *val __unused, int d, int s,
            const struct afswtch *rafp __unused)
 {
        set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
 }
 
-void
+static void
 set80211weptxkey(const char *val, int d __unused, int s,
                 const struct afswtch *rafp __unused)
 {
        set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
 }
 
-void
+static void
 set80211wepkey(const char *val, int d __unused, int s,
               const struct afswtch *rafp __unused)
 {
@@ -261,7 +261,7 @@ set80211wepkey(const char *val, int d __unused, int s,
  * iterface is too inflexable, but it's there so we'll support it since
  * it's not all that hard.
  */
-void
+static void
 set80211nwkey(const char *val, int d __unused, int s,
              const struct afswtch *rafp __unused)
 {
@@ -298,14 +298,14 @@ set80211nwkey(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
 }
 
-void
+static void
 set80211rtsthreshold(const char *val, int d __unused, int s,
        const struct afswtch *rafp __unused)
 {
        set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
 }
 
-void
+static void
 set80211protmode(const char *val, int d __unused, int s,
        const struct afswtch *rafp __unused)
 {
@@ -324,15 +324,15 @@ set80211protmode(const char *val, int d __unused, int s,
        set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
 }
 
-void
+static void
 set80211txpower(const char *val, int d __unused, int s,
        const struct afswtch *rafp __unused)
 {
        set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
 }
 
-void
-ieee80211_status (int s, struct rt_addrinfo *info __unused)
+static void
+ieee80211_status (int s)
 {
        int                     i;
        int                     num;
@@ -623,3 +623,44 @@ print_string(const u_int8_t *buf, int len)
        }
 }
 
+static struct cmd ieee80211_cmds[] = {
+       DEF_CMD_ARG("ssid",             set80211ssid),
+       DEF_CMD_ARG("nwid",             set80211ssid),
+       DEF_CMD_ARG("stationname",      set80211stationname),
+       DEF_CMD_ARG("station",          set80211stationname),   /* BSD/OS */
+       DEF_CMD_ARG("channel",          set80211channel),
+       DEF_CMD_ARG("authmode",         set80211authmode),
+       DEF_CMD_ARG("powersavemode",    set80211powersavemode),
+       DEF_CMD("powersave",    1,      set80211powersave),
+       DEF_CMD("-powersave",   0,      set80211powersave),
+       DEF_CMD_ARG("powersavesleep",   set80211powersavesleep),
+       DEF_CMD_ARG("wepmode",          set80211wepmode),
+       DEF_CMD("wep",          1,      set80211wep),
+       DEF_CMD("-wep",         0,      set80211wep),
+       DEF_CMD_ARG("deftxkey",         set80211weptxkey),
+       DEF_CMD_ARG("weptxkey",         set80211weptxkey),
+       DEF_CMD_ARG("wepkey",           set80211wepkey),
+       DEF_CMD_ARG("nwkey",            set80211nwkey),         /* NetBSD */
+       DEF_CMD("-nwkey",       0,      set80211wep),           /* NetBSD */
+       DEF_CMD_ARG("rtsthreshold",     set80211rtsthreshold),
+       DEF_CMD_ARG("protmode",         set80211protmode),
+       DEF_CMD_ARG("txpower",          set80211txpower),
+};
+
+static struct afswtch af_ieee80211 = {
+       .af_name        = "af_ieee80211",
+       .af_af          = AF_UNSPEC,
+       .af_other_status = ieee80211_status,
+};
+
+static __constructor void
+ieee80211_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(ieee80211_cmds);  i++)
+               cmd_register(&ieee80211_cmds[i]);
+       af_register(&af_ieee80211);
+#undef N
+}
index 980b88b..978c79a 100644 (file)
@@ -1,6 +1,6 @@
 /*     $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $      */
-/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.6.2.3 2001/11/14 04:35:07 yar Exp $ */
-/* $DragonFly: src/sbin/ifconfig/ifmedia.c,v 1.9 2005/11/06 12:21:42 swildner Exp $ */
+/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.19.2.1 2006/03/01 22:24:23 glebius Exp $ */
+/* $DragonFly: src/sbin/ifconfig/ifmedia.c,v 1.10 2006/04/02 03:33:59 sephe Exp $ */
 
 /*
  * Copyright (c) 1997 Jason R. Thorpe.
 
 #include "ifconfig.h"
 
-#ifndef IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS
-  #define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS {                       \
-        { IFM_AUTO, "autoselect" },                                     \
-        { IFM_IEEE80211_11A, "11a" },                                   \
-        { IFM_IEEE80211_11B, "11b" },                                   \
-        { IFM_IEEE80211_11G, "11g" },                                   \
-        { IFM_IEEE80211_FH, "fh" },                                     \
-        { 0, NULL },                                                    \
-}
-#endif
-
-#ifndef IFM_SUBTYPE_IEEE80211_MODE_ALIASES
-  #define IFM_SUBTYPE_IEEE80211_MODE_ALIASES {                            \
-        { IFM_AUTO, "auto" },                                           \
-        { 0, NULL },                                                    \
-}
-#endif
-
 static void    domediaopt(const char *, int, int);
 static int     get_media_subtype(int, const char *);
 static int     get_media_mode(int, const char *);
@@ -121,8 +103,8 @@ static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
 static struct ifmedia_description *get_subtype_desc(int,
     struct ifmedia_type_to_subtype *ttos);
 
-void
-media_status(int s, struct rt_addrinfo *info __unused)
+static void
+media_status(int s)
 {
        struct ifmediareq ifmr;
        int *media_list, i;
@@ -130,7 +112,7 @@ media_status(int s, struct rt_addrinfo *info __unused)
        memset(&ifmr, 0, sizeof(ifmr));
        strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
 
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+       if (ioctl(s, SIOCGIFMEDIA, &ifmr) < 0) {
                /*
                 * Interface doesn't support SIOC{G,S}IFMEDIA.
                 */
@@ -142,12 +124,12 @@ media_status(int s, struct rt_addrinfo *info __unused)
                return;
        }
 
-       media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+       media_list = malloc(ifmr.ifm_count * sizeof(int));
        if (media_list == NULL)
                err(1, "malloc");
        ifmr.ifm_ulist = media_list;
 
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+       if (ioctl(s, SIOCGIFMEDIA, &ifmr) < 0)
                err(1, "SIOCGIFMEDIA");
 
        printf("\tmedia: ");
@@ -179,14 +161,12 @@ media_status(int s, struct rt_addrinfo *info __unused)
                                printf("no ring");
                        break;
 
-#if notyet
                case IFM_ATM:
                        if (ifmr.ifm_status & IFM_ACTIVE)
                                printf("active");
                        else
                                printf("no carrier");
                        break;
-#endif
 
                case IFM_IEEE80211:
                        /* XXX: Different value for adhoc? */
@@ -211,29 +191,73 @@ media_status(int s, struct rt_addrinfo *info __unused)
        free(media_list);
 }
 
-void
-setmedia(const char *val, int d __unused, int s,
-        const struct afswtch *afp __unused)
+static struct ifmediareq *
+getifmediastate(int s)
 {
-       struct ifmediareq ifmr;
-       int first_type, subtype;
+       static struct ifmediareq *ifmr = NULL;
+       int *mwords;
 
-       memset(&ifmr, 0, sizeof(ifmr));
-       strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+       if (ifmr == NULL) {
+               ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+               if (ifmr == NULL)
+                       err(1, "malloc");
+
+               (void) memset(ifmr, 0, sizeof(struct ifmediareq));
+               (void) strncpy(ifmr->ifm_name, name,
+                   sizeof(ifmr->ifm_name));
+
+               ifmr->ifm_count = 0;
+               ifmr->ifm_ulist = NULL;
 
-       ifmr.ifm_count = 1;
-       ifmr.ifm_ulist = &first_type;
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
                /*
-                * If we get E2BIG, the kernel is telling us
-                * that there are more, so we can ignore it.
+                * We must go through the motions of reading all
+                * supported media because we need to know both
+                * the current media type and the top-level type.
                 */
-               if (errno != E2BIG)
+
+               if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
+                       err(1, "SIOCGIFMEDIA");
+               }
+
+               if (ifmr->ifm_count == 0)
+                       errx(1, "%s: no media types?", name);
+
+               mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
+               if (mwords == NULL)
+                       err(1, "malloc");
+  
+               ifmr->ifm_ulist = mwords;
+               if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
                        err(1, "SIOCGIFMEDIA");
        }
 
-       if (ifmr.ifm_count == 0)
-               errx(1, "%s: no media types?", name);
+       return ifmr;
+}
+
+static void
+setifmediacallback(int s, void *arg)
+{
+       struct ifmediareq *ifmr = (struct ifmediareq *)arg;
+       static int did_it = 0;
+
+       if (!did_it) {
+               ifr.ifr_media = ifmr->ifm_current;
+               if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+                       err(1, "SIOCSIFMEDIA (media)");
+               free(ifmr->ifm_ulist);
+               free(ifmr);
+               did_it = 1;
+       }
+}
+
+static void
+setmedia(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct ifmediareq *ifmr;
+       int subtype;
+       
+
+       ifmr = getifmediastate(s);
 
        /*
         * We are primarily concerned with the top-level type.
@@ -244,27 +268,29 @@ setmedia(const char *val, int d __unused, int s,
         * (I'm assuming that all supported media types for a given
         * interface will be the same top-level type..)
         */
-       subtype = get_media_subtype(IFM_TYPE(first_type), val);
+       subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
 
        strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
-           IFM_TYPE(first_type) | subtype;
+       ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
+           IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
 
-       if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
-               err(1, "SIOCSIFMEDIA (media)");
+       if ((ifr.ifr_media & IFM_TMASK) == 0) {
+               ifr.ifr_media &= ~IFM_GMASK;
+       }
+
+       ifmr->ifm_current = ifr.ifr_media;
+       callback_register(setifmediacallback, (void *)ifmr);
 }
 
-void
-setmediaopt(const char *val, int d __unused, int s,
-           const struct afswtch *afp __unused)
+static void
+setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
 {
 
        domediaopt(val, 0, s);
 }
 
-void
-unsetmediaopt(const char *val, int d __unused, int s,
-             const struct afswtch *afp __unused)
+static void
+unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
 {
 
        domediaopt(val, 1, s);
@@ -273,87 +299,40 @@ unsetmediaopt(const char *val, int d __unused, int s,
 static void
 domediaopt(const char *val, int clear, int s)
 {
-       struct ifmediareq ifmr;
-       int *mwords, options;
-
-       memset(&ifmr, 0, sizeof(ifmr));
-       strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+       struct ifmediareq *ifmr;
+       int options;
 
-       /*
-        * We must go through the motions of reading all
-        * supported media because we need to know both
-        * the current media type and the top-level type.
-        */
-
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
-               err(1, "SIOCGIFMEDIA");
-
-       if (ifmr.ifm_count == 0)
-               errx(1, "%s: no media types?", name);
-
-       mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
-       if (mwords == NULL)
-               err(1, "malloc");
-
-       ifmr.ifm_ulist = mwords;
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
-               err(1, "SIOCGIFMEDIA");
+       ifmr = getifmediastate(s);
 
-       options = get_media_options(IFM_TYPE(mwords[0]), val);
-
-       free(mwords);
+       options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
 
        strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       ifr.ifr_media = ifmr.ifm_current;
+       ifr.ifr_media = ifmr->ifm_current;
        if (clear)
                ifr.ifr_media &= ~options;
        else
                ifr.ifr_media |= options;
 
-       if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
-               err(1, "SIOCSIFMEDIA (mediaopt)");
+       ifmr->ifm_current = ifr.ifr_media;
+       callback_register(setifmediacallback, (void *)ifmr);
 }
 
 
-void
-setmediamode(const char *val, int d __unused, int s,
-       const struct afswtch *afp __unused)
+static void
+setmediamode(const char *val, int d, int s, const struct afswtch *afp)
 {
-       struct ifmediareq ifmr;
-       int *mwords, mode;
+       struct ifmediareq *ifmr;
+       int mode;
 
-       memset(&ifmr, 0, sizeof(ifmr));
-       strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+       ifmr = getifmediastate(s);
 
-       /*
-        * We must go through the motions of reading all
-        * supported media because we need to know both
-        * the current media type and the top-level type.
-        */
-
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
-               err(1, "SIOCGIFMEDIA");
-
-       if (ifmr.ifm_count == 0)
-               errx(1, "%s: no media types?", name);
-
-       mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
-       if (mwords == NULL)
-               err(1, "malloc");
-
-       ifmr.ifm_ulist = mwords;
-       if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
-               err(1, "SIOCGIFMEDIA");
-
-       mode = get_media_mode(IFM_TYPE(mwords[0]), val);
-
-       free(mwords);
+       mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
 
        strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       ifr.ifr_media = (ifmr.ifm_current & ~IFM_MMASK) | mode;
+       ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
 
-       if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
-               err(1, "SIOCSIFMEDIA (mode)");
+       ifmr->ifm_current = ifr.ifr_media;
+       callback_register(setifmediacallback, (void *)ifmr);
 }
 
 /**********************************************************************
@@ -405,7 +384,6 @@ struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
 struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
     IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
 
-#if notyet
 static struct ifmedia_description ifm_subtype_atm_descriptions[] =
     IFM_SUBTYPE_ATM_DESCRIPTIONS;
 
@@ -414,7 +392,6 @@ static struct ifmedia_description ifm_subtype_atm_aliases[] =
 
 static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
     IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
-#endif
 
 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
@@ -516,17 +493,13 @@ static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
                {
                        { &ifm_subtype_shared_descriptions[0], 0 },
                        { &ifm_subtype_shared_aliases[0], 1 },
-#if notyet
                        { &ifm_subtype_atm_descriptions[0], 0 },
                        { &ifm_subtype_atm_aliases[0], 1 },
-#endif
                        { NULL, 0 },
                },
                {
                        { &ifm_shared_option_descriptions[0], 0 },
-#if notyet
                        { &ifm_subtype_atm_option_descriptions[0], 0 },
-#endif
                        { NULL, 0 },
                },
                {
@@ -634,8 +607,7 @@ lookup_media_word(struct ifmedia_description *desc, const char *val)
        return (-1);
 }
 
-static struct ifmedia_description *
-get_toptype_desc(int ifmw)
+static struct ifmedia_description *get_toptype_desc(int ifmw)
 {
        struct ifmedia_description *desc;
 
@@ -646,8 +618,7 @@ get_toptype_desc(int ifmw)
        return desc;
 }
 
-static struct ifmedia_type_to_subtype *
-get_toptype_ttos(int ifmw)
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
 {
        struct ifmedia_description *desc;
        struct ifmedia_type_to_subtype *ttos;
@@ -660,8 +631,8 @@ get_toptype_ttos(int ifmw)
        return ttos;
 }
 
-static struct ifmedia_description *
-get_subtype_desc(int ifmw, struct ifmedia_type_to_subtype *ttos)
+static struct ifmedia_description *get_subtype_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
 {
        int i;
        struct ifmedia_description *desc;
@@ -679,8 +650,8 @@ get_subtype_desc(int ifmw, struct ifmedia_type_to_subtype *ttos)
        return NULL;
 }
 
-static struct ifmedia_description *
-get_mode_desc(int ifmw, struct ifmedia_type_to_subtype *ttos)
+static struct ifmedia_description *get_mode_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
 {
        int i;
        struct ifmedia_description *desc;
@@ -810,3 +781,27 @@ print_media_word_ifconfig(int ifmw)
 /**********************************************************************
  * ...until here.
  **********************************************************************/
+
+static struct cmd media_cmds[] = {
+       DEF_CMD_ARG("media",    setmedia),
+       DEF_CMD_ARG("mode",     setmediamode),
+       DEF_CMD_ARG("mediaopt", setmediaopt),
+       DEF_CMD_ARG("-mediaopt",unsetmediaopt),
+};
+static struct afswtch af_media = {
+       .af_name        = "af_media",
+       .af_af          = AF_UNSPEC,
+       .af_other_status = media_status,
+};
+
+static __constructor void
+ifmedia_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(media_cmds);  i++)
+               cmd_register(&media_cmds[i]);
+       af_register(&af_media);
+#undef N
+}
index 5cdfb0a..56f9be2 100644 (file)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifvlan.c,v 1.2 1999/08/28 00:13:09 peter Exp $
- * $DragonFly: src/sbin/ifconfig/ifvlan.c,v 1.7 2005/11/06 12:21:42 swildner Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifvlan.c,v 1.7.2.4 2006/02/09 10:48:43 yar Exp $
+ * $DragonFly: src/sbin/ifconfig/ifvlan.c,v 1.8 2006/04/02 03:33:59 sephe Exp $
  */
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
-#include <sys/mbuf.h>
 
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "ifconfig.h"
 
-static int                     __tag = 0;
+static struct vlanreq          __vreq;
+static int                     __have_dev = 0;
 static int                     __have_tag = 0;
 
-void
-vlan_status(int s, struct rt_addrinfo *info __unused)
+static void
+vlan_status(int s)
 {
        struct vlanreq          vreq;
 
-       bzero((char *)&vreq, sizeof(struct vlanreq));
+       bzero((char *)&vreq, sizeof(vreq));
        ifr.ifr_data = (caddr_t)&vreq;
 
        if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
@@ -75,75 +75,93 @@ vlan_status(int s, struct rt_addrinfo *info __unused)
        printf("\tvlan: %d parent interface: %s\n",
            vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
            "<none>" : vreq.vlr_parent);
-
-       return;
 }
 
-void
-setvlantag(const char *val, int d __unused, int s,
-          const struct afswtch *afp __unused)
+static void
+setvlantag(const char *val, int d, int s, const struct afswtch *afp)
 {
-       u_int16_t               tag;
-       struct vlanreq          vreq;
-
-       __tag = tag = atoi(val);
+       char                    *endp;
+       u_long                  ul;
+
+       ul = strtoul(val, &endp, 0);
+       if (*endp != '\0')
+               errx(1, "invalid value for vlan");
+       __vreq.vlr_tag = ul;
+       /* check if the value can be represented in vlr_tag */
+       if (__vreq.vlr_tag != ul)
+               errx(1, "value for vlan out of range");
+       /* the kernel will do more specific checks on vlr_tag */
        __have_tag = 1;
+}
 
-       bzero((char *)&vreq, sizeof(struct vlanreq));
-       ifr.ifr_data = (caddr_t)&vreq;
-
-       if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
-               err(1, "SIOCGETVLAN");
-
-       vreq.vlr_tag = tag;
-
-       if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
-               err(1, "SIOCSETVLAN");
+static void
+setvlandev(const char *val, int d, int s, const struct afswtch *afp)
+{
 
-       return;
+       strncpy(__vreq.vlr_parent, val, sizeof(__vreq.vlr_parent));
+       __have_dev = 1;
 }
 
-void
-setvlandev(const char *val, int d __unused, int s,
-          const struct afswtch *afp __unused)
+static void
+unsetvlandev(const char *val, int d, int s, const struct afswtch *afp)
 {
-       struct vlanreq          vreq;
 
-       if (!__have_tag)
-               errx(1, "must specify both vlan tag and device");
-
-       bzero((char *)&vreq, sizeof(struct vlanreq));
-       ifr.ifr_data = (caddr_t)&vreq;
+       if (val != NULL)
+               warnx("argument to -vlandev is useless and hence deprecated");
 
+       bzero((char *)&__vreq, sizeof(__vreq));
+       ifr.ifr_data = (caddr_t)&__vreq;
+#if 0  /* this code will be of use when we can alter vlan or vlandev only */
        if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
                err(1, "SIOCGETVLAN");
 
-       strncpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
-       vreq.vlr_tag = __tag;
-
+       bzero((char *)&__vreq.vlr_parent, sizeof(__vreq.vlr_parent));
+       __vreq.vlr_tag = 0; /* XXX clear parent only (no kernel support now) */
+#endif
        if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
                err(1, "SIOCSETVLAN");
-
-       return;
+       __have_dev = __have_tag = 0;
 }
 
-void
-unsetvlandev(const char *val __unused, int d __unused, int s,
-            const struct afswtch *afp __unused)
+static void
+vlan_cb(int s, void *arg)
 {
-       struct vlanreq          vreq;
-
-       bzero((char *)&vreq, sizeof(struct vlanreq));
-       ifr.ifr_data = (caddr_t)&vreq;
 
-       if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
-               err(1, "SIOCGETVLAN");
+       if (__have_tag ^ __have_dev)
+               errx(1, "both vlan and vlandev must be specified");
 
-       bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
-       vreq.vlr_tag = 0;
-
-       if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
-               err(1, "SIOCSETVLAN");
+       if (__have_tag && __have_dev) {
+               ifr.ifr_data = (caddr_t)&__vreq;
+               if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+                       err(1, "SIOCSETVLAN");
+       }
+}
 
-       return;
+static struct cmd vlan_cmds[] = {
+       DEF_CMD_ARG("vlan",                             setvlantag),
+       DEF_CMD_ARG("vlandev",                          setvlandev),
+       /* XXX For compatibility.  Should become DEF_CMD() some day. */
+       DEF_CMD_OPTARG("-vlandev",                      unsetvlandev),
+       DEF_CMD("vlanmtu",      IFCAP_VLAN_MTU,         setifcap),
+       DEF_CMD("-vlanmtu",     -IFCAP_VLAN_MTU,        setifcap),
+       DEF_CMD("vlanhwtag",    IFCAP_VLAN_HWTAGGING,   setifcap),
+       DEF_CMD("-vlanhwtag",   -IFCAP_VLAN_HWTAGGING,  setifcap),
+};
+static struct afswtch af_vlan = {
+       .af_name        = "af_vlan",
+       .af_af          = AF_UNSPEC,
+       .af_other_status = vlan_status,
+};
+
+static __constructor void
+vlan_ctor(void)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       int i;
+
+       for (i = 0; i < N(vlan_cmds);  i++)
+               cmd_register(&vlan_cmds[i]);
+       af_register(&af_vlan);
+       callback_register(vlan_cb, NULL);
+#undef N
 }
index c647582..460c9f6 100644 (file)
@@ -1,6 +1,6 @@
 /*     $NetBSD: if_media.h,v 1.3 1997/03/26 01:19:27 thorpej Exp $     */
 /* $FreeBSD: src/sys/net/if_media.h,v 1.9.2.4 2002/07/30 06:22:40 imp Exp $ */
-/* $DragonFly: src/sys/net/if_media.h,v 1.8 2005/02/14 16:21:34 joerg Exp $ */
+/* $DragonFly: src/sys/net/if_media.h,v 1.9 2006/04/02 03:33:59 sephe Exp $ */
 
 /*
  * Copyright (c) 1997
@@ -204,6 +204,24 @@ int        ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr,
 #define        IFM_IEEE80211_11G       0x00030000      /* 2Ghz, CCK mode */
 #define        IFM_IEEE80211_FH        0x00040000      /* 2Ghz, GFSK mode */
 
+/*
+ * ATM
+ */
+#define IFM_ATM                        0x000000a0
+#define IFM_ATM_UNKNOWN                3
+#define IFM_ATM_UTP_25         4
+#define IFM_ATM_TAXI_100       5
+#define IFM_ATM_TAXI_140       6
+#define IFM_ATM_MM_155         7
+#define IFM_ATM_SM_155         8
+#define IFM_ATM_UTP_155                9
+#define IFM_ATM_MM_622         10
+#define IFM_ATM_SM_622         11
+#define IFM_ATM_VIRTUAL                12
+#define IFM_ATM_SDH            0x00000100      /* SDH instead of SONET */
+#define IFM_ATM_NOSCRAMB       0x00000200      /* no scrambling */
+#define IFM_ATM_UNASSIGNED     0x00000400      /* unassigned cells */
+
 /*
  * Shared media sub-types
  */
@@ -429,6 +447,56 @@ struct ifmedia_description {
        { 0, NULL },                                                    \
 }
 
+#define        IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS {                       \
+       { IFM_AUTO, "autoselect" },                                     \
+       { IFM_IEEE80211_11A, "11a" },                                   \
+       { IFM_IEEE80211_11B, "11b" },                                   \
+       { IFM_IEEE80211_11G, "11g" },                                   \
+       { IFM_IEEE80211_FH, "fh" },                                     \
+       { 0, NULL },                                                    \
+}
+
+#define        IFM_SUBTYPE_IEEE80211_MODE_ALIASES {                            \
+       { IFM_AUTO, "auto" },                                           \
+       { 0, NULL },                                                    \
+}
+
+# define IFM_SUBTYPE_ATM_DESCRIPTIONS {                                        \
+       { IFM_ATM_UNKNOWN,      "Unknown" },                            \
+       { IFM_ATM_UTP_25,       "UTP/25.6MBit" },                       \
+       { IFM_ATM_TAXI_100,     "Taxi/100MBit" },                       \
+       { IFM_ATM_TAXI_140,     "Taxi/140MBit" },                       \
+       { IFM_ATM_MM_155,       "Multi-mode/155MBit" },                 \
+       { IFM_ATM_SM_155,       "Single-mode/155MBit" },                \
+       { IFM_ATM_UTP_155,      "UTP/155MBit" },                        \
+       { IFM_ATM_MM_622,       "Multi-mode/622MBit" },                 \
+       { IFM_ATM_SM_622,       "Single-mode/622MBit" },                \
+       { IFM_ATM_VIRTUAL,      "Virtual" },                            \
+       { 0, NULL },                                                    \
+}
+
+# define IFM_SUBTYPE_ATM_ALIASES {                                     \
+       { IFM_ATM_UNKNOWN,      "UNKNOWN" },                            \
+       { IFM_ATM_UTP_25,       "UTP-25" },                             \
+       { IFM_ATM_TAXI_100,     "TAXI-100" },                           \
+       { IFM_ATM_TAXI_140,     "TAXI-140" },                           \
+       { IFM_ATM_MM_155,       "MM-155" },                             \
+       { IFM_ATM_SM_155,       "SM-155" },                             \
+       { IFM_ATM_UTP_155,      "UTP-155" },                            \
+       { IFM_ATM_MM_622,       "MM-622" },                             \
+       { IFM_ATM_SM_622,       "SM-622" },                             \
+       { IFM_ATM_VIRTUAL,      "VIRTUAL" },                            \
+       { 0, NULL },                                                    \
+}
+
+#define        IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS {                           \
+       { IFM_ATM_SDH, "SDH" },                                         \
+       { IFM_ATM_NOSCRAMB, "Noscramb" },                               \
+       { IFM_ATM_UNASSIGNED, "Unassigned" },                           \
+       { 0, NULL },                                                    \
+}
+
+
 #define        IFM_SUBTYPE_SHARED_DESCRIPTIONS {                               \
        { IFM_AUTO,     "autoselect" },                                 \
        { IFM_MANUAL,   "manual" },                                     \