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