diff options
-rw-r--r-- | sbin/ifconfig/Makefile | 49 | ||||
-rw-r--r-- | sbin/ifconfig/af_atalk.c | 184 | ||||
-rw-r--r-- | sbin/ifconfig/af_inet.c | 198 | ||||
-rw-r--r-- | sbin/ifconfig/af_inet6.c | 547 | ||||
-rw-r--r-- | sbin/ifconfig/af_ipx.c | 128 | ||||
-rw-r--r-- | sbin/ifconfig/af_link.c | 125 | ||||
-rw-r--r-- | sbin/ifconfig/ifclone.c | 155 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.8 | 215 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 1611 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.h | 124 | ||||
-rw-r--r-- | sbin/ifconfig/ifieee80211.c | 1444 | ||||
-rw-r--r-- | sbin/ifconfig/ifmac.c | 27 | ||||
-rw-r--r-- | sbin/ifconfig/ifmedia.c | 36 | ||||
-rw-r--r-- | sbin/ifconfig/ifvlan.c | 37 |
14 files changed, 3342 insertions, 1538 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile index 252f8b6..117441b 100644 --- a/sbin/ifconfig/Makefile +++ b/sbin/ifconfig/Makefile @@ -2,35 +2,36 @@ # $FreeBSD$ PROG= ifconfig -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 - -#comment out to exclude MAC support -SRCS+= ifmac.c -CFLAGS+=-DUSE_MAC - -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 + +.if !defined(RELEASE_CRUNCH) +SRCS+= af_ipx.c # IPX support DPADD= ${LIBIPX} LDADD= -lipx .endif -CFLAGS+=-DNS -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings \ +MAN= ifconfig.8 + +CFLAGS+= -g -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings \ -Wnested-externs -I.. WARNS?= 0 diff --git a/sbin/ifconfig/af_atalk.c b/sbin/ifconfig/af_atalk.c new file mode 100644 index 0000000..0ceb8b9 --- /dev/null +++ b/sbin/ifconfig/af_atalk.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/route.h> /* for RTX_IFA */ + +#include <netatalk/at.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <arpa/inet.h> + +#include "ifconfig.h" + +static struct netrange at_nr; /* AppleTalk net range */ +static struct ifaliasreq at_addreq; + +/* XXX FIXME -- should use strtoul for better parsing. */ +static void +setatrange(const char *range, int dummy __unused, int s, + const struct afswtch *afp) +{ + u_int first = 123, last = 123; + + if (sscanf(range, "%u-%u", &first, &last) != 2 + || first == 0 || first > 0xffff + || last == 0 || last > 0xffff || first > last) + errx(1, "%s: illegal net range: %u-%u", range, first, last); + at_nr.nr_firstnet = htons(first); + at_nr.nr_lastnet = htons(last); +} + +static void +setatphase(const char *phase, int dummy __unused, int s, + const struct afswtch *afp) +{ + if (!strcmp(phase, "1")) + at_nr.nr_phase = 1; + else if (!strcmp(phase, "2")) + at_nr.nr_phase = 2; + else + errx(1, "%s: illegal phase", phase); +} + +static void +at_status(int s __unused, const struct rt_addrinfo * info) +{ + struct sockaddr_at *sat, null_sat; + struct netrange *nr; + + memset(&null_sat, 0, sizeof(null_sat)); + + sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA]; + if (sat == NULL) + return; + nr = &sat->sat_range.r_netrange; + printf("\tatalk %d.%d range %d-%d phase %d", + ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, + ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase); + if (flags & IFF_POINTOPOINT) { + /* note RTAX_BRD overlap with IFF_BROADCAST */ + sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD]; + if (!sat) + sat = &null_sat; + printf("--> %d.%d", + ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); + } + if (flags & IFF_BROADCAST) { + /* note RTAX_BRD overlap with IFF_POINTOPOINT */ + sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD]; + if (sat) + printf(" broadcast %d.%d", + ntohs(sat->sat_addr.s_net), + sat->sat_addr.s_node); + } + + putchar('\n'); +} + +static void +at_getaddr(const char *addr, int which) +{ + struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr; + u_int net, node; + + sat->sat_family = AF_APPLETALK; + sat->sat_len = sizeof(*sat); + if (which == MASK) + errx(1, "AppleTalk does not use netmasks"); + if (sscanf(addr, "%u.%u", &net, &node) != 2 + || net > 0xffff || node > 0xfe) + errx(1, "%s: illegal address", addr); + sat->sat_addr.s_net = htons(net); + sat->sat_addr.s_node = node; +} + +static void +at_postproc(int s, const struct afswtch *afp) +{ + struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr; + + if (at_nr.nr_phase == 0) + at_nr.nr_phase = 2; /* Default phase 2 */ + if (at_nr.nr_firstnet == 0) + at_nr.nr_firstnet = /* Default range of one */ + at_nr.nr_lastnet = sat->sat_addr.s_net; + printf("\tatalk %d.%d range %d-%d phase %d\n", + ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, + ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), + at_nr.nr_phase); + if ((u_short) ntohs(at_nr.nr_firstnet) > + (u_short) ntohs(sat->sat_addr.s_net) + || (u_short) ntohs(at_nr.nr_lastnet) < + (u_short) ntohs(sat->sat_addr.s_net)) + errx(1, "AppleTalk address is not in range"); + sat->sat_range.r_netrange = at_nr; +} + +static struct cmd atalk_cmds[] = { + DEF_CMD_ARG("range", setatrange), + DEF_CMD_ARG("phase", setatphase), +}; + +static struct afswtch af_atalk = { + .af_name = "atalk", + .af_af = AF_APPLETALK, + .af_status = at_status, + .af_getaddr = at_getaddr, + .af_postproc = at_postproc, + .af_difaddr = SIOCDIFADDR, + .af_aifaddr = SIOCAIFADDR, + .af_ridreq = &at_addreq, + .af_addreq = &at_addreq, +}; + +static __constructor void +atalk_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(atalk_cmds); i++) + cmd_register(&atalk_cmds[i]); + af_register(&af_atalk); +#undef N +} diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c new file mode 100644 index 0000000..4a8e3a1 --- /dev/null +++ b/sbin/ifconfig/af_inet.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/route.h> /* for RTX_IFA */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <netinet/in.h> +#include <net/if_var.h> /* for struct ifaddr */ +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "ifconfig.h" + +static struct ifaliasreq in_addreq; +static struct ifreq in_ridreq; + +static void +in_status(int s __unused, const struct rt_addrinfo * info) +{ + struct sockaddr_in *sin, null_sin; + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA]; + if (sin == NULL) + return; + + printf("\tinet %s ", inet_ntoa(sin->sin_addr)); + + if (flags & IFF_POINTOPOINT) { + /* note RTAX_BRD overlap with IFF_BROADCAST */ + sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; + if (!sin) + sin = &null_sin; + printf("--> %s ", inet_ntoa(sin->sin_addr)); + } + + sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK]; + if (!sin) + sin = &null_sin; + printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); + + if (flags & IFF_BROADCAST) { + /* note RTAX_BRD overlap with IFF_POINTOPOINT */ + sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; + if (sin && sin->sin_addr.s_addr != 0) + printf("broadcast %s", inet_ntoa(sin->sin_addr)); + } + putchar('\n'); +} + +#define SIN(x) ((struct sockaddr_in *) &(x)) +static struct sockaddr_in *sintab[] = { + SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), + SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) +}; + +static void +in_getaddr(const char *s, int which) +{ +#define MIN(a,b) ((a)<(b)?(a):(b)) + struct sockaddr_in *sin = sintab[which]; + struct hostent *hp; + struct netent *np; + + sin->sin_len = sizeof(*sin); + if (which != MASK) + sin->sin_family = AF_INET; + + if (which == ADDR) { + char *p = NULL; + + if((p = strrchr(s, '/')) != NULL) { + /* address is `name/masklen' */ + int masklen; + int ret; + struct sockaddr_in *min = sintab[MASK]; + *p = '\0'; + ret = sscanf(p+1, "%u", &masklen); + if(ret != 1 || (masklen < 0 || masklen > 32)) { + *p = '/'; + errx(1, "%s: bad value", s); + } + min->sin_len = sizeof(*min); + min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & + 0xffffffff); + } + } + + if (inet_aton(s, &sin->sin_addr)) + return; + if ((hp = gethostbyname(s)) != 0) + bcopy(hp->h_addr, (char *)&sin->sin_addr, + MIN(hp->h_length, sizeof(sin->sin_addr))); + else if ((np = getnetbyname(s)) != 0) + sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); + else + errx(1, "%s: bad value", s); +#undef MIN +} + +static void +in_status_tunnel(int s) +{ + char src[NI_MAXHOST]; + char dst[NI_MAXHOST]; + struct ifreq ifr; + const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) + return; + if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) + src[0] = '\0'; + + if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) + return; + if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) + dst[0] = '\0'; + + printf("\ttunnel inet %s --> %s\n", src, dst); +} + +static void +in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) +{ + struct ifaliasreq addreq; + + memset(&addreq, 0, sizeof(addreq)); + strncpy(addreq.ifra_name, name, IFNAMSIZ); + memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); + memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) + warn("SIOCSIFPHYADDR"); +} + +static struct afswtch af_inet = { + .af_name = "inet", + .af_af = AF_INET, + .af_status = in_status, + .af_getaddr = in_getaddr, + .af_status_tunnel = in_status_tunnel, + .af_settunnel = in_set_tunnel, + .af_difaddr = SIOCDIFADDR, + .af_aifaddr = SIOCAIFADDR, + .af_ridreq = &in_ridreq, + .af_addreq = &in_addreq, +}; + +static __constructor void +inet_ctor(void) +{ + af_register(&af_inet); +} diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c new file mode 100644 index 0000000..77ad5fc --- /dev/null +++ b/sbin/ifconfig/af_inet6.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/route.h> /* for RTX_IFA */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ifaddrs.h> + +#include <arpa/inet.h> + +#include <netinet/in.h> +#include <net/if_var.h> /* for struct ifaddr */ +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */ + +#include "ifconfig.h" + +/* wrapper for KAME-special getnameinfo() */ +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + +static struct in6_ifreq in6_ridreq; +static struct in6_aliasreq in6_addreq = + { { 0 }, + { 0 }, + { 0 }, + { 0 }, + 0, + { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; +static int ip6lifetime; + +static void in6_fillscopeid(struct sockaddr_in6 *sin6); +static int prefix(void *, int); +static char *sec2str(time_t); +static int explicit_prefix = 0; + +static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ + +static void +setifprefixlen(const char *addr, int dummy __unused, int s, + const struct afswtch *afp) +{ + if (afp->af_getprefix != NULL) + afp->af_getprefix(addr, MASK); + explicit_prefix = 1; +} + +static void +setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused, + const struct afswtch *afp) +{ + if (afp->af_af != AF_INET6) + err(1, "address flags can be set only for inet6 addresses"); + + if (flag < 0) + in6_addreq.ifra_flags &= ~(-flag); + else + in6_addreq.ifra_flags |= flag; +} + +static void +setip6lifetime(const char *cmd, const char *val, int s, + const struct afswtch *afp) +{ + time_t newval, t; + char *ep; + + t = time(NULL); + newval = (time_t)strtoul(val, &ep, 0); + if (val == ep) + errx(1, "invalid %s", cmd); + if (afp->af_af != AF_INET6) + errx(1, "%s not allowed for the AF", cmd); + if (strcmp(cmd, "vltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_expire = t + newval; + in6_addreq.ifra_lifetime.ia6t_vltime = newval; + } else if (strcmp(cmd, "pltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; + in6_addreq.ifra_lifetime.ia6t_pltime = newval; + } +} + +static void +setip6pltime(const char *seconds, int dummy __unused, int s, + const struct afswtch *afp) +{ + setip6lifetime("pltime", seconds, s, afp); +} + +static void +setip6vltime(const char *seconds, int dummy __unused, int s, + const struct afswtch *afp) +{ + setip6lifetime("vltime", seconds, s, afp); +} + +static void +setip6eui64(const char *cmd, int dummy __unused, int s, + const struct afswtch *afp) +{ + struct ifaddrs *ifap, *ifa; + const struct sockaddr_in6 *sin6 = NULL; + const struct in6_addr *lladdr = NULL; + struct in6_addr *in6; + + if (afp->af_af != AF_INET6) + errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); + in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; + if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) + errx(EXIT_FAILURE, "interface index is already filled"); + if (getifaddrs(&ifap) != 0) + err(EXIT_FAILURE, "getifaddrs"); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_INET6 && + strcmp(ifa->ifa_name, name) == 0) { + sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + lladdr = &sin6->sin6_addr; + break; + } + } + } + if (!lladdr) + errx(EXIT_FAILURE, "could not determine link local address"); + + memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); + + freeifaddrs(ifap); +} + +static void +in6_fillscopeid(struct sockaddr_in6 *sin6) +{ +#if defined(__KAME__) && defined(KAME_SCOPEID) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} + +static void +in6_status(int s __unused, const struct rt_addrinfo * info) +{ + struct sockaddr_in6 *sin, null_sin; + struct in6_ifreq ifr6; + int s6; + u_int32_t flags6; + struct in6_addrlifetime lifetime; + time_t t = time(NULL); + int error; + u_int32_t scopeid; + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA]; + if (sin == NULL) + return; + + strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + warn("socket(AF_INET6,SOCK_DGRAM)"); + return; + } + ifr6.ifr_addr = *sin; + if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + warn("ioctl(SIOCGIFAFLAG_IN6)"); + close(s6); + return; + } + flags6 = ifr6.ifr_ifru.ifru_flags6; + memset(&lifetime, 0, sizeof(lifetime)); + ifr6.ifr_addr = *sin; + if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { + warn("ioctl(SIOCGIFALIFETIME_IN6)"); + close(s6); + return; + } + lifetime = ifr6.ifr_ifru.ifru_lifetime; + close(s6); + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && + *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { + u_short index; + + index = *(u_short *)&sin->sin6_addr.s6_addr[2]; + *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = ntohs(index); + } + scopeid = sin->sin6_scope_id; + + error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, + sizeof(addr_buf), NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + if (error != 0) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("\tinet6 %s ", addr_buf); + + if (flags & IFF_POINTOPOINT) { + /* note RTAX_BRD overlap with IFF_BROADCAST */ + sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD]; + /* + * some of the interfaces do not have valid destination + * address. + */ + if (sin && sin->sin6_family == AF_INET6) { + int error; + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && + *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { + u_short index; + + index = *(u_short *)&sin->sin6_addr.s6_addr[2]; + *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = ntohs(index); + } + + error = getnameinfo((struct sockaddr *)sin, + sin->sin6_len, addr_buf, + sizeof(addr_buf), NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + if (error != 0) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("--> %s ", addr_buf); + } + } + + sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK]; + if (!sin) + sin = &null_sin; + printf("prefixlen %d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); + + if ((flags6 & IN6_IFF_ANYCAST) != 0) + printf("anycast "); + if ((flags6 & IN6_IFF_TENTATIVE) != 0) + printf("tentative "); + if ((flags6 & IN6_IFF_DUPLICATED) != 0) + printf("duplicated "); + if ((flags6 & IN6_IFF_DETACHED) != 0) + printf("detached "); + if ((flags6 & IN6_IFF_DEPRECATED) != 0) + printf("deprecated "); + if ((flags6 & IN6_IFF_AUTOCONF) != 0) + printf("autoconf "); + if ((flags6 & IN6_IFF_TEMPORARY) != 0) + printf("temporary "); + + if (scopeid) + printf("scopeid 0x%x ", scopeid); + + if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { + printf("pltime "); + if (lifetime.ia6t_preferred) { + printf("%s ", lifetime.ia6t_preferred < t + ? "0" : sec2str(lifetime.ia6t_preferred - t)); + } else + printf("infty "); + + printf("vltime "); + if (lifetime.ia6t_expire) { + printf("%s ", lifetime.ia6t_expire < t + ? "0" : sec2str(lifetime.ia6t_expire - t)); + } else + printf("infty "); + } + + putchar('\n'); +} + +#define SIN6(x) ((struct sockaddr_in6 *) &(x)) +static struct sockaddr_in6 *sin6tab[] = { + SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), + SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr) +}; + +static void +in6_getprefix(const char *plen, int which) +{ + struct sockaddr_in6 *sin = sin6tab[which]; + u_char *cp; + int len = atoi(plen); + + if ((len < 0) || (len > 128)) + errx(1, "%s: bad value", plen); + sin->sin6_len = sizeof(*sin); + if (which != MASK) + sin->sin6_family = AF_INET6; + if ((len == 0) || (len == 128)) { + memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); + return; + } + memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr)); + for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) + *cp++ = 0xff; + *cp = 0xff << (8 - len); +} + +static void +in6_getaddr(const char *s, int which) +{ + struct sockaddr_in6 *sin = sin6tab[which]; + struct addrinfo hints, *res; + int error = -1; + + newaddr &= 1; + + sin->sin6_len = sizeof(*sin); + if (which != MASK) + sin->sin6_family = AF_INET6; + + if (which == ADDR) { + char *p = NULL; + if((p = strrchr(s, '/')) != NULL) { + *p = '\0'; + in6_getprefix(p + 1, MASK); + explicit_prefix = 1; + } + } + + if (sin->sin6_family == AF_INET6) { + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_INET6; + error = getaddrinfo(s, NULL, &hints, &res); + } + if (error != 0) { + if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) + errx(1, "%s: bad value", s); + } else + bcopy(res->ai_addr, sin, res->ai_addrlen); +} + +static int +prefix(void *val, int size) +{ + u_char *name = (u_char *)val; + int byte, bit, plen = 0; + + for (byte = 0; byte < size; byte++, plen += 8) + if (name[byte] != 0xff) + break; + if (byte == size) + return (plen); + for (bit = 7; bit != 0; bit--, plen++) + if (!(name[byte] & (1 << bit))) + break; + for (; bit != 0; bit--) + if (name[byte] & (1 << bit)) + return(0); + byte++; + for (; byte < size; byte++) + if (name[byte]) + return(0); + return (plen); +} + +static char * +sec2str(time_t total) +{ + static char result[256]; + int days, hours, mins, secs; + int first = 1; + char *p = result; + + if (0) { + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += sprintf(p, "%dd", days); + } + if (!first || hours) { + first = 0; + p += sprintf(p, "%dh", hours); + } + if (!first || mins) { + first = 0; + p += sprintf(p, "%dm", mins); + } + sprintf(p, "%ds", secs); + } else + sprintf(result, "%lu", (unsigned long)total); + + return(result); +} + +static void +in6_postproc(int s, const struct afswtch *afp) +{ + if (explicit_prefix == 0) { + /* Aggregatable address architecture defines all prefixes + are 64. So, it is convenient to set prefixlen to 64 if + it is not specified. */ + setifprefixlen("64", 0, s, afp); + /* in6_getprefix("64", MASK) if MASK is available here... */ + } +} + +static void +in6_status_tunnel(int s) +{ + char src[NI_MAXHOST]; + char dst[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif + struct in6_ifreq in6_ifr; + const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr; + + memset(&in6_ifr, 0, sizeof(in6_ifr)); + strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0) + return; + if (sa->sa_family == AF_INET6) + in6_fillscopeid(&in6_ifr.ifr_addr); + if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, niflag) != 0) + src[0] = '\0'; + + if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0) + return; + if (sa->sa_family == AF_INET6) + in6_fillscopeid(&in6_ifr.ifr_addr); + if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, niflag) != 0) + dst[0] = '\0'; + + printf("\ttunnel inet6 %s --> %s\n", src, dst); +} + +static void +in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) +{ + struct in6_aliasreq in6_addreq; + + memset(&in6_addreq, 0, sizeof(in6_addreq)); + strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); + memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); + memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) + warn("SIOCSIFPHYADDR_IN6"); +} + +static struct cmd inet6_cmds[] = { + DEF_CMD_ARG("prefixlen", setifprefixlen), + DEF_CMD("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 index 0000000..d16e2eb --- /dev/null +++ b/sbin/ifconfig/af_ipx.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/route.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <net/if_var.h> +#define IPXIP +#define IPTUNNEL +#include <netipx/ipx.h> +#include <netipx/ipx_if.h> + +#include "ifconfig.h" + +static struct ifaliasreq ipx_addreq; +static struct ifreq ipx_ridreq; + +static void +ipx_status(int s __unused, const struct rt_addrinfo * info) +{ + struct sockaddr_ipx *sipx, null_sipx; + + sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA]; + if (sipx == NULL) + return; + + printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr)); + + if (flags & IFF_POINTOPOINT) { + sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD]; + if (!sipx) { + memset(&null_sipx, 0, sizeof(null_sipx)); + sipx = &null_sipx; + } + printf("--> %s ", ipx_ntoa(sipx->sipx_addr)); + } + putchar('\n'); +} + +#define SIPX(x) ((struct sockaddr_ipx *) &(x)) +struct sockaddr_ipx *sipxtab[] = { + SIPX(ipx_ridreq.ifr_addr), SIPX(ipx_addreq.ifra_addr), + SIPX(ipx_addreq.ifra_mask), SIPX(ipx_addreq.ifra_broadaddr) +}; + +static void +ipx_getaddr(const char *addr, int which) +{ + struct sockaddr_ipx *sipx = sipxtab[which]; + + sipx->sipx_family = AF_IPX; + sipx->sipx_len = sizeof(*sipx); + sipx->sipx_addr = ipx_addr(addr); + if (which == MASK) + printf("Attempt to set IPX netmask will be ineffectual\n"); +} + +static void +ipx_postproc(int s, const struct afswtch *afp) +{ + if (setipdst) { + struct ipxip_req rq; + int size = sizeof(rq); + + rq.rq_ipx = ipx_addreq.ifra_addr; + rq.rq_ip = ipx_addreq.ifra_dstaddr; + + if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0) + Perror("Encapsulation Routing"); + } +} + +static struct afswtch af_ipx = { + .af_name = "ipx", + .af_af = AF_IPX, + .af_status = ipx_status, + .af_getaddr = ipx_getaddr, + .af_postproc = ipx_postproc, + .af_difaddr = SIOCDIFADDR, + .af_aifaddr = SIOCAIFADDR, + .af_ridreq = &ipx_ridreq, + .af_addreq = &ipx_addreq, +}; + +static __constructor void +ipx_ctor(void) +{ + af_register(&af_ipx); +} diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c new file mode 100644 index 0000000..9daef02 --- /dev/null +++ b/sbin/ifconfig/af_link.c @@ -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. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <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; + + if (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/ifclone.c b/sbin/ifconfig/ifclone.c new file mode 100644 index 0000000..8b613ad --- /dev/null +++ b/sbin/ifconfig/ifclone.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ifconfig.h" + +static void +list_cloners(void) +{ + struct if_clonereq ifcr; + char *cp, *buf; + int idx; + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket(AF_INET,SOCK_DGRAM)"); + + memset(&ifcr, 0, sizeof(ifcr)); + + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) + err(1, "SIOCIFGCLONERS for count"); + + buf = malloc(ifcr.ifcr_total * IFNAMSIZ); + if (buf == NULL) + err(1, "unable to allocate cloner name buffer"); + + ifcr.ifcr_count = ifcr.ifcr_total; + ifcr.ifcr_buffer = buf; + + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) + err(1, "SIOCIFGCLONERS for names"); + + /* + * In case some disappeared in the mean time, clamp it down. + */ + if (ifcr.ifcr_count > ifcr.ifcr_total) + ifcr.ifcr_count = ifcr.ifcr_total; + + for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { + if (idx > 0) + putchar(' '); + printf("%s", cp); + } + + putchar('\n'); + free(buf); +} + +void +clone_create(void) +{ + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket(AF_INET,SOCK_DGRAM)"); + + memset(&ifr, 0, sizeof(ifr)); + (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFCREATE, &ifr) < 0) + err(1, "SIOCIFCREATE"); + + /* + * If we get a different name back then we put in, we probably + * want to print it out, but we might change our mind later so + * we just signal our intrest and leave the printout for later. + */ + if (strcmp(name, ifr.ifr_name) != 0) { + printname = 1; + strlcpy(name, ifr.ifr_name, sizeof(name)); + } + + close(s); +} + +static void +clone_destroy(const char *val, int d, int s, const struct afswtch *rafp) +{ + + (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) + err(1, "SIOCIFDESTROY"); + /* + * If we create and destroy an interface in the same command, + * there isn't any reason to print it's name. + */ + printname = 0; +} + +static struct cmd clone_cmds[] = { + DEF_CMD("destroy", 0, clone_destroy), + DEF_CMD("unplumb", 0, clone_destroy), +}; + +static void +clone_Copt_cb(const char *optarg __unused) +{ + list_cloners(); + exit(0); +} +static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb }; + +static __constructor void +clone_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(clone_cmds); i++) + cmd_register(&clone_cmds[i]); + opt_register(&clone_Copt); +#undef N +} diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 7e31339..57ba50a 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD$ .\" -.Dd July 26, 2004 +.Dd Nov 2, 2004 .Dt IFCONFIG 8 .Os .Sh NAME @@ -55,6 +55,7 @@ .Op Fl d .Op Fl m .Op Fl u +.Op Fl v .Op Ar address_family .Nm .Fl l @@ -66,6 +67,7 @@ .Op Fl d .Op Fl m .Op Fl u +.Op Fl v .Op Fl C .Sh DESCRIPTION The @@ -596,64 +598,101 @@ This may be used to enable an interface after an It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. -.It Cm ssid Ar ssid -For IEEE 802.11 wireless interfaces, set the desired Service Set -Identifier (aka network name). -The SSID is a string up to 32 characters -in length and may be specified as either a normal string or in -hexadecimal when proceeded by -.Ql 0x . -Additionally, the SSID may be cleared by setting it to -.Ql - . -.It Cm nwid Ar ssid -Another name for the -.Cm ssid -parameter. -Included for -.Nx -compatibility. -.It Cm stationname Ar name -For IEEE 802.11 wireless interfaces, set the name of this station. -It appears that the station name is not really part of the IEEE 802.11 -protocol though all interfaces seem to support it. -As such it only -seems to be meaningful to identical or virtually identical equipment. -Setting the station name is identical in syntax to setting the SSID. -.It Cm station Ar name -Another name for the -.Cm stationname -parameter. -Included for -.Bsx -compatibility. -.It Cm channel Ar number -For IEEE 802.11 wireless interfaces, set the desired channel. -Channels range from 1 to 14, but the exact selection available -depends on the region your adaptor was manufactured for. -Setting -the channel to 0 will give you the default for your adaptor. -Many -adaptors ignore this setting unless you are in ad-hoc mode. +.El +.Pp +The following parameters are specific to IEEE 802.11 wireless interfaces: +.Bl -tag -width indent +.It Cm apbridge +When operating as an access point pass packets between +wireless clients directly (default). +To instead let them pass up through the +system and be forwarded using some other mechanism use +.Dq Li -apbridge. +Disabling the internal bridging +is useful when traffic is to be processed with +packet filtering. .It Cm authmode Ar mode -For IEEE 802.11 wireless interfaces, set the desired authentication mode -in infrastructure mode. +Set the desired authentication mode in infrastructure mode. Not all adaptors support all modes. The set of valid modes is .Dq Li none , .Dq Li open , +.Dq Li shared (shared key), +.Dq Li 8021x (IEEE 802.1x), +or +.Dq Li wpa (IEEE WPA/WPA2/802.11i). +The +.Dq Li 8021x and -.Dq Li shared . +.Dq Li wpa +modes are only useful when used an authentication service +(a supplicant for client operation or an authenticator when +operating as an access point). Modes are case insensitive. +.It Cm bssid Ar address +Specify the MAC address of the access point to use when operating +as a station in a BSS network. +This overrides any automatic selection done by the system. +To disable a previously selected access point supply +.Dq Li any , +.Dq Li none , +or +.Dq Li - +for the address. +This option is useful when more than one access points have the same SSID. +Another name for the +.Cm bssid +parameter is +.Cm ap . +.It Cm chanlist Ar channels +Set the desired channels to use when scanning for access +points, neighbors in an IBSS network, or looking for unoccupied +channels when operating as an access point. +The set of channels is specified as a comma-separated list with +each element in the list either a single channel number of a range +of the form +.Dq Li a-b . +Channel numbers must be in the range 1 to 255 and be permissible +according to the operating characteristics of the device. +.It Cm channel Ar number +Set a single desired channel. +Channels range from 1 to 255, but the exact selection available +depends on the region your adaptor was manufactured for. +Setting +the channel to +.Dq Li 0 , +.Dq Li any , +or +.Dq Li - +will give you the default for your adaptor. +Many +adaptors ignore this setting unless you are in ad-hoc mode. +Alternatively the frequency, in megahertz, may be specified +instead of the channel number. +.It Cm hidessid +When operating as an access point do not broadcast the SSID +in beacon frames. +By default the SSID is included in beacon frames. +To re-enable the broadcast of the SSID use +.Fl hidessid . .It Cm powersave -For IEEE 802.11 wireless interfaces, enable powersave mode. -.It Fl powersave -For IEEE 802.11 wireless interfaces, disable powersave mode. +Enable powersave operation. +When operating as a client the station will conserve power by +periodically turning off the radio and listening for +messages from the access point telling it there are packets waiting. +The station must then retrieve the packets. +When operating as an access point the station must honor power +save operation of associated clients. +Not all devices support power save operation, either as a client +or as an access point. +Use +.Fl powersave +to disable powersave operation. .It Cm powersavesleep Ar sleep -For IEEE 802.11 wireless interfaces, set the desired max powersave sleep -time in milliseconds. +Set the desired max powersave sleep time in milliseconds. .It Cm protmode Ar technique -For IEEE 802.11 wireless interfaces operating in 11g, use the specified +For interfaces operating in 802.11g, use the specified .Ar technique for protecting OFDM frames in a mixed 11b/11g network. The set of valid techniques is @@ -664,8 +703,25 @@ and .Dq Li rtscts (RTS/CTS). Technique names are case insensitive. +.It Cm roaming Ar mode +When operating as a station, control how the system will +behave when communication with the current access point +is broken. +.I Mode +may be one of +.Dq Li device +(leave it to the hardware device to decide), +.Dq Li auto +(handle either in the device or the operating system--as appropriate), +.Dq Li manual +(do nothing until explicitly instructed). +By the default the device is left to handle this if it is +capable; otherwise the operating system will automatically +attempt to reestablish communication. +Manual mode is mostly useful when an application wants to +control the selection of an access point. .It Cm rtsthreshold Ar length -For IEEE 802.11 wireless interfaces, set the threshold for which +Set the threshold for which transmitted frames are preceded by transmission of an RTS control frame. @@ -674,8 +730,26 @@ The argument is the frame size in bytes and must be in the range 1 to 2312. Not all adaptors support setting the RTS threshold. +.It Cm ssid Ar ssid +Set the desired Service Set Identifier (aka network name). +The SSID is a string up to 32 characters +in length and may be specified as either a normal string or in +hexadecimal when proceeded by +.Ql 0x . +Additionally, the SSID may be cleared by setting it to +.Ql - . +.It Cm scan +Display the current set of scanned neighbors and/or trigger a new scan. +Only the super-user can trigger a scan. +.It Cm stationname Ar name +Set the name of this station. +It appears that the station name is not really part of the IEEE 802.11 +protocol though all interfaces seem to support it. +As such it only +seems to be meaningful to identical or virtually identical equipment. +Setting the station name is identical in syntax to setting the SSID. .It Cm txpower Ar power -For IEEE 802.11 wireless interfaces, set the power used to transmit frames. +Set the power used to transmit frames. The .Ar power argument @@ -686,7 +760,7 @@ Typically only a few discreet power settings are available and the driver will use the setting closest to the specified value. Not all adaptors support changing the transmit power. .It Cm wepmode Ar mode -For IEEE 802.11 wireless interfaces, set the desired WEP mode. +Set the desired WEP mode. Not all adaptors support all modes. The set of valid modes is .Dq Li off , @@ -706,10 +780,9 @@ is generally another name for .Dq Li mixed . Modes are case insensitive. .It Cm weptxkey Ar index -For IEEE 802.11 wireless interfaces, set the WEP key to be used for -transmission. +Set the WEP key to be used for transmission. .It Cm wepkey Ar key Ns | Ns Ar index : Ns Ar key -For IEEE 802.11 wireless interfaces, set the selected WEP key. +Set the selected WEP key. If an .Ar index is not given, key 1 is set. @@ -732,6 +805,31 @@ Some adaptors support more than four keys. If that is the case, then the first four keys (1-4) will be the standard temporary keys and any others will be adaptor specific keys such as permanent keys stored in NVRAM. +.It Cm wme +Enable Wireless Media Extensions (WME) support, if available, +for the specified interface. +WME is a subset of the IEEE 802.11e standard to support the +efficient communication of realtime and multimedia data. +To disable WME support use +.Fl wme . +.El +.Pp +The following parameters are support for compatibility with other systems: +.Bl -tag -width indent +.It Cm nwid Ar ssid +Another name for the +.Cm ssid +parameter. +Included for +.Nx +compatibility. +.It Cm station Ar name +Another name for the +.Cm stationname +parameter. +Included for +.Bsx +compatibility. .It Cm wep Another way of saying .Cm wepmode on . @@ -746,9 +844,7 @@ Included for compatibility. .It Cm nwkey key Another way of saying: -.Pp .Dq Li "wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-" . -.Pp Included for .Nx compatibility. @@ -758,16 +854,13 @@ compatibility. .Sm on .Xc Another way of saying -.Pp .Dq Li "wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4" . -.Pp Included for .Nx compatibility. .It Fl nwkey Another way of saying .Cm wepmode off . -.Pp Included for .Nx compatibility. @@ -820,6 +913,10 @@ and (only list interfaces that are up). .Pp The +.Fl v +flag may be used to get more verbose status for an interface. +.Pp +The .Fl C flag may be used to list all of the interface cloners available on the system, with no additional information. diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 858b8a4..3725276 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -62,21 +62,6 @@ static const char rcsid[] = #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> - #include <ctype.h> #include <err.h> #include <errno.h> @@ -85,34 +70,15 @@ static const char rcsid[] = #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <ifaddrs.h> #include "ifconfig.h" -/* wrapper for KAME-special getnameinfo() */ -#ifndef NI_WITHSCOPEID -#define NI_WITHSCOPEID 0 -#endif - /* * Since "struct ifreq" is composed of various union members, callers * should pay special attention to interprete the value. * (.e.g. little/big endian difference in the structure.) */ -struct ifreq ifr, ridreq; -struct ifaliasreq addreq; -#ifdef INET6 -struct in6_ifreq in6_ridreq; -struct in6_aliasreq in6_addreq = - { { 0 }, - { 0 }, - { 0 }, - { 0 }, - 0, - { 0, 0, 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; @@ -122,327 +88,78 @@ int setmask; int doalias; int clearaddr; int newaddr = 1; -#ifdef INET6 -static int ip6lifetime; -#endif +int verbose; -struct afswtch; +int supmedia = 0; +int printname = 0; /* Print the name of the created interface. */ -int supmedia = 0; -int listcloners = 0; -int printname = 0; /* Print the name of the created interface. */ - -#ifdef INET6 -char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ -#endif - -void Perror(const char *cmd); -void checkatrange(struct sockaddr_at *); -int ifconfig(int argc, char *const *argv, const struct afswtch *afp); -void notealias(const char *, int, int, const struct afswtch *afp); -void list_cloners(void); -void printb(const char *s, unsigned value, const char *bits); -void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); -void status(const struct afswtch *afp, int addrcount, +static int ifconfig(int argc, char *const *argv, const struct afswtch *afp); +static void status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, struct if_msghdr *ifm, struct ifa_msghdr *ifam); -void tunnel_status(int s); -void usage(void); -void ifmaybeload(char *name); - -#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 } , - { "down", -IFF_UP, setifflags }, - { "arp", -IFF_NOARP, setifflags }, - { "-arp", IFF_NOARP, setifflags }, - { "debug", IFF_DEBUG, setifflags }, - { "-debug", -IFF_DEBUG, setifflags }, - { "promisc", IFF_PPROMISC, setifflags }, - { "-promisc", -IFF_PPROMISC, setifflags }, - { "add", IFF_UP, notealias }, - { "alias", IFF_UP, notealias }, - { "-alias", -IFF_UP, notealias }, - { "delete", -IFF_UP, notealias }, - { "remove", -IFF_UP, notealias }, -#ifdef notdef -#define EN_SWABIPS 0x1000 - { "swabips", EN_SWABIPS, setifflags }, - { "-swabips", -EN_SWABIPS, setifflags }, -#endif - { "netmask", NEXTARG, setifnetmask }, -#ifdef INET6 - { "prefixlen", NEXTARG, setifprefixlen }, - { "anycast", IN6_IFF_ANYCAST, setip6flags }, - { "tentative", IN6_IFF_TENTATIVE, setip6flags }, - { "-tentative", -IN6_IFF_TENTATIVE, setip6flags }, - { "deprecated", IN6_IFF_DEPRECATED, setip6flags }, - { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags }, - { "autoconf", IN6_IFF_AUTOCONF, setip6flags }, - { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags }, - { "pltime", NEXTARG, setip6pltime }, - { "vltime", NEXTARG, setip6vltime }, - { "eui64", 0, setip6eui64 }, -#endif - { "range", NEXTARG, setatrange }, - { "phase", NEXTARG, setatphase }, - { "metric", NEXTARG, setifmetric }, - { "broadcast", NEXTARG, setifbroadaddr }, - { "ipdst", NEXTARG, setifipdst }, - { "tunnel", NEXTARG2, NULL, settunnel }, - { "deletetunnel", 0, deletetunnel }, - { "link0", IFF_LINK0, setifflags }, - { "-link0", -IFF_LINK0, setifflags }, - { "link1", IFF_LINK1, setifflags }, - { "-link1", -IFF_LINK1, setifflags }, - { "link2", IFF_LINK2, setifflags }, - { "-link2", -IFF_LINK2, setifflags }, - { "monitor", IFF_MONITOR, setifflags }, - { "-monitor", -IFF_MONITOR, setifflags }, - { "staticarp", IFF_STATICARP, setifflags }, - { "-staticarp", -IFF_STATICARP, setifflags }, -#ifdef USE_IF_MEDIA - { "media", NEXTARG, setmedia }, - { "mode", NEXTARG, setmediamode }, - { "mediaopt", NEXTARG, setmediaopt }, - { "-mediaopt", NEXTARG, unsetmediaopt }, -#endif -#ifdef USE_VLANS - { "vlan", NEXTARG, setvlantag }, - { "vlandev", NEXTARG, setvlandev }, - { "-vlandev", NEXTARG, unsetvlandev }, -#endif -#if 0 - /* XXX `create' special-cased below */ - {"create", 0, clone_create }, - {"plumb", 0, clone_create }, -#endif - {"destroy", 0, clone_destroy }, - {"unplumb", 0, clone_destroy }, -#ifdef USE_IEEE80211 - { "ssid", NEXTARG, set80211ssid }, - { "nwid", NEXTARG, set80211ssid }, - { "stationname", NEXTARG, set80211stationname }, - { "station", NEXTARG, set80211stationname }, /* BSD/OS */ - { "channel", NEXTARG, set80211channel }, - { "authmode", NEXTARG, set80211authmode }, - { "powersavemode", NEXTARG, set80211powersavemode }, - { "powersave", 1, set80211powersave }, - { "-powersave", 0, set80211powersave }, - { "powersavesleep", NEXTARG, set80211powersavesleep }, - { "wepmode", NEXTARG, set80211wepmode }, - { "wep", 1, set80211wep }, - { "-wep", 0, set80211wep }, - { "weptxkey", NEXTARG, set80211weptxkey }, - { "wepkey", NEXTARG, set80211wepkey }, - { "nwkey", NEXTARG, set80211nwkey }, /* NetBSD */ - { "-nwkey", 0, set80211wep }, /* NetBSD */ - { "rtsthreshold",NEXTARG, set80211rtsthreshold }, - { "protmode", NEXTARG, set80211protmode }, - { "txpower", NEXTARG, set80211txpower }, -#endif -#ifdef USE_MAC - { "maclabel", NEXTARG, setifmaclabel }, -#endif - { "rxcsum", IFCAP_RXCSUM, setifcap }, - { "-rxcsum", -IFCAP_RXCSUM, setifcap }, - { "txcsum", IFCAP_TXCSUM, setifcap }, - { "-txcsum", -IFCAP_TXCSUM, setifcap }, - { "netcons", IFCAP_NETCONS, setifcap }, - { "-netcons", -IFCAP_NETCONS, setifcap }, - { "polling", IFCAP_POLLING, setifcap }, - { "-polling", -IFCAP_POLLING, setifcap }, - { "vlanmtu", IFCAP_VLAN_MTU, setifcap }, - { "-vlanmtu", -IFCAP_VLAN_MTU, setifcap }, - { "vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap }, - { "-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap }, - { "normal", -IFF_LINK0, setifflags }, - { "compress", IFF_LINK0, setifflags }, - { "noicmp", IFF_LINK1, setifflags }, - { "mtu", NEXTARG, setifmtu }, - { "name", NEXTARG, setifname }, - { 0, 0, setifaddr }, - { 0, 0, setifdstaddr }, -}; +static struct afswtch *af_getbyname(const char *name); +static struct afswtch *af_getbyfamily(int af); +static void af_all_status(int, const struct rt_addrinfo *sdl); -/* - * 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*/ - -/* 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) }, - { "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) }, -#if 0 /* XXX conflicts with the media command */ -#ifdef USE_IF_MEDIA - { "media", AF_UNSPEC, media_status, NULL, NULL, }, /* XXX not real!! */ -#endif -#ifdef USE_VLANS - { "vlan", AF_UNSPEC, vlan_status, NULL, NULL, }, /* XXX not real!! */ -#endif -#ifdef USE_IEEE80211 - { "ieee80211", AF_UNSPEC, ieee80211_status, NULL, NULL, }, /* XXX not real!! */ -#endif -#ifdef USE_MAC - { "maclabel", AF_UNSPEC, maclabel_status, NULL, NULL, }, -#endif -#endif - { 0, 0, 0, 0 } -}; - -/* - * Expand the compacted form of addresses as returned via the - * configuration read via sysctl(). - */ +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; - cp += SA_SIZE(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 *argv[]) { - int c; - int all, namesonly, downonly, uponly; + int c, all, namesonly, downonly, uponly; int need_nl = 0, count = 0; - const struct afswtch *afp = 0; + const struct afswtch *afp = NULL; int addrcount, ifindex; - struct if_msghdr *ifm, *nextifm; - struct ifa_msghdr *ifam; - struct sockaddr_dl *sdl; - char *buf, *lim, *next; + struct if_msghdr *ifm, *nextifm; + struct ifa_msghdr *ifam; + struct sockaddr_dl *sdl; + char *buf, *lim, *next; size_t needed; int mib[6]; + char options[1024]; + struct option *p; + + all = downonly = uponly = namesonly = verbose = 0; /* Parse leading line options */ - all = downonly = uponly = namesonly = 0; - while ((c = getopt(argc, argv, "adlmuC" -#ifdef INET6 - "L" -#endif - )) != -1) { + strlcpy(options, "adlmuv", sizeof(options)); + for (p = opts; p != NULL; p = p->next) + strlcat(options, p->opt, sizeof(options)); + while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'a': /* scan all interfaces */ all++; @@ -459,32 +176,23 @@ main(int argc, char *argv[]) case 'u': /* restrict scan to "up" interfaces */ uponly++; break; - case 'C': - listcloners = 1; - break; -#ifdef INET6 - case 'L': - ip6lifetime++; /* print IPv6 address lifetime */ + case 'v': + verbose++; break; -#endif default: - usage(); + for (p = opts; p != NULL; p = p->next) + if (p->opt[0] == c) { + p->cb(optarg); + break; + } + if (p == NULL) + usage(); break; } } argc -= optind; argv += optind; - if (listcloners) { - /* -C must be solitary */ - if (all || supmedia || uponly || downonly || namesonly || - argc > 0) - usage(); - - list_cloners(); - exit(0); - } - /* -l cannot be used with -a or -m */ if (namesonly && (all || supmedia)) usage(); @@ -504,13 +212,11 @@ main(int argc, char *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 +249,9 @@ main(int argc, char *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 +263,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) @@ -630,9 +332,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); @@ -658,69 +359,158 @@ end: exit (0); } -int +static struct afswtch *afs = NULL; + +void +af_register(struct afswtch *p) +{ + p->af_next = afs; + afs = p; +} + +static struct afswtch * +af_getbyname(const char *name) +{ + struct afswtch *afp; + + for (afp = afs; afp != NULL; afp = afp->af_next) + if (strcmp(afp->af_name, name) == 0) + return afp; + return NULL; +} + +static struct afswtch * +af_getbyfamily(int af) +{ + struct afswtch *afp; + + for (afp = afs; afp != NULL; afp = afp->af_next) + if (afp->af_af == af) + return afp; + return NULL; +} + +static void +af_all_status(int s, const struct rt_addrinfo *sdl) +{ + 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 == NULL) + continue; + if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) + continue; + afp->af_status(s, sdl); + 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 +} + +/* specially-handled comamnds */ +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) { - int af, s; + int s; if (afp == NULL) - afp = &afs[0]; - af = afp->af_af == AF_LINK ? AF_INET : afp->af_af; - ifr.ifr_addr.sa_family = 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(af, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); + if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) + 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 */ + 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_func || p->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_func(argv[1], 0, s, afp); argc--, argv++; + } else if (p->c_parameter == OPTARG) { + p->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_func2(argv[1], argv[2], s, afp); argc -= 2, argv += 2; } else - (*p->c_func)(*argv, p->c_parameter, s, afp); + p->c_func(*argv, p->c_parameter, s, afp); } argc--, argv++; } -#ifdef INET6 - if (af == 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 && af == 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 (af == AF_APPLETALK) - checkatrange((struct sockaddr_at *) &addreq.ifra_addr); + /* + * Do any post argument processing required by the address family. + */ + if (afp->af_postproc != NULL) + afp->af_postproc(s, afp); + /* + * Do deferred operations. + */ if (clearaddr) { if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { warnx("interface %s cannot change %s addresses!", @@ -731,7 +521,8 @@ ifconfig(int argc, char *const *argv, const struct afswtch *afp) 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 @@ -753,16 +544,12 @@ ifconfig(int argc, char *const *argv, const struct afswtch *afp) close(s); return(0); } -#define RIDADDR 0 -#define ADDR 1 -#define MASK 2 -#define DSTADDR 3 /*ARGSUSED*/ -void +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. @@ -772,21 +559,20 @@ setifaddr(const char *addr, int param, int s, const struct afswtch *afp) 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 addreq; + struct addrinfo *srcres, *dstres; int ecode; -#ifdef INET6 - struct in6_aliasreq in6_addreq; -#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", @@ -800,43 +586,14 @@ 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(&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"); - break; - -#ifdef INET6 - case AF_INET6: - 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"); - break; -#endif /* INET6 */ - - default: - warn("address family not supported"); - } + afp->af_settunnel(s, srcres, dstres); freeaddrinfo(srcres); freeaddrinfo(dstres); } /* ARGSUSED */ -void +static void deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) { @@ -844,133 +601,43 @@ deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) err(1, "SIOCDIFPHYADDR"); } -void +static void setifnetmask(const char *addr, int dummy __unused, int s, 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, - 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) -{ - 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, - 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; - } -} - -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 (afp->af_getaddr != NULL) { + setmask++; + afp->af_getaddr(addr, MASK); } - if (!lladdr) - errx(EXIT_FAILURE, "could not determine link local address"); - - memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); - - freeifaddrs(ifap); } -#endif -void +static void setifbroadaddr(const char *addr, int dummy __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); } -void +static void setifipdst(const char *addr, int dummy __unused, int s, const struct afswtch *afp) { - in_getaddr(addr, DSTADDR); + const struct afswtch *inet; + + 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 +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), @@ -982,16 +649,16 @@ notealias(const char *addr, int param, int s, const struct afswtch *afp) newaddr = 0; } else clearaddr = 0; +#undef rqtosa } /*ARGSUSED*/ -void +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); } /* @@ -999,7 +666,7 @@ setifdstaddr(const char *addr, int param __unused, int s, * of the ifreq structure, which may confuse other parts of ifconfig. * Make a private copy so we can avoid that. */ -void +static void setifflags(const char *vname, int value, int s, const struct afswtch *afp) { struct ifreq my_ifr; @@ -1043,7 +710,7 @@ setifcap(const char *vname, int value, int s, const struct afswtch *afp) Perror(vname); } -void +static void setifmetric(const char *val, int dummy __unused, int s, const struct afswtch *afp) { @@ -1053,7 +720,7 @@ setifmetric(const char *val, int dummy __unused, int s, warn("ioctl (set metric)"); } -void +static void setifmtu(const char *val, int dummy __unused, int s, const struct afswtch *afp) { @@ -1063,14 +730,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) { - 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)"); @@ -1087,6 +757,25 @@ 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" \ @@ -1097,28 +786,28 @@ setifname(const char *val, int dummy __unused, int s, /* * 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 +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)); - 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); @@ -1134,8 +823,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'); } } @@ -1143,376 +831,38 @@ 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(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 -#ifdef USE_MAC - if (allfamilies || afp->af_status == maclabel_status) - maclabel_status(s, NULL); -#endif + if (allfamilies) + af_all_status(s, (const struct rt_addrinfo *) sdl); + else if (afp->af_status != NULL) + afp->af_status(s, (const struct rt_addrinfo *) sdl); + 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 +static 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 = 𝔦 - } else { - close(s6); - srccmd = SIOCGIFPSRCADDR_IN6; - dstcmd = SIOCGIFPDSTADDR_IN6; - ifrp = (struct ifreq *)&in6_ifr; - } -#else /* INET6 */ - srccmd = SIOCGIFPSRCADDR; - dstcmd = SIOCGIFPDSTADDR; - ifrp = 𝔦 -#endif /* INET6 */ - - if (ioctl(s, srccmd, (caddr_t)ifrp) < 0) - return; -#ifdef INET6 - 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; -#ifdef INET6 - if (ifrp->ifr_addr.sa_family == AF_INET6) - in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); -#endif - getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, - pdstaddr, sizeof(pdstaddr), 0, 0, niflag); - - printf("\ttunnel inet%s %s --> %s\n", ver, - psrcaddr, pdstaddr); -} - -void -in_status(int s __unused, struct rt_addrinfo * info) -{ - struct sockaddr_in *sin, null_sin; - - memset(&null_sin, 0, sizeof(null_sin)); - - sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA]; - 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'); -} - -#ifdef INET6 -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 -} - -void -in6_status(int s __unused, 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]; - 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 = *sin; - 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 = *sin; - 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(&sin->sin6_addr) && - *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { - u_short index; - - index = *(u_short *)&sin->sin6_addr.s6_addr[2]; - *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; - if (sin->sin6_scope_id == 0) - sin->sin6_scope_id = ntohs(index); - } - scopeid = sin->sin6_scope_id; - - error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, - sizeof(addr_buf), NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID); - if (error != 0) - inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, - sizeof(addr_buf)); - printf("\tinet6 %s ", addr_buf); - - if (flags & IFF_POINTOPOINT) { - /* note RTAX_BRD overlap with IFF_BROADCAST */ - sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD]; - /* - * some of the interfaces do not have valid destination - * address. - */ - if (sin && sin->sin6_family == AF_INET6) { - int error; - - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && - *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { - u_short index; - - index = *(u_short *)&sin->sin6_addr.s6_addr[2]; - *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; - if (sin->sin6_scope_id == 0) - sin->sin6_scope_id = ntohs(index); - } - - error = getnameinfo((struct sockaddr *)sin, - sin->sin6_len, addr_buf, - sizeof(addr_buf), NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID); - if (error != 0) - inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, - sizeof(addr_buf)); - printf("--> %s ", addr_buf); - } - } - - sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK]; - if (!sin) - sin = &null_sin; - printf("prefixlen %d ", prefix(&sin->sin6_addr, - sizeof(struct in6_addr))); - - if ((flags6 & IN6_IFF_ANYCAST) != 0) - printf("anycast "); - if ((flags6 & IN6_IFF_TENTATIVE) != 0) - printf("tentative "); - if ((flags6 & IN6_IFF_DUPLICATED) != 0) - printf("duplicated "); - if ((flags6 & IN6_IFF_DETACHED) != 0) - printf("detached "); - if ((flags6 & IN6_IFF_DEPRECATED) != 0) - printf("deprecated "); - if ((flags6 & IN6_IFF_AUTOCONF) != 0) - printf("autoconf "); - if ((flags6 & IN6_IFF_TEMPORARY) != 0) - printf("temporary "); - - if (scopeid) - printf("scopeid 0x%x ", scopeid); - - if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { - printf("pltime "); - if (lifetime.ia6t_preferred) { - printf("%s ", lifetime.ia6t_preferred < t - ? "0" : sec2str(lifetime.ia6t_preferred - t)); - } else - printf("infty "); - - printf("vltime "); - if (lifetime.ia6t_expire) { - printf("%s ", lifetime.ia6t_expire < t - ? "0" : sec2str(lifetime.ia6t_expire - t)); - } else - printf("infty "); - } - - putchar('\n'); -} -#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'); -} - -void -link_status(int s __unused, struct rt_addrinfo *info) -{ - 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 @@ -1533,116 +883,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 *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); -} - -#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 *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); -} - -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); -} -#endif - /* * Print a value a la the %b format of the kernel's printf */ @@ -1674,170 +914,6 @@ 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, - 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); -} - -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); -} - -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 INET6 -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); -} -#endif /*INET6*/ - void ifmaybeload(char *name) { @@ -1877,86 +953,63 @@ ifmaybeload(char *name) 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)); - (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCIFCREATE, &ifr) < 0) - err(1, "SIOCIFCREATE"); - - /* - * If we get a different name back then we put in, we probably - * want to print it out, but we might change our mind later so - * we just signal our intrest and leave the printout for later. - */ - if (strcmp(name, ifr.ifr_name) != 0) { - printname = 1; - strlcpy(name, ifr.ifr_name, sizeof(name)); - } - - close(s); -} +static 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), + DEF_CMD_ARG("ipdst", setifipdst), + DEF_CMD_ARG2("tunnel", settunnel), + 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), + DEF_CMD("monitor", IFF_MONITOR, setifflags), + DEF_CMD("-monitor", -IFF_MONITOR, setifflags), + DEF_CMD("staticarp", IFF_STATICARP, setifflags), + DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), + DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), + DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), + DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), + DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), + DEF_CMD("netcons", IFCAP_NETCONS, setifcap), + DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), + DEF_CMD("polling", IFCAP_POLLING, setifcap), + DEF_CMD("-polling", -IFCAP_POLLING, setifcap), + DEF_CMD("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, int d, int s, const struct afswtch *rafp) +static __constructor void +ifconfig_ctor(void) { +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; - (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; + for (i = 0; i < N(basic_cmds); i++) + cmd_register(&basic_cmds[i]); +#undef N } diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h index fb340fc..aa09ff8 100644 --- a/sbin/ifconfig/ifconfig.h +++ b/sbin/ifconfig/ifconfig.h @@ -34,39 +34,97 @@ * $FreeBSD$ */ -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 *); -extern void maclabel_status(int s, struct rt_addrinfo *); -extern void setifmaclabel(const char *, int, int, const struct afswtch *rafp); +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; + }; + struct cmd *c_next; +}; +void cmd_register(struct cmd *); + +/* + * 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) { name, NEXTARG, { .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_* */ + /* print status method */ + void (*af_status)(int, const struct rt_addrinfo *); + /* 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 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 *name); + +void clone_create(void); diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c index 1e83e80..d7800d4 100644 --- a/sbin/ifconfig/ifieee80211.c +++ b/sbin/ifconfig/ifieee80211.c @@ -74,7 +74,9 @@ #include <net/if.h> #include <net/if_dl.h> #include <net/if_types.h> +#include <net/if_media.h> #include <net/route.h> + #include <net80211/ieee80211.h> #include <net80211/ieee80211_crypto.h> #include <net80211/ieee80211_ioctl.h> @@ -95,7 +97,14 @@ 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 int +isanyarg(const char *arg) +{ + return (strcmp(arg, "-") == 0 || + strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); +} + +static void set80211ssid(const char *val, int d, int s, const struct afswtch *rafp) { int ssid; @@ -116,7 +125,7 @@ set80211ssid(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_SSID, ssid, len, data); } -void +static void set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) { int len; @@ -129,16 +138,49 @@ set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); } -void +/* + * Convert IEEE channel number to MHz frequency. + */ +static u_int +ieee80211_ieee2mhz(u_int chan) +{ + if (chan == 14) + return 2484; + if (chan < 14) /* 0-13 */ + return 2407 + chan*5; + if (chan < 27) /* 15-26 */ + return 2512 + ((chan-15)*20); + return 5000 + (chan*5); +} + +/* + * Convert MHz frequency to IEEE channel number. + */ +static u_int +ieee80211_mhz2ieee(u_int freq) +{ + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + if (freq < 5000) + return 15 + ((freq - 2512) / 20); + return (freq - 5000) / 5; +} + +static void set80211channel(const char *val, int d, int s, const struct afswtch *rafp) { - if (strcmp(val, "-") == 0) + if (!isanyarg(val)) { + int v = atoi(val); + if (v > 255) /* treat as frequency */ + v = ieee80211_mhz2ieee(v); + set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); + } else set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); - else - set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL); } -void +static void set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; @@ -149,6 +191,10 @@ set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) mode = IEEE80211_AUTH_OPEN; } else if (strcasecmp(val, "shared") == 0) { mode = IEEE80211_AUTH_SHARED; + } else if (strcasecmp(val, "8021x") == 0) { + mode = IEEE80211_AUTH_8021X; + } else if (strcasecmp(val, "wpa") == 0) { + mode = IEEE80211_AUTH_WPA; } else { err(1, "unknown authmode"); } @@ -156,7 +202,7 @@ set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); } -void +static void set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; @@ -178,7 +224,7 @@ set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); } -void +static void set80211powersave(const char *val, int d, int s, const struct afswtch *rafp) { if (d == 0) @@ -189,13 +235,13 @@ set80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 0, NULL); } -void +static void set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); } -void +static void set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; @@ -213,19 +259,19 @@ set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); } -void +static void set80211wep(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); } -void +static void set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); } -void +static void set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) { int key = 0; @@ -249,7 +295,7 @@ set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) * 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, int s, const struct afswtch *rafp) { int txkey; @@ -285,13 +331,13 @@ set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); } -void +static void set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL); } -void +static void set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) { int mode; @@ -309,159 +355,1048 @@ set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); } -void +static void set80211txpower(const char *val, int d, int s, const struct afswtch *rafp) { set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); } -void -ieee80211_status (int s, struct rt_addrinfo *info __unused) +#define IEEE80211_ROAMING_DEVICE 0 +#define IEEE80211_ROAMING_AUTO 1 +#define IEEE80211_ROAMING_MANUAL 2 + +static void +set80211roaming(const char *val, int d, int s, const struct afswtch *rafp) { - int i; - int num; - struct ieee80211req ireq; - u_int8_t data[32]; - char spacer; + int mode; + + if (strcasecmp(val, "device") == 0) { + mode = IEEE80211_ROAMING_DEVICE; + } else if (strcasecmp(val, "auto") == 0) { + mode = IEEE80211_ROAMING_AUTO; + } else if (strcasecmp(val, "manual") == 0) { + mode = IEEE80211_ROAMING_MANUAL; + } else { + err(1, "unknown roaming mode"); + } + set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); +} + +static void +set80211wme(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_WME, d, 0, NULL); +} + +static void +set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); +} + +static void +set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); +} + +static void +set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) +{ + struct ieee80211req_chanlist chanlist; +#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) + char *temp, *cp, *tp; + + temp = malloc(strlen(val) + 1); + if (temp == NULL) + errx(1, "malloc failed"); + strcpy(temp, val); + memset(&chanlist, 0, sizeof(chanlist)); + cp = temp; + for (;;) { + int first, last, f; + + tp = strchr(cp, ','); + if (tp != NULL) + *tp++ = '\0'; + switch (sscanf(cp, "%u-%u", &first, &last)) { + case 1: + if (first > MAXCHAN) + errx(-1, "channel %u out of range, max %u", + first, MAXCHAN); + setbit(chanlist.ic_channels, first); + break; + case 2: + if (first > MAXCHAN) + errx(-1, "channel %u out of range, max %u", + first, MAXCHAN); + if (last > MAXCHAN) + errx(-1, "channel %u out of range, max %u", + last, MAXCHAN); + if (first > last) + errx(-1, "void channel range, %u > %u", + first, last); + for (f = first; f <= last; f++) + setbit(chanlist.ic_channels, f); + break; + } + if (tp == NULL) + break; + while (isspace(*tp)) + tp++; + if (!isdigit(*tp)) + break; + cp = tp; + } + set80211(s, IEEE80211_IOC_CHANLIST, 0, + sizeof(chanlist), (uint8_t *) &chanlist); +#undef MAXCHAN +} + +static void +set80211bssid(const char *val, int d, int s, const struct afswtch *rafp) +{ + + if (!isanyarg(val)) { + char *temp; + struct sockaddr_dl sdl; + + temp = malloc(strlen(val) + 1); + if (temp == NULL) + errx(1, "malloc failed"); + temp[0] = ':'; + strcpy(temp + 1, val); + sdl.sdl_len = sizeof(sdl); + link_addr(temp, &sdl); + free(temp); + if (sdl.sdl_alen != IEEE80211_ADDR_LEN) + errx(1, "malformed link-level address"); + set80211(s, IEEE80211_IOC_BSSID, 0, + IEEE80211_ADDR_LEN, LLADDR(&sdl)); + } else { + uint8_t zerobssid[IEEE80211_ADDR_LEN]; + memset(zerobssid, 0, sizeof(zerobssid)); + set80211(s, IEEE80211_IOC_BSSID, 0, + IEEE80211_ADDR_LEN, zerobssid); + } +} + +static int +getac(const char *ac) +{ + if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) + return WME_AC_BE; + if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) + return WME_AC_BK; + if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) + return WME_AC_VI; + if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) + return WME_AC_VO; + errx(1, "unknown wme access class %s", ac); +} + +static +DECL_CMD_FUNC2(set80211cwmin, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); +} + +static +DECL_CMD_FUNC2(set80211cwmax, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); +} + +static +DECL_CMD_FUNC2(set80211aifs, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); +} + +static +DECL_CMD_FUNC2(set80211txoplimit, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); +} + +static +DECL_CMD_FUNC(set80211acm, val, d) +{ + set80211(s, IEEE80211_IOC_WME_ACM, d, WME_AC_BE, NULL); +} + +static +DECL_CMD_FUNC(set80211ackpolicy, val, d) +{ + set80211(s, IEEE80211_IOC_WME_ACKPOLICY, d, WME_AC_BE, NULL); +} + +static +DECL_CMD_FUNC2(set80211bsscwmin, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), + getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); +} + +static +DECL_CMD_FUNC2(set80211bsscwmax, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), + getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); +} + +static +DECL_CMD_FUNC2(set80211bssaifs, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), + getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); +} + +static +DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) +{ + set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), + getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); +} + +static +DECL_CMD_FUNC(set80211dtimperiod, val, d) +{ + set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); +} + +static +DECL_CMD_FUNC(set80211bintval, val, d) +{ + set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); +} + +static void +set80211macmac(int s, int op, const char *val) +{ + char *temp; + struct sockaddr_dl sdl; + + temp = malloc(strlen(val) + 1); + if (temp == NULL) + errx(1, "malloc failed"); + temp[0] = ':'; + strcpy(temp + 1, val); + sdl.sdl_len = sizeof(sdl); + link_addr(temp, &sdl); + free(temp); + if (sdl.sdl_alen != IEEE80211_ADDR_LEN) + errx(1, "malformed link-level address"); + set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); +} + +static +DECL_CMD_FUNC(set80211addmac, val, d) +{ + set80211macmac(s, IEEE80211_IOC_ADDMAC, val); +} + +static +DECL_CMD_FUNC(set80211delmac, val, d) +{ + set80211macmac(s, IEEE80211_IOC_DELMAC, val); +} + +static +DECL_CMD_FUNC(set80211maccmd, val, d) +{ + set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); +} + +static int +getmaxrate(uint8_t rates[15], uint8_t nrates) +{ + int i, maxrate = -1; + + for (i = 0; i < nrates; i++) { + int rate = rates[i] & IEEE80211_RATE_VAL; + if (rate > maxrate) + maxrate = rate; + } + return maxrate / 2; +} + +static const char * +getcaps(int capinfo) +{ + static char capstring[32]; + char *cp = capstring; + + if (capinfo & IEEE80211_CAPINFO_ESS) + *cp++ = 'E'; + if (capinfo & IEEE80211_CAPINFO_IBSS) + *cp++ = 'I'; + if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) + *cp++ = 'c'; + if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) + *cp++ = 'C'; + if (capinfo & IEEE80211_CAPINFO_PRIVACY) + *cp++ = 'P'; + if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) + *cp++ = 'S'; + if (capinfo & IEEE80211_CAPINFO_PBCC) + *cp++ = 'B'; + if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) + *cp++ = 'A'; + if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) + *cp++ = 's'; + if (capinfo & IEEE80211_CAPINFO_RSN) + *cp++ = 'R'; + if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) + *cp++ = 'D'; + *cp = '\0'; + return capstring; +} + +static void +printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) +{ + printf("%s", tag); + if (verbose) { + maxlen -= strlen(tag)+2; + if (2*ielen > maxlen) + maxlen--; + printf("<"); + for (; ielen > 0; ie++, ielen--) { + if (maxlen-- <= 0) + break; + printf("%02x", *ie); + } + if (ielen != 0) + printf("-"); + printf(">"); + } +} + +/* + * Copy the ssid string contents into buf, truncating to fit. If the + * ssid is entirely printable then just copy intact. Otherwise convert + * to hexadecimal. If the result is truncated then replace the last + * three characters with "...". + */ +static size_t +copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) +{ + const u_int8_t *p; + size_t maxlen; + int i; + + if (essid_len > bufsize) + maxlen = bufsize; + else + maxlen = essid_len; + /* determine printable or not */ + for (i = 0, p = essid; i < maxlen; i++, p++) { + if (*p < ' ' || *p > 0x7e) + break; + } + if (i != maxlen) { /* not printable, print as hex */ + if (bufsize < 3) + return 0; + strlcpy(buf, "0x", bufsize); + bufsize -= 2; + p = essid; + for (i = 0; i < maxlen && bufsize >= 2; i++) { + sprintf(&buf[2+2*i], "%02x", *p++); + bufsize -= 2; + } + maxlen = 2+2*i; + } else { /* printable, truncate as needed */ + memcpy(buf, essid, maxlen); + } + if (maxlen != essid_len) + memcpy(buf+maxlen-3, "...", 3); + return maxlen; +} + +/* unalligned little endian access */ +#define LE_READ_4(p) \ + ((u_int32_t) \ + ((((const u_int8_t *)(p))[0] ) | \ + (((const u_int8_t *)(p))[1] << 8) | \ + (((const u_int8_t *)(p))[2] << 16) | \ + (((const u_int8_t *)(p))[3] << 24))) + +static int __inline +iswpaoui(const u_int8_t *frm) +{ + return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); +} + +static int __inline +iswmeoui(const u_int8_t *frm) +{ + return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); +} + +static int __inline +isatherosoui(const u_int8_t *frm) +{ + return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); +} + +static void +printies(const u_int8_t *vp, int ielen, int maxcols) +{ + while (ielen > 0) { + switch (vp[0]) { + case IEEE80211_ELEMID_VENDOR: + if (iswpaoui(vp)) + printie(" WPA", vp, 2+vp[1], maxcols); + else if (iswmeoui(vp)) + printie(" WME", vp, 2+vp[1], maxcols); + else + printie(" VEN", vp, 2+vp[1], maxcols); + break; + case IEEE80211_ELEMID_RSN: + printie(" RSN", vp, 2+vp[1], maxcols); + break; + default: + printie(" ???", vp, 2+vp[1], maxcols); + break; + } + ielen -= 2+vp[1]; + vp += 2+vp[1]; + } +} + +static void +list_scan(int s) +{ + uint8_t buf[24*1024]; + struct ieee80211req ireq; + char ssid[14]; + uint8_t *cp; + int len; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; + ireq.i_data = buf; + ireq.i_len = sizeof(buf); + if (ioctl(s, SIOCG80211, &ireq) < 0) + errx(1, "unable to get scan results"); + len = ireq.i_len; + if (len < sizeof(struct ieee80211req_scan_result)) + return; + + printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n" + , "SSID" + , "BSSID" + , "CHAN" + , "RATE" + , "S:N" + , "INT" + , "CAPS" + ); + cp = buf; + do { + struct ieee80211req_scan_result *sr; + uint8_t *vp; + + sr = (struct ieee80211req_scan_result *) cp; + vp = (u_int8_t *)(sr+1); + printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" + , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len) + , ssid + , ether_ntoa((const struct ether_addr *) sr->isr_bssid) + , ieee80211_mhz2ieee(sr->isr_freq) + , getmaxrate(sr->isr_rates, sr->isr_nrates) + , sr->isr_rssi, sr->isr_noise + , sr->isr_intval + , getcaps(sr->isr_capinfo) + ); + printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; + printf("\n"); + cp += sr->isr_len, len -= sr->isr_len; + } while (len >= sizeof(struct ieee80211req_scan_result)); +} + +#include <net80211/ieee80211_freebsd.h> + +static void +scan_and_wait(int s) +{ + struct ieee80211req ireq; + int sroute; + + sroute = socket(PF_ROUTE, SOCK_RAW, 0); + if (sroute < 0) { + perror("socket(PF_ROUTE,SOCK_RAW)"); + return; + } + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_SCAN_REQ; + /* NB: only root can trigger a scan so ignore errors */ + if (ioctl(s, SIOCS80211, &ireq) >= 0) { + char buf[2048]; + struct if_announcemsghdr *ifan; + struct rt_msghdr *rtm; + + do { + if (read(sroute, buf, sizeof(buf)) < 0) { + perror("read(PF_ROUTE)"); + break; + } + rtm = (struct rt_msghdr *) buf; + if (rtm->rtm_version != RTM_VERSION) + break; + ifan = (struct if_announcemsghdr *) rtm; + } while (rtm->rtm_type != RTM_IEEE80211 || + ifan->ifan_what != RTM_IEEE80211_SCAN); + } + close(sroute); +} + +static +DECL_CMD_FUNC(set80211scan, val, d) +{ + scan_and_wait(s); + list_scan(s); +} + +static void +list_stations(int s) +{ + uint8_t buf[24*1024]; + struct ieee80211req ireq; + uint8_t *cp; + int len; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_STA_INFO; + ireq.i_data = buf; + ireq.i_len = sizeof(buf); + if (ioctl(s, SIOCG80211, &ireq) < 0) + errx(1, "unable to get station information"); + len = ireq.i_len; + if (len < sizeof(struct ieee80211req_sta_info)) + return; + + printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n" + , "ADDR" + , "AID" + , "CHAN" + , "RATE" + , "RSSI" + , "IDLE" + , "TXSEQ" + , "RXSEQ" + , "CAPS" + , "ERP" + ); + cp = buf; + do { + struct ieee80211req_sta_info *si; + uint8_t *vp; + + si = (struct ieee80211req_sta_info *) cp; + vp = (u_int8_t *)(si+1); + printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x" + , ether_ntoa((const struct ether_addr*) si->isi_macaddr) + , IEEE80211_AID(si->isi_associd) + , ieee80211_mhz2ieee(si->isi_freq) + , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 + , si->isi_rssi + , si->isi_inact + , si->isi_txseqs[0] + , si->isi_rxseqs[0] + , getcaps(si->isi_capinfo) + , si->isi_erp + ); + printies(vp, si->isi_ie_len, 24); + printf("\n"); + cp += si->isi_len, len -= si->isi_len; + } while (len >= sizeof(struct ieee80211req_sta_info)); +} + +static void +print_chaninfo(const struct ieee80211_channel *c) +{ +#define IEEE80211_IS_CHAN_PASSIVE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) + char buf[14]; + + buf[0] = '\0'; + if (IEEE80211_IS_CHAN_FHSS(c)) + strlcat(buf, " FHSS", sizeof(buf)); + if (IEEE80211_IS_CHAN_A(c)) + strlcat(buf, " 11a", sizeof(buf)); + /* XXX 11g schizophrenia */ + if (IEEE80211_IS_CHAN_G(c) || + IEEE80211_IS_CHAN_PUREG(c)) + strlcat(buf, " 11g", sizeof(buf)); + else if (IEEE80211_IS_CHAN_B(c)) + strlcat(buf, " 11b", sizeof(buf)); + if (IEEE80211_IS_CHAN_T(c)) + strlcat(buf, " Turbo", sizeof(buf)); + printf("Channel %3u : %u%c Mhz%-14.14s", + ieee80211_mhz2ieee(c->ic_freq), c->ic_freq, + IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); +#undef IEEE80211_IS_CHAN_PASSIVE +} + +static void +list_channels(int s, int allchans) +{ + struct ieee80211req ireq; + struct ieee80211req_chaninfo chans; + struct ieee80211req_chaninfo achans; + const struct ieee80211_channel *c; + int i, half; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_CHANINFO; + ireq.i_data = &chans; + ireq.i_len = sizeof(chans); + if (ioctl(s, SIOCG80211, &ireq) < 0) + errx(1, "unable to get channel information"); + if (!allchans) { + struct ieee80211req_chanlist active; + + ireq.i_type = IEEE80211_IOC_CHANLIST; + ireq.i_data = &active; + ireq.i_len = sizeof(active); + if (ioctl(s, SIOCG80211, &ireq) < 0) + errx(1, "unable to get active channel list"); + memset(&achans, 0, sizeof(achans)); + for (i = 0; i < chans.ic_nchans; i++) { + c = &chans.ic_chans[i]; + if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans) + achans.ic_chans[achans.ic_nchans++] = *c; + } + } else + achans = chans; + half = achans.ic_nchans / 2; + if (achans.ic_nchans % 2) + half++; + for (i = 0; i < achans.ic_nchans / 2; i++) { + print_chaninfo(&achans.ic_chans[i]); + print_chaninfo(&achans.ic_chans[half+i]); + printf("\n"); + } + if (achans.ic_nchans % 2) { + print_chaninfo(&achans.ic_chans[i]); + printf("\n"); + } +} + +static void +list_keys(int s) +{ +} + +#define IEEE80211_C_BITS \ +"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ +"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ +"\31WPA2\32BURST\33WME" + +static void +list_capabilities(int s) +{ + struct ieee80211req ireq; + u_int32_t caps; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; + if (ioctl(s, SIOCG80211, &ireq) < 0) + errx(1, "unable to get driver capabilities"); + caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); + printb(name, caps, IEEE80211_C_BITS); + putchar('\n'); +} + +static void +list_wme(int s) +{ + static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; + struct ieee80211req ireq; + int ac; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_len = 0; + for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { +again: + if (ireq.i_len & IEEE80211_WMEPARAM_BSS) + printf("\t%s", " "); + else + printf("\t%s", acnames[ac]); + + ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; + + /* show WME BSS parameters */ + ireq.i_type = IEEE80211_IOC_WME_CWMIN; + if (ioctl(s, SIOCG80211, &ireq) != -1) + printf(" cwmin %2u", ireq.i_val); + ireq.i_type = IEEE80211_IOC_WME_CWMAX; + if (ioctl(s, SIOCG80211, &ireq) != -1) + printf(" cwmax %2u", ireq.i_val); + ireq.i_type = IEEE80211_IOC_WME_AIFS; + if (ioctl(s, SIOCG80211, &ireq) != -1) + printf(" aifs %2u", ireq.i_val); + ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; + if (ioctl(s, SIOCG80211, &ireq) != -1) + printf(" txopLimit %3u", ireq.i_val); + ireq.i_type = IEEE80211_IOC_WME_ACM; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (ireq.i_val) + printf(" acm"); + else if (verbose) + printf(" -acm"); + } + /* !BSS only */ + if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { + ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (!ireq.i_val) + printf(" -ack"); + else if (verbose) + printf(" ack"); + } + } + printf("\n"); + if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { + ireq.i_len |= IEEE80211_WMEPARAM_BSS; + goto again; + } else + ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; + } +} + +static +DECL_CMD_FUNC(set80211list, arg, d) +{ +#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) + + if (iseq(arg, "sta")) + list_stations(s); + else if (iseq(arg, "scan") || iseq(arg, "ap")) + list_scan(s); + else if (iseq(arg, "chan") || iseq(arg, "freq")) + list_channels(s, 1); + else if (iseq(arg, "active")) + list_channels(s, 0); + else if (iseq(arg, "keys")) + list_keys(s); + else if (iseq(arg, "caps")) + list_capabilities(s); + else if (iseq(arg, "wme")) + list_wme(s); + else + errx(1, "Don't know how to list %s for %s", arg, name); +#undef iseq +} + +static enum ieee80211_opmode +get80211opmode(int s) +{ + struct ifmediareq ifmr; + + (void) memset(&ifmr, 0, sizeof(ifmr)); + (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); + + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { + if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) + return IEEE80211_M_IBSS; /* XXX ahdemo */ + if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) + return IEEE80211_M_HOSTAP; + if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) + return IEEE80211_M_MONITOR; + } + return IEEE80211_M_STA; +} + +static const struct ieee80211_channel * +getchaninfo(int s, int chan) +{ + struct ieee80211req ireq; + static struct ieee80211req_chaninfo chans; + static struct ieee80211_channel undef; + const struct ieee80211_channel *c; + int i, freq; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_CHANINFO; + ireq.i_data = &chans; + ireq.i_len = sizeof(chans); + if (ioctl(s, SIOCG80211, &ireq) < 0) + errx(1, "unable to get channel information"); + freq = ieee80211_ieee2mhz(chan); + for (i = 0; i < chans.ic_nchans; i++) { + c = &chans.ic_chans[i]; + if (c->ic_freq == freq) + return c; + } + return &undef; +} + +#if 0 +static void +printcipher(int s, struct ieee80211req *ireq, int keylenop) +{ + switch (ireq->i_val) { + case IEEE80211_CIPHER_WEP: + ireq->i_type = keylenop; + if (ioctl(s, SIOCG80211, ireq) != -1) + printf("WEP-%s", + ireq->i_len <= 5 ? "40" : + ireq->i_len <= 13 ? "104" : "128"); + else + printf("WEP"); + break; + case IEEE80211_CIPHER_TKIP: + printf("TKIP"); + break; + case IEEE80211_CIPHER_AES_OCB: + printf("AES-OCB"); + break; + case IEEE80211_CIPHER_AES_CCM: + printf("AES-CCM"); + break; + case IEEE80211_CIPHER_CKIP: + printf("CKIP"); + break; + case IEEE80211_CIPHER_NONE: + printf("NONE"); + break; + default: + printf("UNKNOWN (0x%x)", ireq->i_val); + break; + } +} +#endif + +#define MAXCOL 78 +int col; +char spacer; + +#define LINE_BREAK() do { \ + if (spacer != '\t') { \ + printf("\n"); \ + spacer = '\t'; \ + } \ + col = 8; /* 8-col tab */ \ +} while (0) +#define LINE_CHECK(fmt, ...) do { \ + col += sizeof(fmt)-2; \ + if (col > MAXCOL) { \ + LINE_BREAK(); \ + col += sizeof(fmt)-2; \ + } \ + printf(fmt, __VA_ARGS__); \ + spacer = ' '; \ +} while (0) + +static void +printkey(const struct ieee80211req_key *ik) +{ + static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; + int keylen = ik->ik_keylen; + int printcontents; + + printcontents = + (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); + if (printcontents) + LINE_BREAK(); + switch (ik->ik_type) { + case IEEE80211_CIPHER_WEP: + /* compatibility */ + LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1, + keylen <= 5 ? "40-bit" : + keylen <= 13 ? "104-bit" : "128-bit"); + break; + case IEEE80211_CIPHER_TKIP: + if (keylen > 128/8) + keylen -= 128/8; /* ignore MIC for now */ + LINE_CHECK("%cTKIP %u:%u-bit", + spacer, ik->ik_keyix+1, 8*keylen); + break; + case IEEE80211_CIPHER_AES_OCB: + LINE_CHECK("%cAES-OCB %u:%u-bit", + spacer, ik->ik_keyix+1, 8*keylen); + break; + case IEEE80211_CIPHER_AES_CCM: + LINE_CHECK("%cAES-CCM %u:%u-bit", + spacer, ik->ik_keyix+1, 8*keylen); + break; + case IEEE80211_CIPHER_CKIP: + LINE_CHECK("%cCKIP %u:%u-bit", + spacer, ik->ik_keyix+1, 8*keylen); + break; + case IEEE80211_CIPHER_NONE: + LINE_CHECK("%cNULL %u:%u-bit", + spacer, ik->ik_keyix+1, 8*keylen); + break; + default: + LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer, + ik->ik_type, ik->ik_keyix+1, 8*keylen); + break; + } + if (printcontents) { + int i; + + printf(" <"); + for (i = 0; i < keylen; i++) + printf("%02x", ik->ik_keydata[i]); + printf(">"); + if (ik->ik_type != IEEE80211_CIPHER_WEP && + (ik->ik_keyrsc != 0 || verbose)) + printf(" rsc %llu", ik->ik_keyrsc); + if (ik->ik_type != IEEE80211_CIPHER_WEP && + (ik->ik_keytsc != 0 || verbose)) + printf(" tsc %llu", ik->ik_keytsc); + if (ik->ik_flags != 0 && verbose) { + const char *sep = " "; + + if (ik->ik_flags & IEEE80211_KEY_XMIT) + printf("%stx", sep), sep = "+"; + if (ik->ik_flags & IEEE80211_KEY_RECV) + printf("%srx", sep), sep = "+"; + if (ik->ik_flags & IEEE80211_KEY_DEFAULT) + printf("%sdef", sep), sep = "+"; + } + LINE_BREAK(); + } +} + +static void +ieee80211_status(int s, const struct rt_addrinfo *info __unused) +{ + static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; + enum ieee80211_opmode opmode = get80211opmode(s); + int i, num, wpa, wme; + struct ieee80211req ireq; + u_int8_t data[32]; + const struct ieee80211_channel *c; (void) memset(&ireq, 0, sizeof(ireq)); (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); ireq.i_data = &data; + wpa = 0; /* unknown/not set */ + ireq.i_type = IEEE80211_IOC_SSID; ireq.i_val = -1; if (ioctl(s, SIOCG80211, &ireq) < 0) { /* If we can't get the SSID, the this isn't an 802.11 device. */ return; } - printf("\tssid "); - print_string(data, ireq.i_len); num = 0; ireq.i_type = IEEE80211_IOC_NUMSSIDS; - if (ioctl(s, SIOCG80211, &ireq) >= 0) { + if (ioctl(s, SIOCG80211, &ireq) >= 0) num = ireq.i_val; - } - ireq.i_type = IEEE80211_IOC_SSID; - for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { - if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { - printf(" %d:", ireq.i_val + 1); - print_string(data, ireq.i_len); + printf("\tssid "); + if (num > 1) { + ireq.i_type = IEEE80211_IOC_SSID; + for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { + if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { + printf(" %d:", ireq.i_val + 1); + print_string(data, ireq.i_len); + } } - } - printf("\n"); + } else + print_string(data, ireq.i_len); + + ireq.i_type = IEEE80211_IOC_CHANNEL; + if (ioctl(s, SIOCG80211, &ireq) < 0) + goto end; + c = getchaninfo(s, ireq.i_val); + if (ireq.i_val != -1) { + printf(" channel %d", ireq.i_val); + if (verbose) + printf(" (%u)", c->ic_freq); + } else if (verbose) + printf(" channel UNDEF"); + + ireq.i_type = IEEE80211_IOC_BSSID; + ireq.i_len = IEEE80211_ADDR_LEN; + if (ioctl(s, SIOCG80211, &ireq) >= 0 && + memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0) + printf(" bssid %s", ether_ntoa(ireq.i_data)); ireq.i_type = IEEE80211_IOC_STATIONNAME; if (ioctl(s, SIOCG80211, &ireq) != -1) { - printf("\tstationname "); + printf("\n\tstationname "); print_string(data, ireq.i_len); - printf("\n"); } - ireq.i_type = IEEE80211_IOC_CHANNEL; - if (ioctl(s, SIOCG80211, &ireq) < 0) { - goto end; - } - printf("\tchannel %d", ireq.i_val); + spacer = ' '; /* force first break */ + LINE_BREAK(); ireq.i_type = IEEE80211_IOC_AUTHMODE; if (ioctl(s, SIOCG80211, &ireq) != -1) { - printf(" authmode"); switch (ireq.i_val) { case IEEE80211_AUTH_NONE: - printf(" NONE"); + LINE_CHECK("%cauthmode NONE", spacer); break; case IEEE80211_AUTH_OPEN: - printf(" OPEN"); + LINE_CHECK("%cauthmode OPEN", spacer); break; case IEEE80211_AUTH_SHARED: - printf(" SHARED"); + LINE_CHECK("%cauthmode SHARED", spacer); break; - default: - printf(" UNKNOWN"); + case IEEE80211_AUTH_8021X: + LINE_CHECK("%cauthmode 802.1x", spacer); break; - } - } - - ireq.i_type = IEEE80211_IOC_POWERSAVE; - if (ioctl(s, SIOCG80211, &ireq) != -1 && - ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { - printf(" powersavemode"); - switch (ireq.i_val) { - case IEEE80211_POWERSAVE_OFF: - printf(" OFF"); - break; - case IEEE80211_POWERSAVE_CAM: - printf(" CAM"); + case IEEE80211_AUTH_WPA: + ireq.i_type = IEEE80211_IOC_WPA; + if (ioctl(s, SIOCG80211, &ireq) != -1) + wpa = ireq.i_val; + if (!wpa) + wpa = 1; /* default to WPA1 */ + switch (wpa) { + case 2: + LINE_CHECK("%cauthmode WPA2/802.11i", + spacer); + break; + case 3: + LINE_CHECK("%cauthmode WPA1+WPA2/802.11i", + spacer); + break; + default: + LINE_CHECK("%cauthmode WPA", spacer); + break; + } break; - case IEEE80211_POWERSAVE_PSP: - printf(" PSP"); - break; - case IEEE80211_POWERSAVE_PSP_CAM: - printf(" PSP-CAM"); - break; - } - - ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) - printf(" powersavesleep %d", ireq.i_val); - } - } - - printf("\n"); - - spacer = '\t'; - ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - printf("%crtsthreshold %d", spacer, ireq.i_val); - spacer = ' '; - } - - ireq.i_type = IEEE80211_IOC_PROTMODE; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - printf("%cprotmode", spacer); - switch (ireq.i_val) { - case IEEE80211_PROTMODE_OFF: - printf(" OFF"); - break; - case IEEE80211_PROTMODE_CTS: - printf(" CTS"); - break; - case IEEE80211_PROTMODE_RTSCTS: - printf(" RTSCTS"); + case IEEE80211_AUTH_AUTO: + LINE_CHECK("%cauthmode AUTO", spacer); break; default: - printf(" UNKNOWN"); + LINE_CHECK("%cauthmode UNKNOWN (0x%x)", + spacer, ireq.i_val); break; } - spacer = ' '; - } - - ireq.i_type = IEEE80211_IOC_TXPOWER; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - printf("%ctxpower %d", spacer, ireq.i_val); - spacer = ' '; } - if (spacer != '\t') - printf("\n"); - ireq.i_type = IEEE80211_IOC_WEP; if (ioctl(s, SIOCG80211, &ireq) != -1 && ireq.i_val != IEEE80211_WEP_NOSUP) { - printf("\twepmode"); + int firstkey; + switch (ireq.i_val) { case IEEE80211_WEP_OFF: - printf(" OFF"); + LINE_CHECK("%cprivacy OFF", spacer); break; case IEEE80211_WEP_ON: - printf(" ON"); + LINE_CHECK("%cprivacy ON", spacer); break; case IEEE80211_WEP_MIXED: - printf(" MIXED"); + LINE_CHECK("%cprivacy MIXED", spacer); break; default: - printf(" UNKNOWN"); + LINE_CHECK("%cprivacy UNKNOWN (0x%x)", + spacer, ireq.i_val); break; } @@ -475,7 +1410,10 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused) warn("WEP support, but no tx key!"); goto end; } - printf(" weptxkey %d", ireq.i_val+1); + if (ireq.i_val != -1) + LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1); + else if (verbose) + LINE_CHECK("%cdeftxkey UNDEF", spacer); ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; if (ioctl(s, SIOCG80211, &ireq) < 0) { @@ -484,28 +1422,201 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused) } num = ireq.i_val; - printf("\n"); - - ireq.i_type = IEEE80211_IOC_WEPKEY; - spacer = '\t'; + firstkey = 1; for (i = 0; i < num; i++) { - ireq.i_val = i; + struct ieee80211req_key ik; + + memset(&ik, 0, sizeof(ik)); + ik.ik_keyix = i; + ireq.i_type = IEEE80211_IOC_WPAKEY; + ireq.i_data = &ik; + ireq.i_len = sizeof(ik); if (ioctl(s, SIOCG80211, &ireq) < 0) { warn("WEP support, but can get keys!"); goto end; } - if (ireq.i_len == 0 || - ireq.i_len > IEEE80211_KEYBUF_SIZE) - continue; - printf("%cwepkey %d:%s", spacer, i+1, - ireq.i_len <= 5 ? "40-bit" : - ireq.i_len <= 13 ? "104-bit" : "128-bit"); - if (spacer == '\t') + if (ik.ik_keylen != 0) { + if (verbose) + LINE_BREAK(); + printkey(&ik); + firstkey = 0; + } + } + } + + ireq.i_type = IEEE80211_IOC_POWERSAVE; + if (ioctl(s, SIOCG80211, &ireq) != -1 && + ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { + if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { + switch (ireq.i_val) { + case IEEE80211_POWERSAVE_OFF: + LINE_CHECK("%cpowersavemode OFF", + spacer); + break; + case IEEE80211_POWERSAVE_CAM: + LINE_CHECK("%cpowersavemode CAM", + spacer); + break; + case IEEE80211_POWERSAVE_PSP: + LINE_CHECK("%cpowersavemode PSP", + spacer); + break; + case IEEE80211_POWERSAVE_PSP_CAM: + LINE_CHECK("%cpowersavemode PSP-CAM", + spacer); + break; + } + ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; + if (ioctl(s, SIOCG80211, &ireq) != -1) + LINE_CHECK("%cpowersavesleep %d", + spacer, ireq.i_val); + } + } + + ireq.i_type = IEEE80211_IOC_TXPOWMAX; + if (ioctl(s, SIOCG80211, &ireq) != -1) + LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val); + + if (verbose) { + ireq.i_type = IEEE80211_IOC_TXPOWER; + if (ioctl(s, SIOCG80211, &ireq) != -1) + LINE_CHECK("%ctxpower %d", spacer, ireq.i_val); + } + + ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (ireq.i_val != IEEE80211_RTS_MAX || verbose) + LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val); + } + + if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) { + ireq.i_type = IEEE80211_IOC_PROTMODE; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + switch (ireq.i_val) { + case IEEE80211_PROTMODE_OFF: + LINE_CHECK("%cprotmode OFF", spacer); + break; + case IEEE80211_PROTMODE_CTS: + LINE_CHECK("%cprotmode CTS", spacer); + break; + case IEEE80211_PROTMODE_RTSCTS: + LINE_CHECK("%cprotmode RTSCTS", spacer); + break; + default: + LINE_CHECK("%cprotmode UNKNOWN (0x%x)", + spacer, ireq.i_val); + break; + } + } + } + + ireq.i_type = IEEE80211_IOC_WME; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + wme = ireq.i_val; + if (wme) + LINE_CHECK("%cwme", spacer); + else if (verbose) + LINE_CHECK("%c-wme", spacer); + } else + wme = 0; + + if (opmode == IEEE80211_M_HOSTAP) { + ireq.i_type = IEEE80211_IOC_HIDESSID; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (ireq.i_val) + LINE_CHECK("%cssid HIDE", spacer); + else if (verbose) + LINE_CHECK("%cssid SHOW", spacer); + } + + ireq.i_type = IEEE80211_IOC_APBRIDGE; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (!ireq.i_val) + LINE_CHECK("%c-apbridge", spacer); + else if (verbose) + LINE_CHECK("%capbridge", spacer); + } + + ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; + if (ioctl(s, SIOCG80211, &ireq) != -1) + LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val); + } else { + ireq.i_type = IEEE80211_IOC_ROAMING; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { + switch (ireq.i_val) { + case IEEE80211_ROAMING_DEVICE: + LINE_CHECK("%croaming DEVICE", spacer); + break; + case IEEE80211_ROAMING_AUTO: + LINE_CHECK("%croaming AUTO", spacer); + break; + case IEEE80211_ROAMING_MANUAL: + LINE_CHECK("%croaming MANUAL", spacer); + break; + default: + LINE_CHECK("%croaming UNKNOWN (0x%x)", + spacer, ireq.i_val); + break; + } + } + } + } + ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (ireq.i_val) + LINE_CHECK("%cbintval %u", spacer, ireq.i_val); + else if (verbose) + LINE_CHECK("%cbintval %u", spacer, ireq.i_val); + } + + if (wme && verbose) { + LINE_BREAK(); + list_wme(s); + } + + if (wpa) { + ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (ireq.i_val) + LINE_CHECK("%ccountermeasures", spacer); + else if (verbose) + LINE_CHECK("%c-countermeasures", spacer); + } +#if 0 + /* XXX not interesting with WPA done in user space */ + ireq.i_type = IEEE80211_IOC_KEYMGTALGS; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + } + + ireq.i_type = IEEE80211_IOC_MCASTCIPHER; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + printf("%cmcastcipher ", spacer); + printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); + spacer = ' '; + } + + ireq.i_type = IEEE80211_IOC_UCASTCIPHER; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + printf("%cucastcipher ", spacer); + printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); + } + + if (wpa & 2) { + ireq.i_type = IEEE80211_IOC_RSNCAPS; + if (ioctl(s, SIOCG80211, &ireq) != -1) { + printf("%cRSN caps 0x%x", spacer, ireq.i_val); spacer = ' '; + } + } + + ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; + if (ioctl(s, SIOCG80211, &ireq) != -1) { } - if (spacer == ' ') - printf("\n"); +#endif + LINE_BREAK(); } + LINE_BREAK(); end: return; @@ -607,3 +1718,78 @@ 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("weptxkey", set80211weptxkey), + DEF_CMD_ARG("wepkey", set80211wepkey), + DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ + DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ + DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), + DEF_CMD_ARG("protmode", set80211protmode), + DEF_CMD_ARG("txpower", set80211txpower), + DEF_CMD_ARG("roaming", set80211roaming), + DEF_CMD("wme", 1, set80211wme), + DEF_CMD("-wme", 0, set80211wme), + DEF_CMD("hidessid", 1, set80211hidessid), + DEF_CMD("-hidessid", 0, set80211hidessid), + DEF_CMD("apbridge", 1, set80211apbridge), + DEF_CMD("-apbridge", 0, set80211apbridge), + DEF_CMD_ARG("chanlist", set80211chanlist), + DEF_CMD_ARG("bssid", set80211bssid), + DEF_CMD_ARG("ap", set80211bssid), + DEF_CMD("scan", 0, set80211scan), + DEF_CMD_ARG("list", set80211list), + DEF_CMD_ARG2("cwmin", set80211cwmin), + DEF_CMD_ARG2("cwmax", set80211cwmax), + DEF_CMD_ARG2("aifs", set80211aifs), + DEF_CMD_ARG2("txoplimit", set80211txoplimit), + DEF_CMD("acm", 1, set80211acm), + DEF_CMD("-acm", 0, set80211acm), + DEF_CMD("ack", 1, set80211ackpolicy), + DEF_CMD("-ack", 0, set80211ackpolicy), + DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), + DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), + DEF_CMD_ARG2("bss:aifs", set80211bssaifs), + DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), + DEF_CMD_ARG("dtimperiod", set80211dtimperiod), + DEF_CMD_ARG("bintval", set80211bintval), + DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), + DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), + DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), + DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), + DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), + DEF_CMD_ARG("mac:add", set80211addmac), + DEF_CMD_ARG("mac:del", set80211delmac), +#if 0 + DEF_CMD_ARG("mac:kick", set80211kickmac), +#endif +}; +static struct afswtch af_ieee80211 = { + .af_name = "af_ieee80211", + .af_af = AF_UNSPEC, + .af_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 +} diff --git a/sbin/ifconfig/ifmac.c b/sbin/ifconfig/ifmac.c index 41b718b..4e5de09 100644 --- a/sbin/ifconfig/ifmac.c +++ b/sbin/ifconfig/ifmac.c @@ -49,8 +49,8 @@ #include "ifconfig.h" -void -maclabel_status(int s, struct rt_addrinfo *info) +static void +maclabel_status(int s, const struct rt_addrinfo *info) { struct ifreq ifr; mac_t label; @@ -77,7 +77,7 @@ mac_free: mac_free(label); } -void +static void setifmaclabel(const char *val, int d, int s, const struct afswtch *rafp) { struct ifreq ifr; @@ -98,3 +98,24 @@ setifmaclabel(const char *val, int d, int s, const struct afswtch *rafp) if (error == -1) perror("setifmac"); } + +static struct cmd mac_cmds[] = { + DEF_CMD_ARG("maclabel", setifmaclabel), +}; +static struct afswtch af_mac = { + .af_name = "af_maclabel", + .af_af = AF_UNSPEC, + .af_status = maclabel_status, +}; + +static __constructor void +mac_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(mac_cmds); i++) + cmd_register(&mac_cmds[i]); + af_register(&af_mac); +#undef N +} diff --git a/sbin/ifconfig/ifmedia.c b/sbin/ifconfig/ifmedia.c index cdbfc53..7deddd8 100644 --- a/sbin/ifconfig/ifmedia.c +++ b/sbin/ifconfig/ifmedia.c @@ -102,8 +102,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, const struct rt_addrinfo *info __unused) { struct ifmediareq ifmr; int *media_list, i; @@ -190,7 +190,7 @@ media_status(int s, struct rt_addrinfo *info __unused) free(media_list); } -void +static void setmedia(const char *val, int d, int s, const struct afswtch *afp) { struct ifmediareq ifmr; @@ -232,14 +232,14 @@ setmedia(const char *val, int d, int s, const struct afswtch *afp) err(1, "SIOCSIFMEDIA (media)"); } -void +static void setmediaopt(const char *val, int d, int s, const struct afswtch *afp) { domediaopt(val, 0, s); } -void +static void unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) { @@ -291,7 +291,7 @@ domediaopt(const char *val, int clear, int s) } -void +static void setmediamode(const char *val, int d, int s, const struct afswtch *afp) { struct ifmediareq ifmr; @@ -777,3 +777,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_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 +} diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c index 7e089b9..59afb79 100644 --- a/sbin/ifconfig/ifvlan.c +++ b/sbin/ifconfig/ifvlan.c @@ -61,8 +61,8 @@ static const char rcsid[] = static int __tag = 0; static int __have_tag = 0; -void -vlan_status(int s, struct rt_addrinfo *info __unused) +static void +vlan_status(int s, const struct rt_addrinfo *info __unused) { struct vlanreq vreq; @@ -79,7 +79,7 @@ vlan_status(int s, struct rt_addrinfo *info __unused) return; } -void +static void setvlantag(const char *val, int d, int s, const struct afswtch *afp) { u_int16_t tag; @@ -102,7 +102,7 @@ setvlantag(const char *val, int d, int s, const struct afswtch *afp) return; } -void +static void setvlandev(const char *val, int d, int s, const struct afswtch *afp) { struct vlanreq vreq; @@ -125,7 +125,7 @@ setvlandev(const char *val, int d, int s, const struct afswtch *afp) return; } -void +static void unsetvlandev(const char *val, int d, int s, const struct afswtch *afp) { struct vlanreq vreq; @@ -144,3 +144,30 @@ unsetvlandev(const char *val, int d, int s, const struct afswtch *afp) return; } + +static struct cmd vlan_cmds[] = { + DEF_CMD_ARG("vlan", setvlantag), + DEF_CMD_ARG("vlandev", setvlandev), + DEF_CMD_ARG("-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_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); +#undef N +} |