diff options
Diffstat (limited to 'network_cmds/ifconfig.tproj')
-rw-r--r-- | network_cmds/ifconfig.tproj/af_inet.c | 316 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/af_inet6.c | 753 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/af_link.c | 164 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/if6lowpan.c | 178 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifbond.c | 284 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifbridge.c | 952 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifclone.c | 170 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifconfig.8 | 1109 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifconfig.c | 2692 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifconfig.h | 186 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/iffake.c | 138 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifmedia.c | 872 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/ifvlan.c | 207 | ||||
-rw-r--r-- | network_cmds/ifconfig.tproj/nexus.c | 98 |
14 files changed, 8119 insertions, 0 deletions
diff --git a/network_cmds/ifconfig.tproj/af_inet.c b/network_cmds/ifconfig.tproj/af_inet.c new file mode 100644 index 0000000..621bd16 --- /dev/null +++ b/network_cmds/ifconfig.tproj/af_inet.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2009-2011, 2020 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * 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. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ifaddrs.h> + +#include <netinet/in.h> +#include <net/if_var.h> /* for struct ifaddr */ +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "ifconfig.h" + +static struct ifaliasreq in_addreq; +static struct ifreq in_ridreq; + +static void +in_status(int s __unused, const struct ifaddrs *ifa) +{ + struct sockaddr_in *sin, null_sin; + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in *)ifa->ifa_addr; + if (sin == NULL) + return; + + printf("\tinet %s ", inet_ntoa(sin->sin_addr)); + + if (ifa->ifa_flags & IFF_POINTOPOINT) { + sin = (struct sockaddr_in *)ifa->ifa_dstaddr; + if (sin == NULL) + sin = &null_sin; + printf("--> %s ", inet_ntoa(sin->sin_addr)); + } + + sin = (struct sockaddr_in *)ifa->ifa_netmask; + if (sin == NULL) + sin = &null_sin; + printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); + + if (ifa->ifa_flags & IFF_BROADCAST) { + sin = (struct sockaddr_in *)ifa->ifa_broadaddr; + if (sin != NULL && sin->sin_addr.s_addr != 0) + printf("broadcast %s", inet_ntoa(sin->sin_addr)); + } + putchar('\n'); +} + +#define SIN(x) ((struct sockaddr_in *) &(x)) +static struct sockaddr_in *sintab[] = { + SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), + SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) +}; + +static void +in_getaddr(const char *s, int which) +{ +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif /* MIN */ + 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)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + 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)); + strlcpy(addreq.ifra_name, name, sizeof(addreq.ifra_name)); + 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 void +in_set_router(int s, int enable) +{ + struct ifreq ifr; + + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_intval = enable; + + if (ioctl(s, SIOCSETROUTERMODE, &ifr) < 0) + warn("SIOCSETROUTERMODE"); +} + +static int +routermode_from_string(char * str, int *mode_p) +{ + int success = 1; + + if (strcasecmp(str, "enabled") == 0) { + *mode_p = 1; + } else if (strcasecmp(str, "disabled") == 0) { + *mode_p = 0; + } else { + success = 0; + } + return (success); +} + +static const char * +routermode_string(int mode) +{ + const char * str; + + switch (mode) { + case 0: + str = "disabled"; + break; + case 1: + str = "enabled"; + break; + default: + str = "<unknown>"; + break; + } + return str; +} + +static int +in_routermode(int s, int argc, char *const*argv) +{ + struct ifreq ifr; + int ret; + + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (argc == 0) { + ret = 0; +#ifndef SIOCGETROUTERMODE +#define SIOCGETROUTERMODE _IOWR('i', 209, struct ifreq) /* get IPv4 router mode state */ +#endif /* SIOCGETROUTERMODE */ + if (ioctl(s, SIOCGETROUTERMODE, &ifr) < 0) { + if (argv != NULL) { + warn("SIOCGETROUTERMODE"); + } + } else { + /* argv is NULL if we're called from status() */ + printf("%s%s\n", + (argv == NULL) ? "\troutermode4: " : "", + routermode_string(ifr.ifr_intval)); + } + ret = 0; + } else { + int mode; + + if (routermode_from_string(argv[0], &mode) == 0) { + errx(EXIT_FAILURE, + "mode '%s' invalid, must be one of " + "disabled or enabled", + argv[0]); + } + ifr.ifr_intval = mode; + if (ioctl(s, SIOCSETROUTERMODE, &ifr) < 0) { + warn("SIOCSETROUTERMODE"); + } + ret = 1; + } + return ret; +} + +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_setrouter = in_set_router, + .af_routermode = in_routermode, + .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/network_cmds/ifconfig.tproj/af_inet6.c b/network_cmds/ifconfig.tproj/af_inet6.c new file mode 100644 index 0000000..c32c5c0 --- /dev/null +++ b/network_cmds/ifconfig.tproj/af_inet6.c @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2009-2017, 2020 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * 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. + */ + + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ifaddrs.h> + +#include <arpa/inet.h> + +#include <netinet/in.h> +#include <net/if_var.h> /* for struct ifaddr */ +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */ + +#include "ifconfig.h" + +#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \ + "\004IFDISABLED\005DONT_SET_IFROUTE\006PROXY_PREFIXES" \ + "\007IGNORE_NA\010INSECURE\011REPLICATED\012DAD" + +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 +setnd6flags(const char *dummyaddr __unused, int d, int s, + const struct afswtch *afp) +{ + struct in6_ndireq nd; + int error; + + memset(&nd, 0, sizeof(nd)); + strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); + error = ioctl(s, SIOCGIFINFO_IN6, &nd); + if (error) { + warn("ioctl(SIOCGIFINFO_IN6)"); + return; + } + if (d < 0) + nd.ndi.flags &= ~(-d); + else + nd.ndi.flags |= d; + error = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd); + if (error) + warn("ioctl(SIOCSIFINFO_FLAGS)"); +} + +static void +setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused, + const struct afswtch *afp) +{ + if (afp->af_af != AF_INET6) + err(1, "address flags can be set only for inet6 addresses"); + + if (flag < 0) + in6_addreq.ifra_flags &= ~(-flag); + else + in6_addreq.ifra_flags |= flag; +} + +static void +setip6lifetime(const char *cmd, const char *val, int s, + const struct afswtch *afp) +{ + time_t newval, t; + char *ep; + + t = time(NULL); + newval = (time_t)strtoul(val, &ep, 0); + if (val == ep) + errx(1, "invalid %s", cmd); + if (afp->af_af != AF_INET6) + errx(1, "%s not allowed for the AF", cmd); + if (strcmp(cmd, "vltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_expire = t + newval; + in6_addreq.ifra_lifetime.ia6t_vltime = newval; + } else if (strcmp(cmd, "pltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; + in6_addreq.ifra_lifetime.ia6t_pltime = newval; + } +} + +static void +setip6pltime(const char *seconds, int dummy __unused, int s, + const struct afswtch *afp) +{ + setip6lifetime("pltime", seconds, s, afp); +} + +static void +setip6vltime(const char *seconds, int dummy __unused, int s, + const struct afswtch *afp) +{ + setip6lifetime("vltime", seconds, s, afp); +} + +static void +setip6eui64(const char *cmd, int dummy __unused, int s, + const struct afswtch *afp) +{ + struct ifaddrs *ifap, *ifa; + const struct sockaddr_in6 *sin6 = NULL; + const struct in6_addr *lladdr = NULL; + struct in6_addr *in6; + + if (afp->af_af != AF_INET6) + errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); + in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; + if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) + errx(EXIT_FAILURE, "interface index is already filled"); + if (getifaddrs(&ifap) != 0) + err(EXIT_FAILURE, "getifaddrs"); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_INET6 && + strcmp(ifa->ifa_name, name) == 0) { + sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + lladdr = &sin6->sin6_addr; + break; + } + } + } + if (!lladdr) + errx(EXIT_FAILURE, "could not determine link local address"); + + memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); + + freeifaddrs(ifap); +} + +static void +in6_fillscopeid(struct sockaddr_in6 *sin6) +{ +#if defined(__KAME__) && defined(KAME_SCOPEID) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} + +static void +in6_status(int s __unused, const struct ifaddrs *ifa) +{ + struct sockaddr_in6 *sin, null_sin; + struct in6_ifreq ifr6; + int s6; + u_int32_t flags6; + struct in6_addrlifetime lifetime; + time_t t = time(NULL); + int error; + u_int32_t scopeid; + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in6 *)ifa->ifa_addr; + if (sin == NULL) + return; + + strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + warn("socket(AF_INET6,SOCK_DGRAM)"); + return; + } + ifr6.ifr_addr = *sin; + if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + warn("ioctl(SIOCGIFAFLAG_IN6)"); + close(s6); + return; + } + flags6 = ifr6.ifr_ifru.ifru_flags6; + memset(&lifetime, 0, sizeof(lifetime)); + ifr6.ifr_addr = *sin; + if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { + warn("ioctl(SIOCGIFALIFETIME_IN6)"); + close(s6); + return; + } + lifetime = ifr6.ifr_ifru.ifru_lifetime; + close(s6); + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && + *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { + u_short index; + + index = *(u_short *)&sin->sin6_addr.s6_addr[2]; + *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = ntohs(index); + } + scopeid = sin->sin6_scope_id; + + error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, + sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); + if (error != 0) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("\tinet6 %s ", addr_buf); + + if (ifa->ifa_flags & IFF_POINTOPOINT) { + sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr; + /* + * some of the interfaces do not have valid destination + * address. + */ + if (sin != NULL && sin->sin6_family == AF_INET6) { + int error; + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && + *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { + u_short index; + + index = *(u_short *)&sin->sin6_addr.s6_addr[2]; + *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = ntohs(index); + } + + error = getnameinfo((struct sockaddr *)sin, + sin->sin6_len, addr_buf, + sizeof(addr_buf), NULL, 0, + NI_NUMERICHOST); + if (error != 0) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("--> %s ", addr_buf); + } + } + + sin = (struct sockaddr_in6 *)ifa->ifa_netmask; + if (sin == NULL) + sin = &null_sin; + printf("prefixlen %d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); + + if ((flags6 & IN6_IFF_ANYCAST) != 0) + printf("anycast "); + if ((flags6 & IN6_IFF_TENTATIVE) != 0) + printf("tentative "); + if ((flags6 & IN6_IFF_OPTIMISTIC) != 0) + printf("optimistic "); + 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 ((flags6 & IN6_IFF_DYNAMIC) != 0) + printf("dynamic "); + if ((flags6 & IN6_IFF_SECURED) != 0) + printf("secured "); + if ((flags6 & IN6_IFF_CLAT46) != 0) + printf("clat46 "); + + 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 += snprintf(p, sizeof(result) - (p - result), "%dd", days); + } + if (!first || hours) { + first = 0; + p += snprintf(p, sizeof(result) - (p - result), "%dh", hours); + } + if (!first || mins) { + first = 0; + p += snprintf(p, sizeof(result) - (p - result), "%dm", mins); + } + snprintf(p, sizeof(result) - (p - result), "%ds", secs); + } else + snprintf(result, sizeof(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)); + strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name)); + + 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 +nd6_status(int s) +{ + struct in6_ndireq nd; + int s6; + int error; + + memset(&nd, 0, sizeof(nd)); + strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if (errno != EPROTONOSUPPORT) + warn("socket(AF_INET6, SOCK_DGRAM)"); + return; + } + error = ioctl(s6, SIOCGIFINFO_IN6, &nd); + if (error) { + if (errno != EPFNOSUPPORT && errno != EINVAL) + warn("ioctl(SIOCGIFINFO_IN6)"); + close(s6); + return; + } + close(s6); + if (nd.ndi.flags == 0) + return; + printb("\tnd6 options", (unsigned int)nd.ndi.flags, ND6BITS); + putchar('\n'); +} + +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)); + strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name)); + 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"); +} + +#ifndef IPV6_ROUTER_MODE_EXCLUSIVE +#define IPV6_ROUTER_MODE_DISABLED 0 +#define IPV6_ROUTER_MODE_EXCLUSIVE 1 +#define IPV6_ROUTER_MODE_HYBRID 2 +#endif /* IPV6_ROUTER_MODE_EXCLUSIVE */ + +static void +in6_set_router(int s, int enable) +{ + struct ifreq ifr; + + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_intval = (enable == 0) + ? IPV6_ROUTER_MODE_DISABLED + : IPV6_ROUTER_MODE_EXCLUSIVE; + + if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0) + warn("SIOCSETROUTERMODE_IN6"); +} + +static int +routermode_from_string(char * str, int *mode_p) +{ + int success = 1; + + if (strcasecmp(str, "exclusive") == 0 || + strcasecmp(str, "enabled") == 0) { + *mode_p = IPV6_ROUTER_MODE_EXCLUSIVE; + } else if (strcasecmp(str, "hybrid") == 0) { + *mode_p = IPV6_ROUTER_MODE_HYBRID; + } else if (strcasecmp(str, "disabled") == 0) { + *mode_p = IPV6_ROUTER_MODE_DISABLED; + } else { + success = 0; + } + return (success); +} + +static const char * +routermode_string(int mode) +{ + const char * str; + + switch (mode) { + case IPV6_ROUTER_MODE_EXCLUSIVE: + str = "enabled"; + break; + case IPV6_ROUTER_MODE_HYBRID: + str = "hybrid"; + break; + case IPV6_ROUTER_MODE_DISABLED: + str = "disabled"; + break; + default: + str = "<unknown>"; + break; + } + return str; +} + +static int +in6_routermode(int s, int argc, char *const*argv) +{ + struct in6_ifreq ifr; + int ret; + + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (argc == 0) { + ret = 0; +#ifndef SIOCGETROUTERMODE_IN6 +#define SIOCGETROUTERMODE_IN6 _IOWR('i', 137, struct in6_ifreq) +#endif /* SIOCGETROUTERMODE_IN6 */ + if (ioctl(s, SIOCGETROUTERMODE_IN6, &ifr) < 0) { + if (argv != NULL) { + warn("SIOCGETROUTERMODE_IN6"); + } + } else { + /* argv is NULL if we're called from status() */ + printf("%s%s\n", + (argv == NULL) ? "\troutermode6: " : "", + routermode_string(ifr.ifr_intval)); + } + ret = 0; + } else { + int mode; + + if (routermode_from_string(argv[0], &mode) == 0) { + errx(EXIT_FAILURE, + "mode '%s' invalid, must be one of " + "disabled, exclusive, or hybrid", + argv[0]); + } + ifr.ifr_intval = mode; + if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0) { + warn("SIOCSETROUTERMODE_IN6"); + } + ret = 1; + } + return ret; +} + +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), + /* RFC 4429, section 3.1, says: + * "Optimistic DAD SHOULD NOT be used for manually entered + * addresses." + * it's not a MUST... + */ + DEF_CMD("optimistic", IN6_IFF_OPTIMISTIC, setip6flags), + DEF_CMD("-optimistic", -IN6_IFF_OPTIMISTIC, 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("nud", ND6_IFF_PERFORMNUD, setnd6flags), + DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags), + DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags), + DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags), + DEF_CMD("replicated", ND6_IFF_REPLICATED, setnd6flags), + DEF_CMD("-replicated", -ND6_IFF_REPLICATED, setnd6flags), + DEF_CMD("proxy_prefixes", ND6_IFF_PROXY_PREFIXES, setnd6flags), + DEF_CMD("-proxy_prefixes", -ND6_IFF_PROXY_PREFIXES, setnd6flags), + DEF_CMD("insecure", ND6_IFF_INSECURE, setnd6flags), + DEF_CMD("-insecure", -ND6_IFF_INSECURE, setnd6flags), + DEF_CMD_ARG("pltime", setip6pltime), + DEF_CMD_ARG("vltime", setip6vltime), + DEF_CMD("eui64", 0, setip6eui64), + DEF_CMD("secured", IN6_IFF_SECURED, setip6flags), + DEF_CMD("-secured", -IN6_IFF_SECURED, setip6flags), + DEF_CMD("dad", ND6_IFF_DAD, setnd6flags), + DEF_CMD("-dad", -ND6_IFF_DAD, setnd6flags), +}; + +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_other_status = nd6_status, + .af_postproc = in6_postproc, + .af_status_tunnel = in6_status_tunnel, + .af_settunnel = in6_set_tunnel, + .af_setrouter = in6_set_router, + .af_routermode = in6_routermode, + .af_difaddr = SIOCDIFADDR_IN6, + .af_aifaddr = SIOCAIFADDR_IN6, + .af_ridreq = &in6_ridreq, + .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/network_cmds/ifconfig.tproj/af_link.c b/network_cmds/ifconfig.tproj/af_link.c new file mode 100644 index 0000000..ca9444c --- /dev/null +++ b/network_cmds/ifconfig.tproj/af_link.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2009 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * 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. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ifaddrs.h> + +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/ethernet.h> + +#include "ifconfig.h" + +static struct ifreq link_ridreq; + +static void +link_status(int s __unused, const struct ifaddrs *ifa) +{ + /* XXX no const 'cuz LLADDR is defined wrong */ + struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr; + + if (sdl != NULL && sdl->sdl_alen > 0) { +#ifdef notyet + 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); + } +#else + char *cp = (char *)LLADDR(sdl); + int n = sdl->sdl_alen; + + if (sdl->sdl_type == IFT_ETHER) + printf ("\tether "); + else + printf ("\tlladdr "); + while (--n >= 0) + printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' '); + putchar('\n'); +#endif + } +} + +static void +link_getaddr(const char *addr, int which) +{ + char *temp; + struct sockaddr_dl sdl; + struct sockaddr *sa = &link_ridreq.ifr_addr; + size_t slen = strlen(addr); + + if (which != ADDR) + errx(1, "can't set link-level netmask or broadcast"); + if ((temp = malloc(slen + 2)) == NULL) + errx(1, "malloc failed"); + temp[0] = ':'; + strlcpy(temp + 1, addr, slen + 1); + 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/network_cmds/ifconfig.tproj/if6lowpan.c b/network_cmds/ifconfig.tproj/if6lowpan.c new file mode 100644 index 0000000..f0f4b2e --- /dev/null +++ b/network_cmds/ifconfig.tproj/if6lowpan.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2017-2018 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (c) 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_6lowpan_var.h> +#include <net/route.h> + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> + +#include "ifconfig.h" + +#include <sys/cdefs.h> + + +static boolean_t is_sixlowpan_inited = FALSE; +static struct sixlowpanreq params; + +static int +get6lowpan(int s, struct ifreq *ifr, struct sixlowpanreq *req) +{ + bzero((char *)req, sizeof(*req)); + ifr->ifr_data = (caddr_t)req; + return ioctl(s, SIOCGIF6LOWPAN, (caddr_t)ifr); +} + +static void +sixlowpan_status(int s) +{ + struct sixlowpanreq req; + + if (get6lowpan(s, &ifr, &req) != -1) + printf("\t6lowpan: parent interface: %s\n", + req.parent[0] == '\0' ? + "<none>" : req.parent); +} + + +static void +set6lowpandev(const char *val, int d, int s, const struct afswtch *afp) +{ + struct sixlowpanreq req; + + strlcpy(params.parent, val, sizeof(params.parent)); + is_sixlowpan_inited = TRUE; + fprintf(stderr, "val %s\n", val); + + strlcpy(req.parent, val, sizeof(req.parent)); + ifr.ifr_data = (caddr_t) &req; + if (ioctl(s, SIOCSIF6LOWPAN, (caddr_t)&ifr) == -1) + err(1, "SIOCSIF6LOWPAN"); +} + +static void +unset6lowpandev(const char *val, int d, int s, const struct afswtch *afp) +{ + struct sixlowpanreq req; + + bzero((char *)&req, sizeof(req)); + ifr.ifr_data = (caddr_t)&req; + + if (ioctl(s, SIOCGIF6LOWPAN, (caddr_t)&ifr) == -1) + err(1, "SIOCGIF6LOWPAN"); + + bzero((char *)&req, sizeof(req)); + if (ioctl(s, SIOCSIF6LOWPAN, (caddr_t)&ifr) == -1) + err(1, "SIOCSIF6LOWPAN"); +} + +static void +sixlowpan_create(const char *val, int d, int s, const struct afswtch *afp) +{ + strlcpy(params.parent, val, sizeof(params.parent)); + is_sixlowpan_inited = TRUE; +} + +static void +sixlowpan_clone_cb(int s, void *arg) +{ + if (is_sixlowpan_inited == TRUE && params.parent[0] == '\0') + errx(1, "6lowpandev must be specified"); +} + +static struct cmd sixlowpan_cmds[] = { + DEF_CLONE_CMD_ARG("6lowpandev", sixlowpan_create), + DEF_CMD_OPTARG("6lowpansetdev", set6lowpandev), + DEF_CMD_OPTARG("6lowpanunsetdev", unset6lowpandev), +}; +static struct afswtch af_6lowpan = { + .af_name = "af_6lowpan", + .af_af = AF_UNSPEC, + .af_other_status = sixlowpan_status, +}; + +static __constructor void +sixlowpan_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(sixlowpan_cmds); i++) + cmd_register(&sixlowpan_cmds[i]); + af_register(&af_6lowpan); + callback_register(sixlowpan_clone_cb, NULL); +#undef N +} diff --git a/network_cmds/ifconfig.tproj/ifbond.c b/network_cmds/ifconfig.tproj/ifbond.c new file mode 100644 index 0000000..b8bcdfe --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifbond.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * ifbond.c + * - add and remove interfaces from a bond interface + */ + +/* + * Modification History: + * + * July 14, 2004 Dieter Siegmund (dieter@apple.com) + * - created + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_bond_var.h> + +#include <net/route.h> + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> + +#include "ifconfig.h" +extern int bond_details; + +#define EA_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x" +#define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)]) +#define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5) + +static __inline__ const char * +selected_state_string(u_char s) +{ + static const char * names[] = { "unselected", "selected", "standby" }; + + if (s <= IF_BOND_STATUS_SELECTED_STATE_STANDBY) { + return (names[s]); + } + return ("<unknown>"); +} + +static void +bond_print_details(struct if_bond_status * ibs_p, int count) + +{ + int i; + struct if_bond_status * scan_p = ibs_p; + + for (i = 0; i < count; i++, scan_p++) { + struct if_bond_partner_state * ps; + ps = &scan_p->ibs_partner_state; + printf("\tbond interface: %s priority: 0x%04x " + "state: 0x%02x partner system: 0x%04x," + EA_FORMAT " " + "key: 0x%04x port: 0x%04x priority: 0x%04x " + "state: 0x%02x\n", + scan_p->ibs_if_name, scan_p->ibs_port_priority, + scan_p->ibs_state, ps->ibps_system_priority, + EA_LIST(&ps->ibps_system), ps->ibps_key, + ps->ibps_port, ps->ibps_port_priority, + ps->ibps_state); + } + return; +} + +void +bond_status(int s) +{ + int i; + struct if_bond_req ibr; + struct if_bond_status * ibs_p; + struct if_bond_status_req * ibsr_p; + char mode_buf[16]; + const char * mode_str; + + bzero((char *)&ibr, sizeof(ibr)); + ibr.ibr_op = IF_BOND_OP_GET_STATUS; + ibsr_p = &ibr.ibr_ibru.ibru_status; + ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION; + ifr.ifr_data = (caddr_t)&ibr; + + /* how many of them are there? */ + if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) { + return; + } + switch (ibsr_p->ibsr_mode) { + case IF_BOND_MODE_LACP: + mode_str = "lacp"; + break; + case IF_BOND_MODE_STATIC: + mode_str = "static"; + break; + default: + snprintf(mode_buf, sizeof(mode_buf), "%d", ibsr_p->ibsr_mode); + mode_str = mode_buf; + break; + } + if (ibsr_p->ibsr_total == 0) { + if (bond_details) { + printf("\tbond mode: %s\n" + "\tbond key: 0x%04x interfaces: <none>", + mode_str, ibsr_p->ibsr_key); + } + else { + printf("\tbond interfaces: <none>\n"); + } + return; + } + ibsr_p->ibsr_buffer + = (char *)malloc(sizeof(struct if_bond_status) + * ibsr_p->ibsr_total); + ibsr_p->ibsr_count = ibsr_p->ibsr_total; + + /* get the list */ + if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) { + goto done; + } + if (ibsr_p->ibsr_total > 0) { + if (bond_details) { + printf("\tbond mode: %s\n" + "\tbond key: 0x%04x interfaces:", + mode_str, ibsr_p->ibsr_key); + } + else { + printf("\tbond interfaces:"); + } + ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; + for (i = 0; i < ibsr_p->ibsr_total; i++, ibs_p++) { + printf(" %s", ibs_p->ibs_if_name); + if (bond_details) { + u_char s = ibs_p->ibs_selected_state; + printf(" (%s)", selected_state_string(s)); + } + } + printf("\n"); + if (bond_details) { + bond_print_details((struct if_bond_status *) + ibsr_p->ibsr_buffer, + ibsr_p->ibsr_total); + } + } + else if (bond_details) { + printf("\tbond mode: %s\n" + "\tbond key: 0x%04x interfaces: <none>\n", + mode_str, ibsr_p->ibsr_key); + } + else { + printf("\tbond interfaces: <none>\n"); + } + + done: + free(ibsr_p->ibsr_buffer); + return; +} + +static +DECL_CMD_FUNC(setbonddev, val, d) +{ + struct if_bond_req ibr; + + bzero((char *)&ibr, sizeof(ibr)); + if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name, + sizeof(ibr.ibr_ibru.ibru_if_name), + "%s", val) >= IFNAMSIZ) { + errx(1, "interface name too long"); + } + ibr.ibr_op = IF_BOND_OP_ADD_INTERFACE; + ifr.ifr_data = (caddr_t)&ibr; + if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) + err(1, "SIOCSIFBOND add interface"); + + return; +} + +static +DECL_CMD_FUNC(unsetbonddev, val, d) +{ + struct if_bond_req ibr; + + bzero((char *)&ibr, sizeof(ibr)); + if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name, + sizeof(ibr.ibr_ibru.ibru_if_name), + "%s", val) >= IFNAMSIZ) { + errx(1, "interface name too long"); + } + ibr.ibr_op = IF_BOND_OP_REMOVE_INTERFACE; + ifr.ifr_data = (caddr_t)&ibr; + if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) + err(1, "SIOCSIFBOND remove interface"); + + return; +} + +static +DECL_CMD_FUNC(setbondmode, val, d) +{ + struct if_bond_req ibr; + int mode; + + if (strcmp(val, "lacp") == 0) { + mode = IF_BOND_MODE_LACP; + } + else if (strcmp(val, "static") == 0) { + mode = IF_BOND_MODE_STATIC; + } + else { + mode = strtoul(val, NULL, 0); + if (errno != 0) { + errx(1, "invalid mode value " + "(must be either \"lacp\" or \"static\")"); + } + } + + bzero((char *)&ibr, sizeof(ibr)); + if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name, + sizeof(ibr.ibr_ibru.ibru_if_name), + "%s", val) >= IFNAMSIZ) { + errx(1, "interface name too long"); + } + ibr.ibr_op = IF_BOND_OP_SET_MODE; + ibr.ibr_ibru.ibru_int_val = mode; + ifr.ifr_data = (caddr_t)&ibr; + if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) + err(1, "SIOCSIFBOND set mode"); + + return; +} + +static struct cmd bond_cmds[] = { + DEF_CLONE_CMD_ARG("bonddev", setbonddev), + DEF_CLONE_CMD_ARG("-bonddev", unsetbonddev), + DEF_CMD_ARG("bondmode", setbondmode), +}; +static struct afswtch af_bond = { + .af_name = "af_bond", + .af_af = AF_UNSPEC, + .af_other_status = bond_status, +}; + +static __constructor void +bond_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(bond_cmds); i++) + cmd_register(&bond_cmds[i]); + af_register(&af_bond); +#undef N +} + diff --git a/network_cmds/ifconfig.tproj/ifbridge.c b/network_cmds/ifconfig.tproj/ifbridge.c new file mode 100644 index 0000000..951c56b --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifbridge.c @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2009-2019 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/*- + * 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. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_bridgevar.h> +#include <net/route.h> + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> + +#include <arpa/inet.h> + +#include "ifconfig.h" + +#define PV2ID(pv, epri, eaddr) do { \ + epri = pv >> 48; \ + eaddr[0] = pv >> 40; \ + eaddr[1] = pv >> 32; \ + eaddr[2] = pv >> 24; \ + eaddr[3] = pv >> 16; \ + eaddr[4] = pv >> 8; \ + eaddr[5] = pv >> 0; \ +} while (0) + +static const char *stpstates[] = { + "disabled", + "listening", + "learning", + "forwarding", + "blocking", + "discarding" +}; +static const char *stpproto[] = { + "stp", + "-", + "rstp" +}; +static const char *stproles[] = { + "disabled", + "root", + "designated", + "alternate", + "backup" +}; + +static int +get_val(const char *cp, u_long *valp) +{ + char *endptr; + u_long val; + + errno = 0; + val = strtoul(cp, &endptr, 0); + if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) + return (-1); + + *valp = val; + return (0); +} + +static int +do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) +{ + struct ifdrv ifd; + + memset(&ifd, 0, sizeof(ifd)); + + strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); + ifd.ifd_cmd = op; + ifd.ifd_len = argsize; + ifd.ifd_data = arg; + + return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); +} + +static void +do_bridgeflag(int sock, const char *ifs, int flag, int set) +{ + struct ifbreq req; + + strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); + + if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) + err(1, "unable to get bridge flags"); + + if (set) + req.ifbr_ifsflags |= flag; + else + req.ifbr_ifsflags &= ~flag; + + if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) + err(1, "unable to set bridge flags"); +} + +static void +bridge_interfaces(int s, const char *prefix) +{ + struct ifbifconf bifc; + struct ifbreq *req; + char *inbuf = NULL, *ninbuf; + char *p, *pad; + int i, len = 8192; + + pad = strdup(prefix); + if (pad == NULL) + err(1, "strdup"); + /* replace the prefix with whitespace */ + for (p = pad; *p != '\0'; p++) { + if(isprint(*p)) + *p = ' '; + } + + for (;;) { + ninbuf = realloc(inbuf, len); + if (ninbuf == NULL) + err(1, "unable to allocate interface buffer"); + bifc.ifbic_len = len; + bifc.ifbic_buf = inbuf = ninbuf; + if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0) + err(1, "unable to get interface list"); + if ((bifc.ifbic_len + sizeof(*req)) < len) + break; + len *= 2; + } + + for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) { + req = bifc.ifbic_req + i; + printf("%s%s ", prefix, req->ifbr_ifsname); + printb("flags", req->ifbr_ifsflags, IFBIFBITS); + printf("\n"); + + printf("%s", pad); + printf("ifmaxaddr %u", req->ifbr_addrmax); + printf(" port %u priority %u", req->ifbr_portno, + req->ifbr_priority); + printf(" path cost %u", req->ifbr_path_cost); + + if (req->ifbr_ifsflags & IFBIF_STP) { + if (req->ifbr_proto < + sizeof(stpproto) / sizeof(stpproto[0])) + printf(" proto %s", stpproto[req->ifbr_proto]); + else + printf(" <unknown proto %d>", + req->ifbr_proto); + + printf("\n%s", pad); + if (req->ifbr_role < + sizeof(stproles) / sizeof(stproles[0])) + printf("role %s", stproles[req->ifbr_role]); + else + printf("<unknown role %d>", + req->ifbr_role); + if (req->ifbr_state < + sizeof(stpstates) / sizeof(stpstates[0])) + printf(" state %s", stpstates[req->ifbr_state]); + else + printf(" <unknown state %d>", + req->ifbr_state); + } + printf("\n"); + + if (verbose) { + struct ifbrhostfilter ifbrfh; + struct in_addr in; + struct ether_addr ea; + + bzero(&ifbrfh, sizeof(struct ifbrhostfilter)); + strlcpy(ifbrfh.ifbrhf_ifsname, req->ifbr_ifsname, sizeof(ifbrfh.ifbrhf_ifsname)); + if (do_cmd(s, BRDGGHOSTFILTER, &ifbrfh, sizeof(ifbrfh), 0) < 0) + err(1, "unable to get host filter settings for %s", + ifbrfh.ifbrhf_ifsname); + + if (ifbrfh.ifbrhf_flags & IFBRHF_ENABLED) { + in.s_addr = ifbrfh.ifbrhf_ipsrc; + bcopy(ifbrfh.ifbrhf_hwsrca, ea.octet, ETHER_ADDR_LEN); + } else { + in.s_addr = INADDR_ANY; + bzero(ea.octet, ETHER_ADDR_LEN); + } + printf("%s", pad); + printf("hostfilter %d hw: %s ip: %s", + ifbrfh.ifbrhf_flags & IFBRHF_ENABLED ? 1 : 0, + ether_ntoa(&ea), inet_ntoa(in)); + + printf("\n"); + } + } + + free(inbuf); + free(pad); +} + +static void +bridge_addresses(int s, const char *prefix) +{ + struct ifbaconf ifbac; + struct ifbareq *ifba; + char *inbuf = NULL, *ninbuf; + int i, len = 8192; + struct ether_addr ea; + + for (;;) { + ninbuf = realloc(inbuf, len); + if (ninbuf == NULL) + err(1, "unable to allocate address buffer"); + ifbac.ifbac_len = len; + ifbac.ifbac_buf = inbuf = ninbuf; + if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0) + err(1, "unable to get address cache"); + if ((ifbac.ifbac_len + sizeof(*ifba)) < len) + break; + len *= 2; + } + + for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { + ifba = ifbac.ifbac_req + i; + memcpy(ea.octet, ifba->ifba_dst, + sizeof(ea.octet)); + printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea), + ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire); + printb("flags", ifba->ifba_flags, IFBAFBITS); + printf("\n"); + } + + free(inbuf); +} + +#define MAX_IPv6_STR_LEN INET6_ADDRSTRLEN +static void +bridge_mac_nat(int s, const char *prefix) +{ + char *buf; + unsigned int count; + struct ether_addr ea; + unsigned int i; + struct ifbrmnelist mnl; + char *scan; + + bzero(&mnl, sizeof(mnl)); + if (do_cmd(s, BRDGGMACNATLIST, &mnl, sizeof(mnl), 0) < 0) { + /* err(1, "unable to get mac nat list"); */ + return; + } + if (mnl.ifbml_len == 0) { + return; + } + printf("\tMAC NAT list:\n"); + if (mnl.ifbml_elsize == 0) { + err(1, "kernel reported zero length element size"); + } + if (mnl.ifbml_elsize < sizeof(struct ifbrmne)) { + err(1, "struct element size too small, kernel mismatch"); + } + buf = malloc(mnl.ifbml_len); + if (buf == NULL) { + err(1, "unable to allocate mac nat list buffer"); + } + mnl.ifbml_buf = buf; + if (do_cmd(s, BRDGGMACNATLIST, &mnl, sizeof(mnl), 0) < 0) { + err(1, "unable to get mac nat list"); + } + count = mnl.ifbml_len / mnl.ifbml_elsize; + for (i = 0, scan = buf; i < count; i++, scan += mnl.ifbml_elsize) { + struct ifbrmne *ifbmne = (struct ifbrmne *)scan; + char ntopbuf[INET6_ADDRSTRLEN]; + + memcpy(ea.octet, ifbmne->ifbmne_mac, + sizeof(ea.octet)); + inet_ntop(ifbmne->ifbmne_af, &ifbmne->ifbmne_ip, + ntopbuf, sizeof(ntopbuf)); + printf("%s%s %s %s %lu\n", + prefix, ifbmne->ifbmne_ifname, ntopbuf, ether_ntoa(&ea), + (unsigned long)ifbmne->ifbmne_expire); + } + free(buf); +} + +static void +bridge_status(int s) +{ + struct ifbropreq ifbp; + struct ifbrparam param; + u_int16_t pri; + u_int8_t ht, fd, ma, hc, pro; + u_int8_t lladdr[ETHER_ADDR_LEN]; + u_int16_t bprio; + u_int32_t csize, ctime; + u_int32_t ipfflags; + + if (do_cmd(s, BRDGGCACHE, ¶m, sizeof(param), 0) < 0) + return; + csize = param.ifbrp_csize; + if (do_cmd(s, BRDGGTO, ¶m, sizeof(param), 0) < 0) + return; + ctime = param.ifbrp_ctime; + if (do_cmd(s, BRDGGFILT, ¶m, sizeof(param), 0) < 0) + return; + ipfflags = param.ifbrp_filter; + if (do_cmd(s, BRDGPARAM, &ifbp, sizeof(ifbp), 0) < 0) + return; + pri = ifbp.ifbop_priority; + pro = ifbp.ifbop_protocol; + ht = ifbp.ifbop_hellotime; + fd = ifbp.ifbop_fwddelay; + hc = ifbp.ifbop_holdcount; + ma = ifbp.ifbop_maxage; + + printf("\tConfiguration:\n"); + PV2ID(ifbp.ifbop_bridgeid, bprio, lladdr); + printf("\t\tid %s priority %u hellotime %u fwddelay %u\n", + ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd); + printf("\t\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n", + ma, hc, stpproto[pro], csize, ctime); + + PV2ID(ifbp.ifbop_designated_root, bprio, lladdr); + printf("\t\troot id %s priority %d ifcost %u port %u\n", + ether_ntoa((struct ether_addr *)lladdr), bprio, + ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff); + + printf("\t\tipfilter %s flags 0x%x\n", + (ipfflags & IFBF_FILT_USEIPF) ? "enabled" : "disabled", ipfflags); + + bridge_interfaces(s, "\tmember: "); + + if (!all || verbose > 1) { + printf("\tAddress cache:\n"); + bridge_addresses(s, "\t\t"); + bridge_mac_nat(s, "\t\t"); + } + 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 notdef +static void +setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) +{ + + do_bridgeflag(s, val, IFBIF_STICKY, 1); +} + +static void +unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) +{ + + do_bridgeflag(s, val, IFBIF_STICKY, 0); +} + +static void +setbridge_span(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifbreq req; + + memset(&req, 0, sizeof(req)); + strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); + if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0) + err(1, "BRDGADDS %s", val); +} + +static void +unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifbreq req; + + memset(&req, 0, sizeof(req)); + strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); + if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0) + err(1, "BRDGDELS %s", val); +} +#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); +} + +#ifdef notdef +static void +setbridge_edge(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1); +} + +static void +unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0); +} + +static void +setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1); +} + +static void +unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0); +} + +static void +setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1); +} + +static void +unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0); +} + +static void +setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1); +} + +static void +unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) +{ + do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0); +} +#endif + +static void +setbridge_flush(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifbreq req; + + memset(&req, 0, sizeof(req)); + req.ifbr_ifsflags = IFBF_FLUSHDYN; + if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) + err(1, "BRDGFLUSH"); +} + +static void +setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifbreq req; + + memset(&req, 0, sizeof(req)); + req.ifbr_ifsflags = IFBF_FLUSHALL; + if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) + err(1, "BRDGFLUSH"); +} + +static void +setbridge_static(const char *val, const char *mac, int s, + const struct afswtch *afp) +{ + struct ifbareq req; + struct ether_addr *ea; + + memset(&req, 0, sizeof(req)); + strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); + + ea = ether_aton(mac); + if (ea == NULL) + errx(1, "%s: invalid address: %s", val, mac); + + memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); + req.ifba_flags = IFBAF_STATIC; + req.ifba_vlan = 1; /* XXX allow user to specify */ + + if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0) + err(1, "BRDGSADDR %s", val); +} + +static void +setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifbareq req; + struct ether_addr *ea; + + memset(&req, 0, sizeof(req)); + + ea = ether_aton(val); + if (ea == NULL) + errx(1, "invalid address: %s", val); + + memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); + + if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0) + err(1, "BRDGDADDR %s", val); +} + +static void +setbridge_addr(const char *val, int d, int s, const struct afswtch *afp) +{ + + bridge_addresses(s, ""); +} + +static void +setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp) +{ + struct ifbrparam param; + u_long val; + + if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "invalid value: %s", arg); + + param.ifbrp_csize = val & 0xffffffff; + + if (do_cmd(s, BRDGSCACHE, ¶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); +} + +#ifdef notdef +static void +setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp) +{ + struct ifbrparam param; + + if (strcasecmp(arg, "stp") == 0) { + param.ifbrp_proto = 0; + } else if (strcasecmp(arg, "rstp") == 0) { + param.ifbrp_proto = 2; + } else { + errx(1, "unknown stp protocol"); + } + + if (do_cmd(s, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) + err(1, "BRDGSPROTO %s", arg); +} + +static void +setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp) +{ + struct ifbrparam param; + u_long val; + + if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) + errx(1, "invalid value: %s", arg); + + param.ifbrp_txhc = val & 0xff; + + if (do_cmd(s, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) + err(1, "BRDGSTXHC %s", arg); +} +#endif + +static void +setbridge_ifpriority(const char *ifn, const char *pri, int s, + const struct afswtch *afp) +{ + struct ifbreq req; + u_long val; + + memset(&req, 0, sizeof(req)); + + if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) + errx(1, "invalid value: %s", pri); + + strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); + req.ifbr_priority = val & 0xff; + + if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) + err(1, "BRDGSIFPRIO %s", pri); +} + +static void +setbridge_ifpathcost(const char *ifn, const char *cost, int s, + const struct afswtch *afp) +{ + struct ifbreq req; + u_long val; + + memset(&req, 0, sizeof(req)); + + if (get_val(cost, &val) < 0) + errx(1, "invalid value: %s", cost); + + strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); + req.ifbr_path_cost = val; + + if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0) + err(1, "BRDGSIFCOST %s", cost); +} + +#ifdef notdef +static void +setbridge_ifmaxaddr(const char *ifn, const char *arg, int s, + const struct afswtch *afp) +{ + struct ifbreq req; + u_long val; + + memset(&req, 0, sizeof(req)); + + if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "invalid value: %s", arg); + + strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); + req.ifbr_addrmax = val & 0xffffffff; + + if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0) + err(1, "BRDGSIFAMAX %s", arg); +} +#endif + +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); +} + +#ifdef notdef +static void +setbridge_private(const char *val, int d, int s, const struct afswtch *afp) +{ + + do_bridgeflag(s, val, IFBIF_PRIVATE, 1); +} + +static void +unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp) +{ + + do_bridgeflag(s, val, IFBIF_PRIVATE, 0); +} +#endif + + +static void +setbridge_hostfilter(const char *ifn, const char *addr, int s, + const struct afswtch *afp) +{ + struct ifbrhostfilter req; + struct ether_addr *ea; + struct in_addr in; + + memset(&req, 0, sizeof(req)); + req.ifbrhf_flags = IFBRHF_ENABLED; + + strlcpy(req.ifbrhf_ifsname, ifn, sizeof(req.ifbrhf_ifsname)); + + ea = ether_aton(addr); + if (ea != NULL) { + req.ifbrhf_flags |= IFBRHF_HWSRC; + bcopy(ea, req.ifbrhf_hwsrca, sizeof(req.ifbrhf_hwsrca)); + } else if (inet_aton(addr, &in) != 0) { + req.ifbrhf_flags |= IFBRHF_IPSRC; + req.ifbrhf_ipsrc = in.s_addr; + } else + errx(1, "invalid address: %s", addr); + + if (do_cmd(s, BRDGSHOSTFILTER, &req, sizeof(req), 1) < 0) + err(1, "BRDGSHOSTFILTER %s %s", ifn, addr); +} + +static void +unsetbridge_hostfilter(const char *ifn, int d, int s, const struct afswtch *afp) +{ + struct ifbrhostfilter req; + + memset(&req, 0, sizeof(req)); + strlcpy(req.ifbrhf_ifsname, ifn, sizeof(req.ifbrhf_ifsname)); + + if (do_cmd(s, BRDGSHOSTFILTER, &req, sizeof(req), 1) < 0) + err(1, "BRDGSHOSTFILTER"); +} + +static void +setbridge_macnat(const char *val, int d, int s, const struct afswtch *afp) +{ + + do_bridgeflag(s, val, IFBIF_MAC_NAT, 1); +} + +static void +unsetbridge_macnat(const char *val, int d, int s, const struct afswtch *afp) +{ + + do_bridgeflag(s, val, IFBIF_MAC_NAT, 0); +} + +static struct cmd bridge_cmds[] = { + DEF_CMD_ARG("addm", setbridge_add), + DEF_CMD_ARG("deletem", setbridge_delete), + DEF_CMD_ARG("discover", setbridge_discover), + DEF_CMD_ARG("-discover", unsetbridge_discover), + DEF_CMD_ARG("learn", setbridge_learn), + DEF_CMD_ARG("-learn", unsetbridge_learn), +#ifdef notdef + DEF_CMD_ARG("sticky", setbridge_sticky), + DEF_CMD_ARG("-sticky", unsetbridge_sticky), + 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), +#ifdef notdef + DEF_CMD_ARG("edge", setbridge_edge), + DEF_CMD_ARG("-edge", unsetbridge_edge), + DEF_CMD_ARG("autoedge", setbridge_autoedge), + DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), + DEF_CMD_ARG("ptp", setbridge_ptp), + DEF_CMD_ARG("-ptp", unsetbridge_ptp), + DEF_CMD_ARG("autoptp", setbridge_autoptp), + DEF_CMD_ARG("-autoptp", unsetbridge_autoptp), +#endif + DEF_CMD("flush", 0, setbridge_flush), + DEF_CMD("flushall", 0, setbridge_flushall), + DEF_CMD_ARG2("static", setbridge_static), + DEF_CMD_ARG("deladdr", setbridge_deladdr), + DEF_CMD("addr", 1, setbridge_addr), + DEF_CMD_ARG("maxaddr", setbridge_maxaddr), + DEF_CMD_ARG("hellotime", setbridge_hellotime), + DEF_CMD_ARG("fwddelay", setbridge_fwddelay), + DEF_CMD_ARG("maxage", setbridge_maxage), + DEF_CMD_ARG("priority", setbridge_priority), +#ifdef notdef + DEF_CMD_ARG("proto", setbridge_protocol), + DEF_CMD_ARG("holdcnt", setbridge_holdcount), +#endif + DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), + DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), +#ifdef notdef + DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), +#endif + DEF_CMD_ARG("timeout", setbridge_timeout), +#ifdef notdef + DEF_CMD_ARG("private", setbridge_private), + DEF_CMD_ARG("-private", unsetbridge_private), +#endif + DEF_CMD_ARG2("hostfilter", setbridge_hostfilter), + DEF_CMD_ARG("-hostfilter", unsetbridge_hostfilter), + DEF_CMD_ARG("macnat", setbridge_macnat), + DEF_CMD_ARG("-macnat", unsetbridge_macnat), +}; +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/network_cmds/ifconfig.tproj/ifclone.c b/network_cmds/ifconfig.tproj/ifclone.c new file mode 100644 index 0000000..127d10b --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifclone.c @@ -0,0 +1,170 @@ +/* + * 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. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ifconfig.h" + +static void +list_cloners(void) +{ + struct if_clonereq ifcr; + char *cp, *buf; + int idx; + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket(AF_INET,SOCK_DGRAM)"); + + memset(&ifcr, 0, sizeof(ifcr)); + + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) + err(1, "SIOCIFGCLONERS for count"); + + buf = malloc(ifcr.ifcr_total * IFNAMSIZ); + if (buf == NULL) + err(1, "unable to allocate cloner name buffer"); + + ifcr.ifcr_count = ifcr.ifcr_total; + ifcr.ifcr_buffer = buf; + + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) + err(1, "SIOCIFGCLONERS for names"); + + /* + * In case some disappeared in the mean time, clamp it down. + */ + if (ifcr.ifcr_count > ifcr.ifcr_total) + ifcr.ifcr_count = ifcr.ifcr_total; + + for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { + if (idx > 0) + putchar(' '); + printf("%s", cp); + } + + putchar('\n'); + free(buf); +} + +static clone_callback_func *clone_cb = NULL; + +void +clone_setcallback(clone_callback_func *p) +{ + if (clone_cb != NULL && clone_cb != p) + errx(1, "conflicting device create parameters"); + clone_cb = p; +} + +/* + * Do the actual clone operation. Any parameters must have been + * setup by now. If a callback has been setup to do the work + * then defer to it; otherwise do a simple create operation with + * no parameters. + */ +static void +ifclonecreate(int s, void *arg) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (clone_cb == NULL) { +#ifdef SIOCIFCREATE2 + /* NB: no parameters */ + if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) + err(1, "SIOCIFCREATE2"); +#else + if (ioctl(s, SIOCIFCREATE, &ifr) < 0) + err(1, "SIOCIFCREATE"); +#endif + } else { + clone_cb(s, &ifr); + } + + /* + * If we get a different name back than we put in, print it. + */ + if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) { + strlcpy(name, ifr.ifr_name, sizeof(name)); + printf("%s\n", name); + } +} + +static +DECL_CMD_FUNC(clone_create, arg, d) +{ + callback_register(ifclonecreate, NULL); +} + +static +DECL_CMD_FUNC(clone_destroy, arg, d) +{ + (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) + err(1, "SIOCIFDESTROY"); +} + +static struct cmd clone_cmds[] = { + DEF_CLONE_CMD("create", 0, clone_create), + DEF_CMD("destroy", 0, clone_destroy), + DEF_CLONE_CMD("plumb", 0, clone_create), + DEF_CMD("unplumb", 0, clone_destroy), +}; + +static void +clone_Copt_cb(const char *optarg __unused) +{ + list_cloners(); + exit(0); +} +static struct option clone_Copt = { "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/network_cmds/ifconfig.tproj/ifconfig.8 b/network_cmds/ifconfig.tproj/ifconfig.8 new file mode 100644 index 0000000..9b06f04 --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifconfig.8 @@ -0,0 +1,1109 @@ +.\" Copyright (c) 2013 Apple Inc. All rights reserved. +.\" +.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@ +.\" +.\" This file contains Original Code and/or Modifications of Original Code +.\" as defined in and that are subject to the Apple Public Source License +.\" Version 2.0 (the 'License'). You may not use this file except in +.\" compliance with the License. The rights granted to you under the License +.\" may not be used to create, or enable the creation or redistribution of, +.\" unlawful or unlicensed copies of an Apple operating system, or to +.\" circumvent, violate, or enable the circumvention or violation of, any +.\" terms of an Apple operating system software license agreement. +.\" +.\" Please obtain a copy of the License at +.\" http://www.opensource.apple.com/apsl/ and read it before using this file. +.\" +.\" The Original Code and all software distributed under the License are +.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +.\" Please see the License for the specific language governing rights and +.\" limitations under the License. +.\" +.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 +.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.142.2.6.2.1 2008/11/25 02:59:29 kensmith Exp $ +.\" +.Dd June 20, 2008 +.Dt IFCONFIG 8 +.Os +.Sh NAME +.Nm ifconfig +.Nd configure network interface parameters +.Sh SYNOPSIS +.Nm +.Op Fl L +.Op Fl m +.Op Fl r +.Ar interface +.Op Cm create +.Op Ar address_family +.Oo +.Ar address +.Op Ar dest_address +.Oc +.Op Ar parameters +.Nm +.Ar interface +.Cm destroy +.Nm +.Fl a +.Op Fl L +.Op Fl d +.Op Fl m +.Op Fl r +.Op Fl u +.Op Fl v +.Op Ar address_family +.Nm +.Fl l +.Op Fl d +.Op Fl u +.Op Ar address_family +.Nm +.Op Fl L +.Op Fl d +.Op Fl m +.Op Fl r +.Op Fl u +.Op Fl v +.Op Fl C +.Nm +.Ar interface +.Cm vlan +.Ar vlan-tag +.Cm vlandev +.Ar iface +.Nm +.Ar interface +.Cm -vlandev +.Ar iface +.Nm +.Ar interface +.Cm bonddev +.Ar iface +.Nm +.Ar interface +.Cm -bonddev +.Ar iface +.Nm +.Ar interface +.Cm bondmode +.Ar lacp | static +.Sh DESCRIPTION +The +.Nm +utility is used to assign an address +to a network interface and/or configure +network interface parameters. +.Pp +The following options are available: +.Bl -tag -width indent +.It Ar address +For the +.Tn DARPA Ns -Internet +family, +the address is either a host name present in the host name data +base, +.Xr hosts 5 , +or a +.Tn DARPA +Internet address expressed in the Internet standard +.Dq dot notation . +.Pp +It is also possible to use the CIDR notation (also known as the +slash notation) to include the netmask. +That is, one can specify an address like +.Li 192.168.0.1/16 . +.Pp +For the +.Dq inet6 +family, it is also possible to specify the prefix length using the slash +notation, like +.Li ::1/128 . +See the +.Cm prefixlen +parameter below for more information. +.\" For the Xerox Network Systems(tm) family, +.\" addresses are +.\" .Ar net:a.b.c.d.e.f , +.\" where +.\" .Ar net +.\" is the assigned network number (in decimal), +.\" and each of the six bytes of the host number, +.\" .Ar a +.\" through +.\" .Ar f , +.\" are specified in hexadecimal. +.\" The host number may be omitted on IEEE 802 protocol +.\" (Ethernet, FDDI, and Token Ring) interfaces, +.\" which use the hardware physical address, +.\" and on interfaces other than the first. +.\" For the +.\" .Tn ISO +.\" family, addresses are specified as a long hexadecimal string, +.\" as in the Xerox family. +.\" However, two consecutive dots imply a zero +.\" byte, and the dots are optional, if the user wishes to (carefully) +.\" count out long strings of digits in network byte order. +.Pp +The link-level +.Pq Dq link +address +is specified as a series of colon-separated hex digits. +This can be used to +e.g.\& set a new MAC address on an ethernet interface, though the +mechanism used is not ethernet-specific. +If the interface is already +up when this option is used, it will be briefly brought down and +then brought back up again in order to ensure that the receive +filter in the underlying ethernet hardware is properly reprogrammed. +.It Ar address_family +Specify the +address family +which affects interpretation of the remaining parameters. +Since an interface can receive transmissions in differing protocols +with different naming schemes, specifying the address family is recommended. +The address or protocol families currently +supported are +.Dq inet , +.Dq inet6 , +.\".Dq atalk , +.\".Dq ipx , +.\" .Dq iso , +and +.Dq link . +.\" and +.\" .Dq ns . +The default is +.Dq inet . +.Dq ether +and +.Dq lladdr +are synonyms for +.Dq link . +.It Ar dest_address +Specify the address of the correspondent on the other end +of a point to point link. +.It Ar interface +This +parameter is a string of the form +.Dq name unit , +for example, +.Dq Li en0 . +\.El +.Pp +The following parameters may be set with +.Nm : +.Bl -tag -width indent +.It Cm add +Another name for the +.Cm alias +parameter. +Introduced for compatibility +with +.Bsx . +.It Cm alias +Establish an additional network address for this interface. +This is sometimes useful when changing network numbers, and +one wishes to accept packets addressed to the old interface. +If the address is on the same subnet as the first network address +for this interface, a non-conflicting netmask must be given. +Usually +.Li 0xffffffff +is most appropriate. +.It Fl alias +Remove the network address specified. +This would be used if you incorrectly specified an alias, or it +was no longer needed. +If you have incorrectly set an NS address having the side effect +of specifying the host portion, removing all NS addresses will +allow you to respecify the host portion. +.It Cm anycast +(Inet6 only.) +Specify that the address configured is an anycast address. +Based on the current specification, +only routers may configure anycast addresses. +Anycast address will not be used as source address of any of outgoing +IPv6 packets. +.It Cm arp +Enable the use of the Address Resolution Protocol +.Pq Xr arp 4 +in mapping +between network level addresses and link level addresses (default). +This is currently implemented for mapping between +.Tn DARPA +Internet +addresses and +.Tn IEEE +802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses). +.It Fl arp +Disable the use of the Address Resolution Protocol +.Pq Xr arp 4 . +.It Cm broadcast +(Inet only.) +Specify the address to use to represent broadcasts to the +network. +The default broadcast address is the address with a host part of all 1's. +.It Cm debug +Enable driver dependent debugging code; usually, this turns on +extra console error logging. +.It Fl debug +Disable driver dependent debugging code. +.It Cm delete +Another name for the +.Fl alias +parameter. +.It Cm down +Mark an interface +.Dq down . +When an interface is marked +.Dq down , +the system will not attempt to +transmit messages through that interface. +If possible, the interface will be reset to disable reception as well. +.It Cm ether +Another name for the +.Cm lladdr +parameter. +.\" .It Cm ipdst +.\" This is used to specify an Internet host who is willing to receive +.\" ip packets encapsulating NS packets bound for a remote network. +.\" An apparent point to point link is constructed, and +.\" the address specified will be taken as the NS address and network +.\" of the destination. +.\" IP encapsulation of +.\" .Tn CLNP +.\" packets is done differently. +.It Cm lladdr Ar addr +Set the link-level address on an interface. +This can be used to +e.g. set a new MAC address on an ethernet interface, though the +mechanism used is not ethernet-specific. +The address +.Ar addr +is specified as a series of colon-separated hex digits. +If the interface is already +up when this option is used, it will be briefly brought down and +then brought back up again in order to ensure that the receive +filter in the underlying ethernet hardware is properly reprogrammed. +.It Cm media Ar type +If the driver supports the media selection system, set the media type +of the interface to +.Ar type . +Some interfaces support the mutually exclusive use of one of several +different physical media connectors. +For example, a 10Mbit/s Ethernet +interface might support the use of either +.Tn AUI +or twisted pair connectors. +Setting the media type to +.Cm 10base5/AUI +would change the currently active connector to the AUI port. +Setting it to +.Cm 10baseT/UTP +would activate twisted pair. +Refer to the interfaces' driver +specific documentation or man page for a complete list of the +available types. +.It Cm mediaopt Ar opts +If the driver supports the media selection system, set the specified +media options on the interface. +The +.Ar opts +argument +is a comma delimited list of options to apply to the interface. +Refer to the interfaces' driver specific man page for a complete +list of available options. +.It Fl mediaopt Ar opts +If the driver supports the media selection system, disable the +specified media options on the interface. +.It Cm rxcsum , txcsum +If the driver supports user-configurable checksum offloading, +enable receive (or transmit) checksum offloading on the interface. +Some drivers may not be able to enable these flags independently +of each other, so setting one may also set the other. +The driver will offload as much checksum work as it can reliably +support, the exact level of offloading varies between drivers. +.It Fl rxcsum , txcsum +If the driver supports user-configurable checksum offloading, +disable receive (or transmit) checksum offloading on the interface. +These settings may not always be independent of each other. +.It Cm tso +If the driver supports +.Xr tcp 4 +segmentation offloading, enable TSO on the interface. +Some drivers may not be able to support TSO for +.Xr ip 4 +and +.Xr ip6 4 +packets, so they may enable only one of them. +.It Fl tso +If the driver supports +.Xr tcp 4 +segmentation offloading, disable TSO on the interface. +It will always disable TSO for +.Xr ip 4 +and +.Xr ip6 4 . +.It Cm lro +If the driver supports +.Xr tcp 4 +large receive offloading, enable LRO on the interface. +.It Fl lro +If the driver supports +.Xr tcp 4 +large receive offloading, disable LRO on the interface. +.It Cm av +If supported by the driver, enable 802.1 AVB on the interface. +.It Fl av +If supported by the driver, disable 802.1 AVB on the interface. +.It Cm vlanmtu , vlanhwtag +If the driver offers user-configurable VLAN support, enable +reception of extended frames or tag processing in hardware, +respectively. +Note that this must be issued on a physical interface associated with +.Xr vlan 4 , +not on a +.Xr vlan 4 +interface itself. +.It Fl vlanmtu , vlanhwtag +If the driver offers user-configurable VLAN support, disable +reception of extended frames or tag processing in hardware, +respectively. +.It Cm create +Create the specified network pseudo-device. +If the interface is given without a unit number, try to create a new +device with an arbitrary unit number. +If creation of an arbitrary device is successful, the new device name is +printed to standard output unless the interface is renamed or destroyed +in the same +.Nm +invocation. +.It Cm destroy +Destroy the specified network pseudo-device. +.It Cm plumb +Another name for the +.Cm create +parameter. +Included for +.Tn Solaris +compatibility. +.It Cm unplumb +Another name for the +.Cm destroy +parameter. +Included for +.Tn Solaris +compatibility. +.It Cm metric Ar n +Set the routing metric of the interface to +.Ar n , +default 0. +The routing metric is used by the routing protocol +.Pq Xr routed 8 . +Higher metrics have the effect of making a route +less favorable; metrics are counted as additional hops +to the destination network or host. +.It Cm mtu Ar n +Set the maximum transmission unit of the interface to +.Ar n , +default is interface specific. +The MTU is used to limit the size of packets that are transmitted on an +interface. +Not all interfaces support setting the MTU, and some interfaces have +range restrictions. +.It Cm netmask Ar mask +.\" (Inet and ISO.) +(Inet only.) +Specify how much of the address to reserve for subdividing +networks into sub-networks. +The mask includes the network part of the local address +and the subnet part, which is taken from the host field of the address. +The mask can be specified as a single hexadecimal number +with a leading +.Ql 0x , +with a dot-notation Internet address, +or with a pseudo-network name listed in the network table +.Xr networks 5 . +The mask contains 1's for the bit positions in the 32-bit address +which are to be used for the network and subnet parts, +and 0's for the host part. +The mask should contain at least the standard network portion, +and the subnet field should be contiguous with the network +portion. +.Pp +The netmask can also be specified in CIDR notation after the address. +See the +.Ar address +option above for more information. +.It Cm prefixlen Ar len +(Inet6 only.) +Specify that +.Ar len +bits are reserved for subdividing networks into sub-networks. +The +.Ar len +must be integer, and for syntactical reason it must be between 0 to 128. +It is almost always 64 under the current IPv6 assignment rule. +If the parameter is omitted, 64 is used. +.Pp +The prefix can also be specified using the slash notation after the address. +See the +.Ar address +option above for more information. +.\" see +.\" Xr eon 5 . +.\" .It Cm nsellength Ar n +.\" .Pf ( Tn ISO +.\" only) +.\" This specifies a trailing number of bytes for a received +.\" .Tn NSAP +.\" used for local identification, the remaining leading part of which is +.\" taken to be the +.\" .Tn NET +.\" (Network Entity Title). +.\" The default value is 1, which is conformant to US +.\" .Tn GOSIP . +.\" When an ISO address is set in an ifconfig command, +.\" it is really the +.\" .Tn NSAP +.\" which is being specified. +.\" For example, in +.\" .Tn US GOSIP , +.\" 20 hex digits should be +.\" specified in the +.\" .Tn ISO NSAP +.\" to be assigned to the interface. +.\" There is some evidence that a number different from 1 may be useful +.\" for +.\" .Tn AFI +.\" 37 type addresses. +.It Cm remove +Another name for the +.Fl alias +parameter. +Introduced for compatibility +with +.Bsx . +.Sm off +.It Cm link Op Cm 0 No - Cm 2 +.Sm on +Enable special processing of the link level of the interface. +These three options are interface specific in actual effect, however, +they are in general used to select special modes of operation. +An example +of this is to enable SLIP compression, or to select the connector type +for some Ethernet cards. +Refer to the man page for the specific driver +for more information. +.Sm off +.It Fl link Op Cm 0 No - Cm 2 +.Sm on +Disable special processing at the link level with the specified interface. +.It Cm up +Mark an interface +.Dq up . +This may be used to enable an interface after an +.Dq Nm Cm down . +It happens automatically when setting the first address on an interface. +If the interface was reset when previously marked down, +the hardware will be re-initialized. +.El +.Pp +The following parameters are for ICMPv6 Neighbor Discovery Protocol. +Note that the address family keyword +.Dq Li inet6 +is needed for them: +.Bl -tag -width indent +.It Cm nud +Perform network unreachability detection (NUD). +.It Cm -nud +Do not perform network unreachability detection (NUD). +.It Cm ifdisabled +Disable all IPv6 communication on the interface. +.It Cm -ifdisabled +Do not disable all IPv6 communication on the interface. +.It Cm insecure +Disable the processing of Secure Neighbor Discovery (SEND). +.It Cm -insecure +Do not disabled the processing of Secure Neighbor Discovery (SEND). +.It Cm dad +Perform duplicate address detection (DAD). +.It Cm -dad +Do not perform duplicate address detection (DAD). +.It Cm replicated +Modify duplicate address detection (DAD) protocol to expect that interface +configuration is replicated at a network sleep proxy. Ignores certain NA +messages and disables optimistic DAD. +.It Cm -replicated +Do not use modified duplicated address detection (DAD) protocol. +.El +.Pp +The following parameters are specific to link aggregate interfaces: +.Bl -tag -width indent +.It Cm bonddev Ar iface +If the interface is a bond pseudo device, associate physical interface +.Ar iface +with it. By default, the bond pseudo device is in LACP +(Link Aggregation Control Protocol) mode (see \fBbondmode\fR below). In +this mode, the device conforms to the IEEE 802.3ad Link Aggregation +specification. +.Pp +If this is the first physical interface to be associated with the bond +interface, the bond interface inherits the ethernet address from the +physical interface. Physical interfaces that are added to the bond have +their ethernet address re-programmed so that all members of the bond have +the same ethernet address. If the physical interface is subsequently +removed from the bond using +.Fl bonddev , +a new ethernet address is chosen from the remaining interfaces, and all +interfaces are re-programmed again with the new ethernet address. If no +remaining interfaces exist, the bond interface's ethernet address is cleared. +.Pp +If the specified physical interface +.Ar iface +is not capable of having its ethernet address re-programmed, the +.Cm bonddev +command will fail. +.Pp +Once the physical interface +.Ar iface +is successfully associated with the bond interface, all received packets +are diverted to the bond interface. The physical interface is no longer +useable on its own, and remains that way until it is removed from the bond using +.Fl bonddev . +.Pp +It is possible that the specified interface +.Ar iface +is not capable of aggregating, and may remain unused until the operating +conditions change. +.Pp +The link status of the bond interface depends on the state of link aggregation. +If no active partner is detected, the link status will remain inactive. +.Pp +To monitor the 802.3ad Link Aggregation state, use the +.Fl b +option. +.Pp +A physical interface that is associated with a vlan pseudo device cannot +at the same time be associated with a bond pseudo device. A physical interface +cannot be associated with more than one bond pseudo device at the same time. +.Pp +It is not possible to associate a bond with pseudo interfaces such as vlan. +Only physical ethernet interfaces may be associated with a bond. +.It Fl bonddev Ar iface +If the interface is a bond pseudo device, disassociate the physical interface +.Ar iface +from it. Before the interface is removed from the bond, the bond device +announces to the link partner that the interface is now individual and +no longer aggregatable. +If the physical +.Ar iface +is the last interface in the bond, the bond interface clears its link address. +.It Cm bondmode Ar lacp | static +If the interface is a bond pseudo device, this option will set the \fImode\fR +on the bond interface. The two currently supported modes are +.Ar lacp +and +.Ar static . +The default mode is +.Ar lacp . +.Pp +To enable static mode (and turn off LACP), specify +.Ar static . +In static mode, a member interface is made an active part of the +link aggregate as long as the link status is active. +.Pp +To re-enable LACP mode, specify +.Ar lacp . +.El +.Pp +The following parameters are specific to IP tunnel interfaces, +.Xr gif 4 : +.Bl -tag -width indent +.It Cm tunnel Ar src_addr dest_addr +Configure the physical source and destination address for IP tunnel +interfaces. +The arguments +.Ar src_addr +and +.Ar dest_addr +are interpreted as the outer source/destination for the encapsulating +IPv4/IPv6 header. +.It Fl tunnel +Unconfigure the physical source and destination address for IP tunnel +interfaces previously configured with +.Cm tunnel . +.It Cm deletetunnel +Another name for the +.Fl tunnel +parameter. +.El +.Pp +The following parameters are specific to bridge interfaces: +.Bl -tag -width indent +.It Cm addm Ar interface +Add the interface named by +.Ar interface +as a member of the bridge. +The interface is put into promiscuous mode +so that it can receive every packet sent on the network. +.It Cm deletem Ar interface +Remove the interface named by +.Ar interface +from the bridge. +Promiscuous mode is disabled on the interface when +it is removed from the bridge. +.It Cm maxaddr Ar size +Set the size of the bridge address cache to +.Ar size . +The default is 100 entries. +.It Cm timeout Ar seconds +Set the timeout of address cache entries to +.Ar seconds +seconds. +If +.Ar seconds +is zero, then address cache entries will not be expired. +The default is 240 seconds. +.It Cm addr +Display the addresses that have been learned by the bridge. +.It Cm static Ar interface-name Ar address +Add a static entry into the address cache pointing to +.Ar interface-name . +Static entries are never aged out of the cache or re-placed, even if the +address is seen on a different interface. +.It Cm deladdr Ar address +Delete +.Ar address +from the address cache. +.It Cm flush +Delete all dynamically-learned addresses from the address cache. +.It Cm flushall +Delete all addresses, including static addresses, from the address cache. +.It Cm discover Ar interface +Mark an interface as a +.Dq discovering +interface. +When the bridge has no address cache entry +(either dynamic or static) +for the destination address of a packet, +the bridge will forward the packet to all +member interfaces marked as +.Dq discovering . +This is the default for all interfaces added to a bridge. +.It Cm -discover Ar interface +Clear the +.Dq discovering +attribute on a member interface. +For packets without the +.Dq discovering +attribute, the only packets forwarded on the interface are broadcast +or multicast packets and packets for which the destination address +is known to be on the interface's segment. +.It Cm learn Ar interface +Mark an interface as a +.Dq learning +interface. +When a packet arrives on such an interface, the source +address of the packet is entered into the address cache as being a +destination address on the interface's segment. +This is the default for all interfaces added to a bridge. +.It Cm -learn Ar interface +Clear the +.Dq learning +attribute on a member interface. +.\".It Cm sticky Ar interface +.\"Mark an interface as a +.\".Dq sticky +.\"interface. +.\"Dynamically learned address entries are treated at static once entered into +.\"the cache. +.\"Sticky entries are never aged out of the cache or replaced, even if the +.\"address is seen on a different interface. +.\".It Cm -sticky Ar interface +.\"Clear the +.\".Dq sticky +.\"attribute on a member interface. +.\".It Cm private Ar interface +.\"Mark an interface as a +.\".Dq private +.\"interface. +.\"A private interface does not forward any traffic to any other port that is also +.\"a private interface. +.\".It Cm -private Ar interface +.\"Clear the +.\".Dq private +.\"attribute on a member interface. +.\".It Cm span Ar interface +.\"Add the interface named by +.\".Ar interface +.\"as a span port on the bridge. +.\"Span ports transmit a copy of every frame received by the bridge. +.\"This is most useful for snooping a bridged network passively on +.\"another host connected to one of the span ports of the bridge. +.\".It Cm -span Ar interface +.\"Delete the interface named by +.\".Ar interface +.\"from the list of span ports of the bridge. +.It Cm stp Ar interface +Enable Spanning Tree protocol on +.Ar interface . +The +.Xr if_bridge 4 +driver has support for the IEEE 802.1D Spanning Tree protocol (STP). +Spanning Tree is used to detect and remove loops in a network topology. +.It Cm -stp Ar interface +Disable Spanning Tree protocol on +.Ar interface . +This is the default for all interfaces added to a bridge. +.\".It Cm edge Ar interface +.\"Set +.\".Ar interface +.\"as an edge port. +.\"An edge port connects directly to end stations cannot create bridging +.\"loops in the network, this allows it to transition straight to forwarding. +.\".It Cm -edge Ar interface +.\"Disable edge status on +.\".Ar interface . +.\".It Cm autoedge Ar interface +.\"Allow +.\".Ar interface +.\"to automatically detect edge status. +.\"This is the default for all interfaces added to a bridge. +.\".It Cm -autoedge Ar interface +.\"Disable automatic edge status on +.\".Ar interface . +.\".It Cm ptp Ar interface +.\"Set the +.\".Ar interface +.\"as a point to point link. +.\"This is required for straight transitions to forwarding and +.\"should be enabled on a direct link to another RSTP capable switch. +.\".It Cm -ptp Ar interface +.\"Disable point to point link status on +.\".Ar interface . +.\"This should be disabled for a half duplex link and for an interface +.\"connected to a shared network segment, +.\"like a hub or a wireless network. +.\".It Cm autoptp Ar interface +.\"Automatically detect the point to point status on +.\".Ar interface +.\"by checking the full duplex link status. +.\"This is the default for interfaces added to the bridge. +.\".It Cm -autoptp Ar interface +.\"Disable automatic point to point link detection on +.\".Ar interface . +.It Cm maxage Ar seconds +Set the time that a Spanning Tree protocol configuration is valid. +The default is 20 seconds. +The minimum is 6 seconds and the maximum is 40 seconds. +.It Cm fwddelay Ar seconds +Set the time that must pass before an interface begins forwarding +packets when Spanning Tree is enabled. +The default is 15 seconds. +The minimum is 4 seconds and the maximum is 30 seconds. +.It Cm hellotime Ar seconds +Set the time between broadcasting of Spanning Tree protocol +configuration messages. +The hello time may only be changed when operating in legacy stp mode. +The default is 2 seconds. +The minimum is 1 second and the maximum is 2 seconds. +.It Cm priority Ar value +Set the bridge priority for Spanning Tree. +The default is 32768. +The minimum is 0 and the maximum is 61440. +.\".It Cm proto Ar value +.\"Set the Spanning Tree protocol. +.\"The default is rstp. +.\"The available options are stp and rstp. +.\".It Cm holdcnt Ar value +.\"Set the transmit hold count for Spanning Tree. +.\"This is the number of packets transmitted before being rate limited. +.\"The default is 6. +.\"The minimum is 1 and the maximum is 10. +.It Cm ifpriority Ar interface Ar value +Set the Spanning Tree priority of +.Ar interface +to +.Ar value . +The default is 128. +The minimum is 0 and the maximum is 240. +.It Cm ifpathcost Ar interface Ar value +Set the Spanning Tree path cost of +.Ar interface +to +.Ar value . +The default is calculated from the link speed. +To change a previously selected path cost back to automatic, set the +cost to 0. +The minimum is 1 and the maximum is 200000000. +.It Cm ifmaxaddr Ar interface Ar size +Set the maximum number of hosts allowed from an interface, packets with unknown +source addresses are dropped until an existing host cache entry expires or is +removed. +Set to 0 to disable. +.It Cm hostfilter Ar interface Ar address +Configure the bridge to accept incoming packet on the interface +only if they match the given MAC address and IP address +-- use the command twice to set both type of addresses. +Other filtering restrictions apply. +.It Cm -hostfilter Ar interface +Allow traffic from any host on that interface. +.El +.Pp +The following parameters are specific to vlan interfaces: +.Bl -tag -width indent +.It Cm vlan Ar vlan_tag +Set the VLAN tag value to +.Ar vlan_tag . +This value is a 16-bit number which is used to create an 802.1Q +VLAN header for packets sent from the +.Xr vlan 4 +interface. +Note that +.Cm vlan +and +.Cm vlandev +must both be set at the same time. +.It Cm vlandev Ar iface +Associate the physical interface +.Ar iface +with a +.Xr vlan 4 +interface. +Packets transmitted through the +.Xr vlan 4 +interface will be +diverted to the specified physical interface +.Ar iface +with 802.1Q VLAN encapsulation. +Packets with 802.1Q encapsulation received +by the parent interface with the correct VLAN tag will be diverted to +the associated +.Xr vlan 4 +pseudo-interface. +The +.Xr vlan 4 +interface is assigned a +copy of the parent interface's flags and the parent's ethernet address. +The +.Cm vlandev +and +.Cm vlan +must both be set at the same time. +If the +.Xr vlan 4 +interface already has +a physical interface associated with it, this command will fail. +To +change the association to another physical interface, the existing +association must be cleared first. +.Pp +Note: if the hardware tagging capability +is set on the parent interface, the +.Xr vlan 4 +pseudo +interface's behavior changes: +the +.Xr vlan 4 +interface recognizes that the +parent interface supports insertion and extraction of VLAN tags on its +own (usually in firmware) and that it should pass packets to and from +the parent unaltered. +.It Fl vlandev Op Ar iface +If the driver is a +.Xr vlan 4 +pseudo device, disassociate the parent interface from it. +This breaks the link between the +.Xr vlan 4 +interface and its parent, +clears its VLAN tag, flags and its link address and shuts the interface down. +The +.Ar iface +argument is useless and hence deprecated. +.El +.Pp +The +.Nm +utility displays the current configuration for a network interface +when no optional parameters are supplied. +If a protocol family is specified, +.Nm +will report only the details specific to that protocol family. +.Pp +If the +.Fl m +flag is passed before an interface name, +.Nm +will display the capability list and all +of the supported media for the specified interface. +.Pp +If +.Fl L +flag is supplied, address lifetime is displayed for IPv6 addresses, +as time offset string. +.Pp +Optionally, the +.Fl a +flag may be used instead of an interface name. +This flag instructs +.Nm +to display information about all interfaces in the system. +The +.Fl d +flag limits this to interfaces that are down, and +.Fl u +limits this to interfaces that are up. +When no arguments are given, +.Fl a +is implied. +.Pp +The +.Fl l +flag may be used to list all available interfaces on the system, with +no other additional information. +Use of this flag is mutually exclusive +with all other flags and commands, except for +.Fl d +(only list interfaces that are down) +and +.Fl u +(only list interfaces that are up). +.Pp +The +.Fl v +flag may be used to get more verbose status for an interface. +.Pp +The +.Fl C +flag may be used to list all of the interface cloners available on +the system, with no additional information. +Use of this flag is mutually exclusive with all other flags and commands. +.Pp +The +.Fl r +flag may be used to show additional information related to the count of route references on the network interface. +.Pp +For bridge interfaces, the list of addresses learned by the bridge is not shown when displaying information about +all interfaces except when the +.Fl v +flag is used. +.Pp +Only the super-user may modify the configuration of a network interface. +.Sh NOTES +The media selection system is relatively new and only some drivers support +it (or have need for it). +.Sh EXAMPLES +Assign the IPv4 address +.Li 192.0.2.10 , +with a network mask of +.Li 255.255.255.0 , +to the interface +.Li en0 : +.Dl # ifconfig en0 inet 192.0.2.10 netmask 255.255.255.0 +.Pp +Add the IPv4 address +.Li 192.0.2.45 , +with the CIDR network prefix +.Li /28 , +to the interface +.Li en0 , +using +.Cm add +as a synonym for the canonical form of the option +.Cm alias : +.Dl # ifconfig en0 inet 192.0.2.45/28 add +.Pp +Remove the IPv4 address +.Li 192.0.2.45 +from the interface +.Li en0 : +.Dl # ifconfig en0 inet 192.0.2.45 -alias +.Pp +Add the IPv6 address +.Li 2001:DB8:DBDB::123/48 +to the interface +.Li en0 : +.Dl # ifconfig en0 inet6 2001:db8:bdbd::123 prefixlen 48 alias +Note that lower case hexadecimal IPv6 addresses are acceptable. +.Pp +Remove the IPv6 address added in the above example, +using the +.Li / +character as shorthand for the network prefix, +and using +.Cm delete +as a synonym for the canonical form of the option +.Fl alias : +.Dl # ifconfig en0 inet6 2001:db8:bdbd::123/48 delete +.Pp +Configure the interface +.Li en1 , +to use 100baseTX, full duplex Ethernet media options: +.Dl # ifconfig en1 media 100baseTX mediaopt full-duplex +.Pp +Create the software network interface +.Li gif1 : +.Dl # ifconfig gif1 create +.Pp +Destroy the software network interface +.Li gif1 : +.Dl # ifconfig gif1 destroy +.Sh DIAGNOSTICS +Messages indicating the specified interface does not exist, the +requested address is unknown, or the user is not privileged and +tried to alter an interface's configuration. +.Sh SEE ALSO +.Xr netstat 1 , +.Xr netintro 4 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +utility appeared in +.Bx 4.2 . +.Sh BUGS +Basic IPv6 node operation requires a link-local address on each +interface configured for IPv6. +Normally, such an address is automatically configured by the +kernel on each interface added to the system; this behaviour may +be disabled by setting the sysctl MIB variable +.Va net.inet6.ip6.auto_linklocal +to 0. +.Pp +If you delete such an address using +.Nm , +the kernel may act very odd. +Do this at your own risk. diff --git a/network_cmds/ifconfig.tproj/ifconfig.c b/network_cmds/ifconfig.tproj/ifconfig.c new file mode 100644 index 0000000..3449301 --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifconfig.c @@ -0,0 +1,2692 @@ +/* + * Copyright (c) 2009-2019 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * 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. + */ + +#include <sys/cdefs.h> + +#ifndef lint +__unused static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#ifndef __APPLE__ +#include <sys/module.h> +#include <sys/linker.h> +#endif + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_mib.h> +#include <net/route.h> +#include <net/pktsched/pktsched.h> +#include <net/network_agent.h> + +/* IP */ +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <ifaddrs.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <sysexits.h> +#include <syslog.h> + +#include "ifconfig.h" + +#ifdef __APPLE__ +#include <TargetConditionals.h> +#endif + +/* + * Since "struct ifreq" is composed of various union members, callers + * should pay special attention to interprete the value. + * (.e.g. little/big endian difference in the structure.) + */ +struct ifreq ifr; + +char name[IFNAMSIZ]; +int setaddr; +int setmask; +int doalias; +int clearaddr; +int newaddr = 1; +int noload; +int all; + +int bond_details = 0; +int supmedia = 0; +#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) +int verbose = 1; +int showrtref = 1; +#else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */ +int verbose = 0; +int showrtref = 0; +#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */ +int printkeys = 0; /* Print keying material for interfaces. */ + +static int ifconfig(int argc, char *const *argv, int iscreate, + const struct afswtch *afp); +static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, + struct ifaddrs *ifa); +static char *bytes_to_str(unsigned long long bytes); +static char *bps_to_str(unsigned long long rate); +static char *ns_to_str(unsigned long long nsec); +static void tunnel_status(int s); +static void clat46_addr(int s, char *name); +static void nat64_status(int s, char *name); +static void usage(void); +static char *sched2str(unsigned int s); +static char *tl2str(unsigned int s); +static char *ift2str(unsigned int t, unsigned int f, unsigned int sf); +static char *iffunct2str(u_int32_t functional_type); + +static struct afswtch *af_getbyname(const char *name); +static struct afswtch *af_getbyfamily(int af); +static void af_other_status(int); + +static struct option *opts = NULL; + +void +opt_register(struct option *p) +{ + p->next = opts; + opts = p; +} + +static void +usage(void) +{ + char options[1024]; + struct option *p; + + /* XXX not right but close enough for now */ + options[0] = '\0'; + for (p = opts; p != NULL; p = p->next) { + strlcat(options, p->opt_usage, sizeof(options)); + strlcat(options, " ", sizeof(options)); + } + + fprintf(stderr, + "usage: ifconfig %sinterface address_family [address [dest_address]]\n" + " [parameters]\n" + " ifconfig interface create\n" + " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" + " ifconfig -l [-d] [-u] [address_family]\n" + " ifconfig %s[-d] [-m] [-u] [-v]\n", + options, options, options); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int c, namesonly, downonly, uponly; + const struct afswtch *afp = NULL; + int ifindex; + struct ifaddrs *ifap, *ifa; + struct ifreq paifr; + const struct sockaddr_dl *sdl; + char options[1024], *cp; + const char *ifname; + struct option *p; + size_t iflen; + + all = downonly = uponly = namesonly = noload = 0; + + /* Parse leading line options */ +#ifndef __APPLE__ + strlcpy(options, "adklmnuv", sizeof(options)); +#else + strlcpy(options, "abdlmruv", sizeof(options)); +#endif + for (p = opts; p != NULL; p = p->next) + strlcat(options, p->opt, sizeof(options)); + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'a': /* scan all interfaces */ + all++; + break; + case 'b': /* bond detailed output */ + bond_details++; + break; + case 'd': /* restrict scan to "down" interfaces */ + downonly++; + break; +#ifndef __APPLE__ + case 'k': + printkeys++; + break; +#endif + case 'l': /* scan interface names only */ + namesonly++; + break; + case 'm': /* show media choices in status */ + supmedia = 1; + break; +#ifndef __APPLE__ + case 'n': /* suppress module loading */ + noload++; + break; +#endif + case 'r': + showrtref++; + break; + case 'u': /* restrict scan to "up" interfaces */ + uponly++; + break; + case 'v': + verbose++; + break; + default: + for (p = opts; p != NULL; p = p->next) + if (p->opt[0] == c) { + p->cb(optarg); + break; + } + if (p == NULL) + usage(); + break; + } + } + argc -= optind; + argv += optind; + + /* -l cannot be used with -a or -q or -m or -b */ + if (namesonly && + (all || supmedia || bond_details)) + usage(); + + /* nonsense.. */ + if (uponly && downonly) + usage(); + + /* no arguments is equivalent to '-a' */ + if (!namesonly && argc < 1) + all = 1; + + /* -a and -l allow an address family arg to limit the output */ + if (all || namesonly) { + if (argc > 1) + usage(); + + ifname = NULL; + if (argc == 1) { + afp = af_getbyname(*argv); + if (afp == NULL) + usage(); + if (afp->af_name != NULL) + argc--, argv++; + /* leave with afp non-zero */ + } + } else { + /* not listing, need an argument */ + if (argc < 1) + usage(); + + ifname = *argv; + argc--, argv++; + +#ifdef notdef + /* check and maybe load support for this interface */ + ifmaybeload(ifname); +#endif + ifindex = if_nametoindex(ifname); + if (ifindex == 0) { + /* + * NOTE: We must special-case the `create' command + * right here as we would otherwise fail when trying + * to find the interface. + */ + if (argc > 0 && (strcmp(argv[0], "create") == 0 || + strcmp(argv[0], "plumb") == 0)) { + iflen = strlcpy(name, ifname, sizeof(name)); + if (iflen >= sizeof(name)) + errx(1, "%s: cloning name too long", + ifname); + ifconfig(argc, argv, 1, NULL); + exit(0); + } + errx(1, "interface %s does not exist", ifname); + } + } + + /* Check for address family */ + if (argc > 0) { + afp = af_getbyname(*argv); + if (afp != NULL) + argc--, argv++; + } + + if (getifaddrs(&ifap) != 0) + err(EXIT_FAILURE, "getifaddrs"); + cp = NULL; + ifindex = 0; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + memset(&paifr, 0, sizeof(paifr)); + strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); + if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { + memcpy(&paifr.ifr_addr, ifa->ifa_addr, + ifa->ifa_addr->sa_len); + } + + if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) + continue; + if (ifa->ifa_addr->sa_family == AF_LINK) + sdl = (const struct sockaddr_dl *) ifa->ifa_addr; + else + sdl = NULL; + if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0) + continue; + iflen = strlcpy(name, ifa->ifa_name, sizeof(name)); + if (iflen >= sizeof(name)) { + warnx("%s: interface name too long, skipping", + ifa->ifa_name); + continue; + } + cp = ifa->ifa_name; + + if (downonly && (ifa->ifa_flags & IFF_UP) != 0) + continue; + if (uponly && (ifa->ifa_flags & IFF_UP) == 0) + continue; + ifindex++; + /* + * Are we just listing the interfaces? + */ + if (namesonly) { + if (ifindex > 1) + printf(" "); + fputs(name, stdout); + continue; + } + + if (argc > 0) + ifconfig(argc, argv, 0, afp); + else + status(afp, sdl, ifa); + } + if (namesonly) + printf("\n"); + freeifaddrs(ifap); + + exit(0); +} + +static struct afswtch *afs = NULL; + +void +af_register(struct afswtch *p) +{ + p->af_next = afs; + afs = p; +} + +static struct afswtch * +af_getbyname(const char *name) +{ + struct afswtch *afp; + + for (afp = afs; afp != NULL; afp = afp->af_next) + if (strcmp(afp->af_name, name) == 0) + return afp; + return NULL; +} + +static struct afswtch * +af_getbyfamily(int af) +{ + struct afswtch *afp; + + for (afp = afs; afp != NULL; afp = afp->af_next) + if (afp->af_af == af) + return afp; + return NULL; +} + +static void +af_other_status(int s) +{ + struct afswtch *afp; + uint8_t afmask[howmany(AF_MAX, NBBY)]; + + memset(afmask, 0, sizeof(afmask)); + for (afp = afs; afp != NULL; afp = afp->af_next) { + if (afp->af_other_status == NULL) + continue; + if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) + continue; + afp->af_other_status(s); + setbit(afmask, afp->af_af); + } +} + +static void +af_all_tunnel_status(int s) +{ + struct afswtch *afp; + uint8_t afmask[howmany(AF_MAX, NBBY)]; + + memset(afmask, 0, sizeof(afmask)); + for (afp = afs; afp != NULL; afp = afp->af_next) { + if (afp->af_status_tunnel == NULL) + continue; + if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) + continue; + afp->af_status_tunnel(s); + setbit(afmask, afp->af_af); + } +} + +static struct cmd *cmds = NULL; + +void +cmd_register(struct cmd *p) +{ + p->c_next = cmds; + cmds = p; +} + +static const struct cmd * +cmd_lookup(const char *name) +{ +#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, int iscreate, const struct afswtch *afp) +{ + const struct afswtch *nafp; + struct callback *cb; + int ret, s; + + strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); +top: + if (afp == NULL) + afp = af_getbyname("inet"); + ifr.ifr_addr.sa_family = + afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? + AF_INET : afp->af_af; + + if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) + err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family); + + while (argc > 0) { + const struct cmd *p; + + 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 (iscreate && !p->c_iscloneop) { + /* + * Push the clone create callback so the new + * device is created and can be used for any + * remaining arguments. + */ + cb = callbacks; + if (cb == NULL) + errx(1, "internal error, no callback"); + callbacks = cb->cb_next; + cb->cb_func(s, cb->cb_arg); + iscreate = 0; + /* + * Handle any address family spec that + * immediately follows and potentially + * recreate the socket. + */ + nafp = af_getbyname(*argv); + if (nafp != NULL) { + argc--, argv++; + if (nafp != afp) { + close(s); + afp = nafp; + goto top; + } + } + } + if (p->c_parameter == NEXTARG) { + if (argv[1] == NULL) + errx(1, "'%s' requires argument", + p->c_name); + p->c_u.c_func(argv[1], 0, s, afp); + argc--, argv++; + } else if (p->c_parameter == OPTARG) { + p->c_u.c_func(argv[1], 0, s, afp); + if (argv[1] != NULL) + argc--, argv++; + } else if (p->c_parameter == NEXTARG2) { + if (argc < 3) + errx(1, "'%s' requires 2 arguments", + p->c_name); + p->c_u.c_func2(argv[1], argv[2], s, afp); + argc -= 2, argv += 2; + } else if (p->c_parameter == VAARGS) { + ret = p->c_u.c_funcv(argc - 1, argv + 1, s, afp); + if (ret < 0) + errx(1, "'%s' command error", + p->c_name); + argc -= ret, argv += ret; + } else { + p->c_u.c_func(*argv, p->c_parameter, s, afp); + } + } + argc--, argv++; + } + + /* + * Do any post argument processing required by the address family. + */ + if (afp->af_postproc != NULL) + afp->af_postproc(s, afp); + /* + * Do deferred callbacks registered while processing + * command-line arguments. + */ + for (cb = callbacks; cb != NULL; cb = cb->cb_next) + cb->cb_func(s, cb->cb_arg); + /* + * Do deferred operations. + */ + if (clearaddr) { + if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { + warnx("interface %s cannot change %s addresses!", + name, afp->af_name); + clearaddr = 0; + } + } + if (clearaddr) { + strlcpy(afp->af_ridreq, name, sizeof ifr.ifr_name); + ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); + if (ret < 0) { + if (errno == EADDRNOTAVAIL && (doalias >= 0)) { + /* means no previous address for interface */ + } else + Perror("ioctl (SIOCDIFADDR)"); + } + } + if (newaddr) { + if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { + warnx("interface %s cannot change %s addresses!", + name, afp->af_name); + newaddr = 0; + } + } + if (newaddr && (setaddr || setmask)) { + strlcpy(afp->af_addreq, name, sizeof ifr.ifr_name); + if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) + Perror("ioctl (SIOCAIFADDR)"); + } + + close(s); + return(0); +} + +/*ARGSUSED*/ +static void +setifaddr(const char *addr, int param, int s, const struct afswtch *afp) +{ + if (afp->af_getaddr == NULL) + return; + /* + * Delay the ioctl to set the interface addr until flags are all set. + * The address interpretation may depend on the flags, + * and the flags may change when the address is set. + */ + setaddr++; + if (doalias == 0 && afp->af_af != AF_LINK) + clearaddr = 1; + afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); +} + +static void +settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) +{ + struct addrinfo *srcres, *dstres; + int ecode; + + if (afp->af_settunnel == NULL) { + warn("address family %s does not support tunnel setup", + afp->af_name); + return; + } + + if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) + errx(1, + "source and destination address families do not match"); + + afp->af_settunnel(s, srcres, dstres); + + freeaddrinfo(srcres); + freeaddrinfo(dstres); +} + +/* ARGSUSED */ +static void +deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) +{ + + if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) + err(1, "SIOCDIFPHYADDR"); +} + +static void +setifnetmask(const char *addr, int dummy __unused, int s, + const struct afswtch *afp) +{ + if (afp->af_getaddr != NULL) { + setmask++; + afp->af_getaddr(addr, MASK); + } +} + +static void +setifbroadaddr(const char *addr, int dummy __unused, int s, + const struct afswtch *afp) +{ + if (afp->af_getaddr != NULL) + afp->af_getaddr(addr, DSTADDR); +} + +static void +setifipdst(const char *addr, int dummy __unused, int s, + const struct afswtch *afp) +{ + const struct afswtch *inet; + + inet = af_getbyname("inet"); + if (inet == NULL) + return; + inet->af_getaddr(addr, DSTADDR); + clearaddr = 0; + newaddr = 0; +} + +static void +notealias(const char *addr, int param, int s, const struct afswtch *afp) +{ +#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) + if (setaddr && doalias == 0 && param < 0) + if (afp->af_addreq != NULL && afp->af_ridreq != NULL) + bcopy((caddr_t)rqtosa(af_addreq), + (caddr_t)rqtosa(af_ridreq), + rqtosa(af_addreq)->sa_len); + doalias = param; + if (param < 0) { + clearaddr = 1; + newaddr = 0; + } else + clearaddr = 0; +#undef rqtosa +} + +/*ARGSUSED*/ +static void +setifdstaddr(const char *addr, int param __unused, int s, + const struct afswtch *afp) +{ + if (afp->af_getaddr != NULL) + afp->af_getaddr(addr, DSTADDR); +} + +/* + * Note: doing an SIOCIGIFFLAGS scribbles on the union portion + * of the ifreq structure, which may confuse other parts of ifconfig. + * Make a private copy so we can avoid that. + */ +static void +setifflags(const char *vname, int value, int s, const struct afswtch *afp) +{ + struct ifreq my_ifr; + int flags; + + bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); + + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { + Perror("ioctl (SIOCGIFFLAGS)"); + exit(1); + } + strlcpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); + flags = my_ifr.ifr_flags; + + if (value < 0) { + value = -value; + flags &= ~value; + } else + flags |= value; + my_ifr.ifr_flags = flags & 0xffff; + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) + Perror(vname); +} + +void +setifcap(const char *vname, int value, int s, const struct afswtch *afp) +{ + int flags; + + if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) { + Perror("ioctl (SIOCGIFCAP)"); + exit(1); + } + flags = ifr.ifr_curcap; + if (value < 0) { + value = -value; + flags &= ~value; + } else + flags |= value; + flags &= ifr.ifr_reqcap; + ifr.ifr_reqcap = flags; + if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) + Perror(vname); +} + +static void +setifmetric(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + ifr.ifr_metric = atoi(val); + if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) + warn("ioctl (set metric)"); +} + +static void +setifmtu(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + ifr.ifr_mtu = atoi(val); + if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) + warn("ioctl (set mtu)"); +} + +#ifndef __APPLE__ +static void +setifname(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + char *newname; + + newname = strdup(val); + if (newname == NULL) { + warn("no memory to set ifname"); + return; + } + ifr.ifr_data = newname; + if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { + warn("ioctl (set name)"); + free(newname); + return; + } + strlcpy(name, newname, sizeof(name)); + free(newname); +} +#endif + +static void +setrouter(const char *vname, int value, int s, const struct afswtch *afp) +{ + if (afp->af_setrouter == NULL) { + warn("address family %s does not support router mode", + afp->af_name); + return; + } + + afp->af_setrouter(s, value); +} + +static int +routermode(int argc, char *const *argv, int s, const struct afswtch *afp) +{ + return (*afp->af_routermode)(s, argc, argv); +} + + +static void +setifdesc(const char *val, int dummy __unused, int s, const struct afswtch *afp) +{ + struct if_descreq ifdr; + + bzero(&ifdr, sizeof (ifdr)); + strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name)); + ifdr.ifdr_len = strlen(val); + strlcpy((char *)ifdr.ifdr_desc, val, sizeof (ifdr.ifdr_desc)); + + if (ioctl(s, SIOCSIFDESC, (caddr_t)&ifdr) < 0) { + warn("ioctl (set desc)"); + } +} + +static void +settbr(const char *val, int dummy __unused, int s, const struct afswtch *afp) +{ + struct if_linkparamsreq iflpr; + long double bps; + u_int64_t rate; + u_int32_t percent = 0; + char *cp; + + errno = 0; + bzero(&iflpr, sizeof (iflpr)); + strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name)); + + bps = strtold(val, &cp); + if (val == cp || errno != 0) { + warn("Invalid value '%s'", val); + return; + } + rate = (u_int64_t)bps; + if (cp != NULL) { + if (!strcmp(cp, "b") || !strcmp(cp, "bps")) { + ; /* nothing */ + } else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbps")) { + rate *= 1000; + } else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbps")) { + rate *= 1000 * 1000; + } else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbps")) { + rate *= 1000 * 1000 * 1000; + } else if (!strcmp(cp, "%")) { + percent = rate; + if (percent == 0 || percent > 100) { + printf("Value out of range '%s'", val); + return; + } + } else if (*cp != '\0') { + printf("Unknown unit '%s'", cp); + return; + } + } + iflpr.iflpr_output_tbr_rate = rate; + iflpr.iflpr_output_tbr_percent = percent; + if (ioctl(s, SIOCSIFLINKPARAMS, &iflpr) < 0 && + errno != ENOENT && errno != ENXIO && errno != ENODEV) { + warn("ioctl (set link params)"); + } else if (errno == ENXIO) { + printf("TBR cannot be set on %s\n", name); + } else if (errno == 0 && rate == 0) { + printf("%s: TBR is now disabled\n", name); + } else if (errno == ENODEV) { + printf("%s: requires absolute TBR rate\n", name); + } else if (percent != 0) { + printf("%s: TBR rate set to %u%% of effective link rate\n", + name, percent); + } else { + printf("%s: TBR rate set to %s\n", name, bps_to_str(rate)); + } +} + +static int +get_int64(uint64_t *i, char const *s) +{ + char *cp; + *i = strtol(s, &cp, 10); + if (cp == s || errno != 0) { + return (-1); + } + return (0); +} + +static int +get_int32(uint32_t *i, char const *s) +{ + char *cp; + *i = strtol(s, &cp, 10); + if (cp == s || errno != 0) { + return (-1); + } + return (0); +} + +static int +get_percent(double *d, const char *s) +{ + char *cp; + *d = strtod(s, &cp) / (double)100; + if (*d == HUGE_VALF || *d == HUGE_VALL) { + return (-1); + } + if (*d == 0.0 || (*cp != '\0' && strcmp(cp, "%") != 0)) { + return (-1); + } + return (0); +} + +static int +get_percent_fixed_point(uint32_t *i, const char *s) +{ + double p; + + if (get_percent(&p, s) != 0){ + return (-1); + } + + *i = p * IF_NETEM_PARAMS_PSCALE; + return (0); +} + +static int +netem_parse_args(struct if_netem_params *p, int argc, char *const *argv) +{ + int argc_saved = argc; + uint64_t bandwitdh = 0; + uint32_t latency = 0, jitter = 0; + uint32_t corruption = 0; + uint32_t duplication = 0; + uint32_t loss_p_gr_gl = 0, loss_p_gr_bl = 0, loss_p_bl_br = 0, + loss_p_bl_gr = 0, loss_p_br_bl = 0; + uint32_t reordering = 0; + + bzero(p, sizeof (*p)); + + /* take out "input"/"output" */ + argc--, argv++; + + for ( ; argc > 0; ) { + if (strcmp(*argv, "bandwidth") == 0) { + argc--, argv++; + if (argc <= 0 || get_int64(&bandwitdh, *argv) != 0) { + err(1, "Invalid value '%s'", *argv); + } + argc--, argv++; + } else if (strcmp(*argv, "corruption") == 0) { + argc--, argv++; + if (argc <= 0 || + get_percent_fixed_point(&corruption, *argv) != 0) { + err(1, "Invalid value '%s'", *argv); + } + argc--, argv++; + } else if (strcmp(*argv, "delay") == 0) { + argc--, argv++; + if (argc <= 0 || get_int32(&latency, *argv) != 0) { + err(1, "Invalid value '%s'", *argv); + } + argc--, argv++; + if (argc > 0 && get_int32(&jitter, *argv) == 0) { + argc--, argv++; + } + } else if (strcmp(*argv, "duplication") == 0) { + argc--, argv++; + if (argc <= 0 || + get_percent_fixed_point(&duplication, *argv) != 0) { + err(1, "Invalid value '%s'", *argv); + return (-1); + } + argc--, argv++; + } else if (strcmp(*argv, "loss") == 0) { + argc--, argv++; + if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_gl, *argv) != 0) { + err(1, "Invalid value '%s'", *argv); + } + /* we may have all 5 probs, use naive model if not */ + argc--, argv++; + if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_bl, *argv) != 0) { + continue; + } + /* if more than p_gr_gl, then should have all probs */ + argc--, argv++; + if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_br, *argv) != 0) { + err(1, "Invalid value '%s' for p_bl_br", *argv); + } + argc--, argv++; + if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_gr, *argv) != 0) { + err(1, "Invalid value '%s' for p_bl_gr", *argv); + } + argc--, argv++; + if (argc <= 0 || get_percent_fixed_point(&loss_p_br_bl, *argv) != 0) { + err(1, "Invalid value '%s' for p_br_bl", *argv); + } + argc--, argv++; + } else if (strcmp(*argv, "reordering") == 0) { + argc--, argv++; + if (argc <= 0 || get_percent_fixed_point(&reordering, *argv) != 0) { + err(1, "Invalid value '%s'", *argv); + } + argc--, argv++; + } else { + return (-1); + } + } + + if (corruption > IF_NETEM_PARAMS_PSCALE) { + err(1, "corruption percentage > 100%%"); + } + + if (duplication > IF_NETEM_PARAMS_PSCALE) { + err(1, "duplication percentage > 100%%"); + } + + if (duplication > 0 && latency == 0) { + /* we need to insert dup'ed packet with latency */ + err(1, "duplication needs latency param"); + } + + if (latency > 1000) { + err(1, "latency %dms too big (> 1 sec)", latency); + } + + if (jitter * 3 > latency) { + err(1, "jitter %dms too big (latency %dms)", jitter, latency); + } + + /* if gr_gl == 0 (no loss), other prob should all be zero */ + if (loss_p_gr_gl == 0 && + (loss_p_gr_bl != 0 || loss_p_bl_br != 0 || loss_p_bl_gr != 0 || + loss_p_br_bl != 0)) { + err(1, "loss params not all zero when gr_gl is zero"); + } + + /* check state machine transition prob integrity */ + if (loss_p_gr_gl > IF_NETEM_PARAMS_PSCALE || + /* gr_gl = IF_NETEM_PARAMS_PSCALE for total loss */ + loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE || + loss_p_bl_br > IF_NETEM_PARAMS_PSCALE || + loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE || + loss_p_br_bl > IF_NETEM_PARAMS_PSCALE || + loss_p_gr_gl + loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE || + loss_p_bl_br + loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE) { + err(1, "loss params too big"); + } + + if (reordering > IF_NETEM_PARAMS_PSCALE) { + err(1, "reordering percentage > 100%%"); + } + + p->ifnetem_bandwidth_bps = bandwitdh; + p->ifnetem_latency_ms = latency; + p->ifnetem_jitter_ms = jitter; + p->ifnetem_corruption_p = corruption; + p->ifnetem_duplication_p = duplication; + p->ifnetem_loss_p_gr_gl = loss_p_gr_gl; + p->ifnetem_loss_p_gr_bl = loss_p_gr_bl; + p->ifnetem_loss_p_bl_br = loss_p_bl_br; + p->ifnetem_loss_p_bl_gr = loss_p_bl_gr; + p->ifnetem_loss_p_br_bl = loss_p_br_bl; + p->ifnetem_reordering_p = reordering; + + return (argc_saved - argc); +} + +void +print_netem_params(struct if_netem_params *p, const char *desc) +{ + struct if_netem_params zero_params; + double pscale = IF_NETEM_PARAMS_PSCALE / 100; + bzero(&zero_params, sizeof (zero_params)); + + if (memcmp(p, &zero_params, sizeof (zero_params)) == 0) { + printf("%s NetEm Disabled\n\n", desc); + } else { + printf( + "%s NetEm Parameters\n" + "\tbandwidth rate %llubps\n" + "\tdelay latency %dms\n" + "\t jitter %dms\n", + desc, p->ifnetem_bandwidth_bps, + p->ifnetem_latency_ms, p->ifnetem_jitter_ms); + if (p->ifnetem_loss_p_gr_bl == 0 && + p->ifnetem_loss_p_bl_br == 0 && + p->ifnetem_loss_p_bl_gr == 0 && + p->ifnetem_loss_p_br_bl == 0) { + printf( + "\tloss %.3f%%\n", + (double) p->ifnetem_loss_p_gr_gl / pscale); + } else { + printf( + "\tloss GAP_RECV -> GAP_LOSS %.3f%%\n" + "\t GAP_RECV -> BURST_LOSS %.3f%%\n" + "\t BURST_LOSS -> BURST_RECV %.3f%%\n" + "\t BURST_LOSS -> GAP_RECV %.3f%%\n" + "\t BURST_RECV -> BURST_LOSS %.3f%%\n", + (double) p->ifnetem_loss_p_gr_gl / pscale, + (double) p->ifnetem_loss_p_gr_bl / pscale, + (double) p->ifnetem_loss_p_bl_br / pscale, + (double) p->ifnetem_loss_p_bl_gr / pscale, + (double) p->ifnetem_loss_p_br_bl / pscale); + } + printf( + "\tcorruption %.3f%%\n" + "\treordering %.3f%%\n\n", + (double) p->ifnetem_corruption_p / pscale, + (double) p->ifnetem_reordering_p / pscale); + } +} + +static int +setnetem(int argc, char *const *argv, int s, const struct afswtch *afp) +{ + struct if_linkparamsreq iflpr; + struct if_netem_params input_params, output_params; + int ret = 0, error = 0; + + bzero(&iflpr, sizeof (iflpr)); + bzero(&input_params, sizeof (input_params)); + bzero(&output_params, sizeof (output_params)); + + if (argc > 1) { + if (strcmp(argv[0], "input") == 0) { + ret = netem_parse_args(&input_params, argc, argv); + } else if (strcmp(argv[0], "output") == 0) { + ret = netem_parse_args(&output_params, argc, argv); + } else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) { + goto bad_args; + } else { + fprintf(stderr, "uknown option %s\n", argv[0]); + goto bad_args; + } + if (ret < 0) { + goto bad_args; + } + } + + errno = 0; + strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name)); + error = ioctl(s, SIOCGIFLINKPARAMS, &iflpr); + if (error < 0) { + warn("ioctl (get link params)"); + } + + if (argc == 0) { + print_netem_params(&iflpr.iflpr_input_netem, "Input"); + print_netem_params(&iflpr.iflpr_output_netem, "Output"); + return (0); + } else if (argc == 1) { + if (strcmp(argv[0], "input") == 0) { + bzero(&iflpr.iflpr_input_netem, + sizeof (iflpr.iflpr_input_netem)); + } else if (strcmp(argv[0], "output") == 0) { + bzero(&iflpr.iflpr_output_netem, + sizeof (iflpr.iflpr_output_netem)); + } else { + fprintf(stderr, "uknown option %s\n", argv[0]); + goto bad_args; + } + printf("%s: netem is now disabled for %s\n", name, argv[0]); + ret = 1; + } else { + if (strcmp(argv[0], "input") == 0) { + iflpr.iflpr_input_netem = input_params; + } else if (strcmp(argv[0], "output") == 0) { + iflpr.iflpr_output_netem = output_params; + } + } + + error = ioctl(s, SIOCSIFLINKPARAMS, &iflpr); + if (error < 0 && errno != ENOENT && errno != ENXIO && errno != ENODEV) { + warn("ioctl (set link params)"); + } else if (errno == ENXIO) { + printf("netem cannot be set on %s\n", name); + } else { + printf("%s: netem configured\n", name); + } + + return (ret); +bad_args: + fprintf(stderr, "Usage:\n" + "\tTo enable/set netem params\n" + "\t\tnetem <input|output>\n" + "\t\t [ bandwidth BIT_PER_SEC ]\n" + "\t\t [ delay DELAY_MSEC [ JITTER_MSEC ] ]\n" + "\t\t [ loss PERCENTAGE ]\n" + "\t\t [ duplication PERCENTAGE ]\n" + "\t\t [ reordering PERCENTAGE ]\n\n" + "\tTo disable <input|output> netem\n" + "\t\tnetem <input|output>\n\n" + "\tTo show current settings\n" + "\t\tnetem\n\n"); + return (-1); +} + +static void +setthrottle(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + struct if_throttlereq iftr; + char *cp; + + errno = 0; + bzero(&iftr, sizeof (iftr)); + strlcpy(iftr.ifthr_name, name, sizeof (iftr.ifthr_name)); + + iftr.ifthr_level = strtold(val, &cp); + if (val == cp || errno != 0) { + warn("Invalid value '%s'", val); + return; + } + + if (ioctl(s, SIOCSIFTHROTTLE, &iftr) < 0 && errno != ENXIO) { + warn("ioctl (set throttling level)"); + } else if (errno == ENXIO) { + printf("throttling level cannot be set on %s\n", name); + } else { + printf("%s: throttling level set to %d\n", name, + iftr.ifthr_level); + } +} + +static void +setdisableoutput(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + struct ifreq ifr; + char *cp; + errno = 0; + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + + ifr.ifr_ifru.ifru_disable_output = strtold(val, &cp); + if (val == cp || errno != 0) { + warn("Invalid value '%s'", val); + return; + } + + if (ioctl(s, SIOCSIFDISABLEOUTPUT, &ifr) < 0 && errno != ENXIO) { + warn("ioctl set disable output"); + } else if (errno == ENXIO) { + printf("output thread can not be disabled on %s\n", name); + } else { + printf("output %s on %s\n", + ((ifr.ifr_ifru.ifru_disable_output == 0) ? "enabled" : "disabled"), + name); + } +} + +static void +setlog(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + char *cp; + + errno = 0; + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + ifr.ifr_log.ifl_level = strtold(val, &cp); + if (val == cp || errno != 0) { + warn("Invalid value '%s'", val); + return; + } + ifr.ifr_log.ifl_flags = (IFRLOGF_DLIL|IFRLOGF_FAMILY|IFRLOGF_DRIVER| + IFRLOGF_FIRMWARE); + + if (ioctl(s, SIOCSIFLOG, &ifr) < 0) + warn("ioctl (set logging parameters)"); +} + +void +setcl2k(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_2kcl = value; + + if (ioctl(s, SIOCSIF2KCL, (caddr_t)&ifr) < 0) + Perror(vname); +} + +void +setexpensive(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_expensive = value; + + if (ioctl(s, SIOCSIFEXPENSIVE, (caddr_t)&ifr) < 0) + Perror(vname); +} + +#ifdef SIOCSIFCONSTRAINED +void +setconstrained(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_constrained = value; + + if (ioctl(s, SIOCSIFCONSTRAINED, (caddr_t)&ifr) < 0) + Perror(vname); +} +#endif + +static void +setifmpklog(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_mpk_log = value; + + if (ioctl(s, SIOCSIFMPKLOG, (caddr_t)&ifr) < 0) + Perror(vname); +} + +void +settimestamp(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (value == 0) { + if (ioctl(s, SIOCSIFTIMESTAMPDISABLE, (caddr_t)&ifr) < 0) + Perror(vname); + } else { + if (ioctl(s, SIOCSIFTIMESTAMPENABLE, (caddr_t)&ifr) < 0) + Perror(vname); + } +} + +void +setecnmode(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + char *cp; + + if (strcmp(val, "default") == 0) + ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DEFAULT; + else if (strcmp(val, "enable") == 0) + ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_ENABLE; + else if (strcmp(val, "disable") == 0) + ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DISABLE; + else { + ifr.ifr_ifru.ifru_ecn_mode = strtold(val, &cp); + if (val == cp || errno != 0) { + warn("Invalid ECN mode value '%s'", val); + return; + } + } + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (ioctl(s, SIOCSECNMODE, (caddr_t)&ifr) < 0) + Perror("ioctl(SIOCSECNMODE)"); +} + +void +setprobeconnectivity(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_probe_connectivity = value; + + if (ioctl(s, SIOCSIFPROBECONNECTIVITY, (caddr_t)&ifr) < 0) + Perror(vname); +} + +#if defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) + +void +setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + u_long ioc; + +#if (DEBUG | DEVELOPMENT) + printf("%s(%s, %s)\n", __func__, cmd, arg); +#endif /* (DEBUG | DEVELOPMENT) */ + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (strcmp(cmd, "mode") == 0) { + ioc = SIOCSQOSMARKINGMODE; + + if (strcmp(arg, "fastlane") == 0) + ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE; + else if (strcmp(arg, "rfc4594") == 0) + ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_RFC4594; + else if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "off") == 0) + ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE; + else + err(EX_USAGE, "bad value for qosmarking mode: %s", arg); + } else if (strcmp(cmd, "enabled") == 0) { + ioc = SIOCSQOSMARKINGENABLED; + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + ifr.ifr_qosmarking_enabled = 1; + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + ifr.ifr_qosmarking_enabled = 0; + else + err(EX_USAGE, "bad value for qosmarking enabled: %s", arg); + } else { + err(EX_USAGE, "qosmarking takes mode or enabled"); + } + + if (ioctl(s, ioc, (caddr_t)&ifr) < 0) + err(EX_OSERR, "ioctl(%s, %s)", cmd, arg); +} + +void +setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + warnx("### fastlane is obsolete, use qosmarking ###"); + + if (strcmp(cmd, "capable") == 0) { + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + setqosmarking("mode", "fastlane", s, afp); + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + setqosmarking("mode", "off", s, afp); + else + err(EX_USAGE, "bad value for fastlane %s", cmd); + } else if (strcmp(cmd, "enable") == 0) { + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + setqosmarking("enabled", "1", s, afp); + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + setqosmarking("enabled", "0", s, afp); + else + err(EX_USAGE, "bad value for fastlane %s", cmd); + } else { + err(EX_USAGE, "fastlane takes capable or enable"); + } +} + +#else /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */ + +void +setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + int value; + u_long ioc; + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (strcmp(cmd, "capable") == 0) + ioc = SIOCSFASTLANECAPABLE; + else if (strcmp(cmd, "enable") == 0) + ioc = SIOCSFASTLEENABLED; + else + err(EX_USAGE, "fastlane takes capable or enabled"); + + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + value = 1; + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + value = 0; + else + err(EX_USAGE, "bad value for fastlane %s", cmd); + + if (ioc == SIOCSFASTLANECAPABLE) + ifr.ifr_fastlane_capable = value; + else + ifr.ifr_fastlane_enabled = value; + + if (ioctl(s, ioc, (caddr_t)&ifr) < 0) + err(EX_OSERR, "ioctl(%s, %s)", cmd, arg); +} + + +void +setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp) +{ + if (strcmp(cmd, "mode") == 0) { + if (strcmp(arg, "fastlane") == 0) + setfastlane("capable", "on", s, afp); + else if (strcmp(arg, "none") == 0) + setfastlane("capable", "off", s, afp); + else + err(EX_USAGE, "bad value for qosmarking mode: %s", arg); + } else if (strcmp(cmd, "enabled") == 0) { + if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0|| + strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0) + setfastlane("enable", "on", s, afp); + else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0|| + strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0) + setfastlane("enable", "off", s, afp); + else + err(EX_USAGE, "bad value for qosmarking enabled: %s", arg); + } else { + err(EX_USAGE, "qosmarking takes mode or enabled"); + } +} + +#endif /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */ + +void +setlowpowermode(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_low_power_mode = !!value; + + if (ioctl(s, SIOCSIFLOWPOWER, (caddr_t)&ifr) < 0) + Perror(vname); +} + +struct str2num { + const char *str; + uint32_t num; +}; + +static struct str2num subfamily_str2num[] = { + { .str = "any", .num = IFRTYPE_SUBFAMILY_ANY }, + { .str = "USB", .num = IFRTYPE_SUBFAMILY_USB }, + { .str = "Bluetooth", .num = IFRTYPE_SUBFAMILY_BLUETOOTH }, + { .str = "Wi-Fi", .num = IFRTYPE_SUBFAMILY_WIFI }, + { .str = "wifi", .num = IFRTYPE_SUBFAMILY_WIFI }, + { .str = "Thunderbolt", .num = IFRTYPE_SUBFAMILY_THUNDERBOLT }, + { .str = "reserverd", .num = IFRTYPE_SUBFAMILY_RESERVED }, + { .str = "intcoproc", .num = IFRTYPE_SUBFAMILY_INTCOPROC }, + { .str = "QuickRelay", .num = IFRTYPE_SUBFAMILY_QUICKRELAY }, + { .str = "Default", .num = IFRTYPE_SUBFAMILY_DEFAULT }, + { .str = NULL, .num = 0 }, +}; + +static uint32_t +get_num_from_str(struct str2num* str2nums, const char *str) +{ + struct str2num *str2num = str2nums; + + while (str2num != NULL && str2num->str != NULL) { + if (strcasecmp(str2num->str, str) == 0) { + return str2num->num; + } + str2num++; + } + return 0; +} + +static void +setifsubfamily(const char *val, int dummy __unused, int s, + const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + + char *endptr; + uint32_t subfamily = strtoul(val, &endptr, 0); + if (*endptr != 0) { + subfamily = get_num_from_str(subfamily_str2num, val); + if (subfamily == 0) { + return; + } + } + + ifr.ifr_type.ift_subfamily = subfamily; + if (ioctl(s, SIOCSIFSUBFAMILY, (caddr_t)&ifr) < 0) + warn("ioctl(SIOCSIFSUBFAMILY)"); +} + +void +setifavailability(const char *vname, int value, int s, const struct afswtch *afp) +{ + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_interface_state.valid_bitmask = IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID; + if (value == 0) { + ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE; + } else { + ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_AVAILABLE; + } + if (ioctl(s, SIOCSIFINTERFACESTATE, (caddr_t)&ifr) < 0) + warn("ioctl(SIOCSIFINTERFACESTATE)"); +} + +static void +show_routermode(int s) +{ + struct afswtch *afp; + + afp = af_getbyname("inet"); + if (afp != NULL) { + (*afp->af_routermode)(s, 0, NULL); + } +} + +static void +show_routermode6(void) +{ + struct afswtch *afp; + static int s = -1; + + afp = af_getbyname("inet6"); + if (afp != NULL) { + if (s < 0) { + s = socket(AF_INET6, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return; + } + } + (*afp->af_routermode)(s, 0, NULL); + } +} + +#define IFFBITS \ +"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ +"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ +"\20MULTICAST" + +#define IFEFBITS \ +"\020\1AUTOCONFIGURING\4PROBE_CONNECTIVITY\5FASTLN_CAP\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \ +"\12VLAN\13BOND\14ARPLL\15CLAT46\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \ +"\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \ +"\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\33CHANNEL_DRV\34CA" \ +"\35SENDLIST\36DIRECTLINK\37FASTLN_ON\40UPDOWNCHANGE" + +#define IFXFBITS \ +"\020\1WOL\2TIMESTAMP\3NOAUTONX\4LEGACY\5TXLOWINET\6RXLOWINET\7ALLOCKPI" \ +"\10LOWPOWER\11MPKLOG\12CONSTRAINED" + +#define IFCAPBITS \ +"\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \ +"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS\13CHANNEL_IO\14HW_TIMESTAMP\15SW_TIMESTAMP" \ +"\16PARTIAL_CSUM\17ZEROINVERT_CSUM" + +#define IFRLOGF_BITS \ +"\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE" + +/* + * Print the status of the interface. If an address family was + * specified, show only it; otherwise, show them all. + */ +static void +status(const struct afswtch *afp, const struct sockaddr_dl *sdl, + struct ifaddrs *ifa) +{ + struct ifaddrs *ift; + int allfamilies, s; + struct ifstat ifs; + struct if_descreq ifdr; + struct if_linkparamsreq iflpr; + int mib[6]; + struct ifmibdata_supplemental ifmsupp; + size_t miblen = sizeof(struct ifmibdata_supplemental); + u_int64_t eflags = 0; + u_int64_t xflags = 0; + int curcap = 0; + + if (afp == NULL) { + allfamilies = 1; + afp = af_getbyname("inet"); + } else + allfamilies = 0; + + ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); + if (s < 0) + err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); + + printf("%s: ", name); + printb("flags", ifa->ifa_flags, IFFBITS); + if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1) + if (ifr.ifr_metric) + printf(" metric %d", ifr.ifr_metric); + if (ioctl(s, SIOCGIFMTU, &ifr) != -1) + printf(" mtu %d", ifr.ifr_mtu); + if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1) + printf(" rtref %d", ifr.ifr_route_refcnt); + if (verbose) { + unsigned int ifindex = if_nametoindex(ifa->ifa_name); + if (ifindex != 0) + printf(" index %u", ifindex); + } +#ifdef SIOCGIFCONSTRAINED + // Constrained is stored in if_xflags which isn't exposed directly + if (ioctl(s, SIOCGIFCONSTRAINED, (caddr_t)&ifr) == 0 && + ifr.ifr_constrained != 0) { + printf(" constrained"); + } +#endif + putchar('\n'); + + if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 && + (eflags = ifr.ifr_eflags) != 0) { + printb("\teflags", eflags, IFEFBITS); + putchar('\n'); + } + + if (verbose && ioctl(s, SIOCGIFXFLAGS, (caddr_t)&ifr) != -1 && + (xflags = ifr.ifr_xflags) != 0) { + printb("\txflags", xflags, IFXFBITS); + putchar('\n'); + } + + if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { + if (ifr.ifr_curcap != 0) { + curcap = ifr.ifr_curcap; + printb("\toptions", ifr.ifr_curcap, IFCAPBITS); + putchar('\n'); + } + if (supmedia && ifr.ifr_reqcap != 0) { + printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); + putchar('\n'); + } + } + + tunnel_status(s); + + for (ift = ifa; ift != NULL; ift = ift->ifa_next) { + if (ift->ifa_addr == NULL) + continue; + if (strcmp(ifa->ifa_name, ift->ifa_name) != 0) + continue; + if (allfamilies) { + const struct afswtch *p; + p = af_getbyfamily(ift->ifa_addr->sa_family); + if (p != NULL && p->af_status != NULL) + p->af_status(s, ift); + } else if (afp->af_af == ift->ifa_addr->sa_family) + afp->af_status(s, ift); + } + +/* Print CLAT46 address */ + clat46_addr(s, name); + +/* Print NAT64 prefix */ + nat64_status(s, name); + +#if 0 + if (allfamilies || afp->af_af == AF_LINK) { + const struct afswtch *lafp; + + /* + * Hack; the link level address is received separately + * from the routing information so any address is not + * handled above. Cobble together an entry and invoke + * the status method specially. + */ + lafp = af_getbyname("lladdr"); + if (lafp != NULL) { + info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; + lafp->af_status(s, &info); + } + } +#endif + if (allfamilies) + af_other_status(s); + else if (afp->af_other_status != NULL) + afp->af_other_status(s); + + strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name); + if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) + printf("%s", ifs.ascii); + + /* The rest is for when verbose is set; if not set, we're done */ + if (!verbose) + goto done; + + if (ioctl(s, SIOCGIFTYPE, &ifr) != -1) { + char *c = ift2str(ifr.ifr_type.ift_type, + ifr.ifr_type.ift_family, ifr.ifr_type.ift_subfamily); + if (c != NULL) + printf("\ttype: %s\n", c); + } + + if (verbose > 1) { + if (ioctl(s, SIOCGIFFUNCTIONALTYPE, &ifr) != -1) { + char *c = iffunct2str(ifr.ifr_functional_type); + if (c != NULL) + printf("\tfunctional type: %s\n", c); + } + } + { + struct if_agentidsreq ifar; + memset(&ifar, 0, sizeof(ifar)); + + strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name)); + + if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != -1) { + if (ifar.ifar_count != 0) { + ifar.ifar_uuids = calloc(ifar.ifar_count, sizeof(uuid_t)); + if (ifar.ifar_uuids != NULL) { + if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != 1) { + for (int agent_i = 0; agent_i < ifar.ifar_count; agent_i++) { + struct netagent_req nar; + memset(&nar, 0, sizeof(nar)); + + uuid_copy(nar.netagent_uuid, ifar.ifar_uuids[agent_i]); + + if (ioctl(s, SIOCGIFAGENTDATA, &nar) != 1) { + printf("\tagent domain:%s type:%s flags:0x%x desc:\"%s\"\n", + nar.netagent_domain, nar.netagent_type, + nar.netagent_flags, nar.netagent_desc); + } + } + } + free(ifar.ifar_uuids); + } + } + } + } + + if (ioctl(s, SIOCGIFLINKQUALITYMETRIC, &ifr) != -1) { + int lqm = ifr.ifr_link_quality_metric; + if (verbose > 1) { + printf("\tlink quality: %d ", lqm); + if (lqm == IFNET_LQM_THRESH_OFF) + printf("(off)"); + else if (lqm == IFNET_LQM_THRESH_UNKNOWN) + printf("(unknown)"); + else if (lqm > IFNET_LQM_THRESH_UNKNOWN && + lqm <= IFNET_LQM_THRESH_BAD) + printf("(bad)"); + else if (lqm > IFNET_LQM_THRESH_UNKNOWN && + lqm <= IFNET_LQM_THRESH_POOR) + printf("(poor)"); + else if (lqm > IFNET_LQM_THRESH_POOR && + lqm <= IFNET_LQM_THRESH_GOOD) + printf("(good)"); + else + printf("(?)"); + printf("\n"); + } else if (lqm > IFNET_LQM_THRESH_UNKNOWN) { + printf("\tlink quality: %d ", lqm); + if (lqm <= IFNET_LQM_THRESH_BAD) + printf("(bad)"); + else if (lqm <= IFNET_LQM_THRESH_POOR) + printf("(poor)"); + else if (lqm <= IFNET_LQM_THRESH_GOOD) + printf("(good)"); + else + printf("(?)"); + printf("\n"); + } + } + + { + if (ioctl(s, SIOCGIFINTERFACESTATE, &ifr) != -1) { + printf("\tstate"); + if (ifr.ifr_interface_state.valid_bitmask & + IF_INTERFACE_STATE_RRC_STATE_VALID) { + uint8_t rrc_state = ifr.ifr_interface_state.rrc_state; + + printf(" rrc: %u ", rrc_state); + if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_CONNECTED) + printf("(connected)"); + else if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_IDLE) + printf("(idle)"); + else + printf("(?)"); + } + if (ifr.ifr_interface_state.valid_bitmask & + IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) { + uint8_t ifavail = ifr.ifr_interface_state.interface_availability; + + printf(" availability: %u ", ifavail); + if (ifavail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE) + printf("(true)"); + else if (ifavail == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE) + printf("(false)"); + else + printf("(?)"); + } else { + printf(" availability: (not valid)"); + } + if (verbose > 1 && + ifr.ifr_interface_state.valid_bitmask & + IF_INTERFACE_STATE_LQM_STATE_VALID) { + int8_t lqm = ifr.ifr_interface_state.lqm_state; + + printf(" lqm: %d", lqm); + + if (lqm == IFNET_LQM_THRESH_OFF) + printf("(off)"); + else if (lqm == IFNET_LQM_THRESH_UNKNOWN) + printf("(unknown)"); + else if (lqm == IFNET_LQM_THRESH_BAD) + printf("(bad)"); + else if (lqm == IFNET_LQM_THRESH_POOR) + printf("(poor)"); + else if (lqm == IFNET_LQM_THRESH_GOOD) + printf("(good)"); + else + printf("(?)"); + } + } + printf("\n"); + } + + bzero(&iflpr, sizeof (iflpr)); + strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name)); + if (ioctl(s, SIOCGIFLINKPARAMS, &iflpr) != -1) { + u_int64_t ibw_max = iflpr.iflpr_input_bw.max_bw; + u_int64_t ibw_eff = iflpr.iflpr_input_bw.eff_bw; + u_int64_t obw_max = iflpr.iflpr_output_bw.max_bw; + u_int64_t obw_eff = iflpr.iflpr_output_bw.eff_bw; + u_int64_t obw_tbr = iflpr.iflpr_output_tbr_rate; + u_int32_t obw_pct = iflpr.iflpr_output_tbr_percent; + u_int64_t ilt_max = iflpr.iflpr_input_lt.max_lt; + u_int64_t ilt_eff = iflpr.iflpr_input_lt.eff_lt; + u_int64_t olt_max = iflpr.iflpr_output_lt.max_lt; + u_int64_t olt_eff = iflpr.iflpr_output_lt.eff_lt; + + + if (eflags & IFEF_TXSTART) { + u_int32_t flags = iflpr.iflpr_flags; + u_int32_t sched = iflpr.iflpr_output_sched; + struct if_throttlereq iftr; + + printf("\tscheduler: %s%s ", + (flags & IFLPRF_ALTQ) ? "ALTQ_" : "", + sched2str(sched)); + if (flags & IFLPRF_DRVMANAGED) + printf("(driver managed)"); + printf("\n"); + + bzero(&iftr, sizeof (iftr)); + strlcpy(iftr.ifthr_name, name, + sizeof (iftr.ifthr_name)); + if (ioctl(s, SIOCGIFTHROTTLE, &iftr) != -1 && + iftr.ifthr_level != IFNET_THROTTLE_OFF) + printf("\tthrottling: level %d (%s)\n", + iftr.ifthr_level, tl2str(iftr.ifthr_level)); + } + + if (obw_tbr != 0 && obw_eff > obw_tbr) + obw_eff = obw_tbr; + + if (ibw_max != 0 || obw_max != 0) { + if (ibw_max == obw_max && ibw_eff == obw_eff && + ibw_max == ibw_eff && obw_tbr == 0) { + printf("\tlink rate: %s\n", + bps_to_str(ibw_max)); + } else { + printf("\tuplink rate: %s [eff] / ", + bps_to_str(obw_eff)); + if (obw_tbr != 0) { + if (obw_pct == 0) + printf("%s [tbr] / ", + bps_to_str(obw_tbr)); + else + printf("%s [tbr %u%%] / ", + bps_to_str(obw_tbr), + obw_pct); + } + printf("%s", bps_to_str(obw_max)); + if (obw_tbr != 0) + printf(" [max]"); + printf("\n"); + if (ibw_eff == ibw_max) { + printf("\tdownlink rate: %s\n", + bps_to_str(ibw_max)); + } else { + printf("\tdownlink rate: " + "%s [eff] / ", bps_to_str(ibw_eff)); + printf("%s [max]\n", + bps_to_str(ibw_max)); + } + } + } else if (obw_tbr != 0) { + printf("\tuplink rate: %s [tbr]\n", + bps_to_str(obw_tbr)); + } + + if (ilt_max != 0 || olt_max != 0) { + if (ilt_max == olt_max && ilt_eff == olt_eff && + ilt_max == ilt_eff) { + printf("\tlink latency: %s\n", + ns_to_str(ilt_max)); + } else { + if (olt_max != 0 && olt_eff == olt_max) { + printf("\tuplink latency: %s\n", + ns_to_str(olt_max)); + } else if (olt_max != 0) { + printf("\tuplink latency: " + "%s [eff] / ", ns_to_str(olt_eff)); + printf("%s [max]\n", + ns_to_str(olt_max)); + } + if (ilt_max != 0 && ilt_eff == ilt_max) { + printf("\tdownlink latency: %s\n", + ns_to_str(ilt_max)); + } else if (ilt_max != 0) { + printf("\tdownlink latency: " + "%s [eff] / ", ns_to_str(ilt_eff)); + printf("%s [max]\n", + ns_to_str(ilt_max)); + } + } + } + } + + /* Common OID prefix */ + mib[0] = CTL_NET; + mib[1] = PF_LINK; + mib[2] = NETLINK_GENERIC; + mib[3] = IFMIB_IFDATA; + mib[4] = if_nametoindex(name); + mib[5] = IFDATA_SUPPLEMENTAL; + if (sysctl(mib, 6, &ifmsupp, &miblen, (void *)0, 0) == -1) + err(1, "sysctl IFDATA_SUPPLEMENTAL"); + + if (ifmsupp.ifmd_data_extended.ifi_alignerrs != 0) { + printf("\tunaligned pkts: %llu\n", + ifmsupp.ifmd_data_extended.ifi_alignerrs); + } + if (ifmsupp.ifmd_data_extended.ifi_dt_bytes != 0) { + printf("\tdata milestone interval: %s\n", + bytes_to_str(ifmsupp.ifmd_data_extended.ifi_dt_bytes)); + } + + bzero(&ifdr, sizeof (ifdr)); + strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name)); + if (ioctl(s, SIOCGIFDESC, &ifdr) != -1 && ifdr.ifdr_len) { + printf("\tdesc: %s\n", ifdr.ifdr_desc); + } + + if (ioctl(s, SIOCGIFLOG, &ifr) != -1 && ifr.ifr_log.ifl_level) { + printf("\tlogging: level %d ", ifr.ifr_log.ifl_level); + printb("facilities", ifr.ifr_log.ifl_flags, IFRLOGF_BITS); + putchar('\n'); + } + + if (ioctl(s, SIOCGIFDELEGATE, &ifr) != -1 && ifr.ifr_delegated) { + char delegatedif[IFNAMSIZ+1]; + if (if_indextoname(ifr.ifr_delegated, delegatedif) != NULL) + printf("\teffective interface: %s\n", delegatedif); + } + + if (ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) { + if (ifr.ifr_start_delay_qlen > 0 && + ifr.ifr_start_delay_timeout > 0) { + printf("\ttxstart qlen: %u packets " + "timeout: %u microseconds\n", + ifr.ifr_start_delay_qlen, + ifr.ifr_start_delay_timeout/1000); + } + } +#if defined(IFCAP_HW_TIMESTAMP) && defined(IFCAP_SW_TIMESTAMP) + if ((curcap & (IFCAP_HW_TIMESTAMP | IFCAP_SW_TIMESTAMP)) && + ioctl(s, SIOCGIFTIMESTAMPENABLED, &ifr) != -1) { + printf("\ttimestamp: %s\n", + (ifr.ifr_intval != 0) ? "enabled" : "disabled"); + } +#endif +#if defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) + if (ioctl(s, SIOCGQOSMARKINGENABLED, &ifr) != -1) { + printf("\tqosmarking enabled: %s mode: ", + ifr.ifr_qosmarking_enabled ? "yes" : "no"); + if (ioctl(s, SIOCGQOSMARKINGMODE, &ifr) != -1) { + switch (ifr.ifr_qosmarking_mode) { + case IFRTYPE_QOSMARKING_FASTLANE: + printf("fastlane\n"); + break; + case IFRTYPE_QOSMARKING_RFC4594: + printf("RFC4594\n"); + break; + case IFRTYPE_QOSMARKING_MODE_NONE: + printf("none\n"); + break; + default: + printf("unknown (%u)\n", ifr.ifr_qosmarking_mode); + break; + } + } + } +#endif /* defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) */ + + if (ioctl(s, SIOCGIFLOWPOWER, &ifr) != -1) { + printf("\tlow power mode: %s\n", + (ifr.ifr_low_power_mode != 0) ? "enabled" : "disabled"); + } + if (ioctl(s, SIOCGIFMPKLOG, &ifr) != -1) { + printf("\tmulti layer packet logging (mpklog): %s\n", + (ifr.ifr_mpk_log != 0) ? "enabled" : "disabled"); + } + show_routermode(s); + show_routermode6(); + +done: + close(s); + return; +} + +#define KILOBYTES 1024 +#define MEGABYTES (KILOBYTES * KILOBYTES) +#define GIGABYTES (KILOBYTES * KILOBYTES * KILOBYTES) + +static char * +bytes_to_str(unsigned long long bytes) +{ + static char buf[32]; + const char *u; + long double n = bytes, t; + + if (bytes >= GIGABYTES) { + t = n / GIGABYTES; + u = "GB"; + } else if (n >= MEGABYTES) { + t = n / MEGABYTES; + u = "MB"; + } else if (n >= KILOBYTES) { + t = n / KILOBYTES; + u = "KB"; + } else { + t = n; + u = "bytes"; + } + + snprintf(buf, sizeof (buf), "%-4.2Lf %s", t, u); + return (buf); +} + +#define GIGABIT_PER_SEC 1000000000 /* gigabit per second */ +#define MEGABIT_PER_SEC 1000000 /* megabit per second */ +#define KILOBIT_PER_SEC 1000 /* kilobit per second */ + +static char * +bps_to_str(unsigned long long rate) +{ + static char buf[32]; + const char *u; + long double n = rate, t; + + if (rate >= GIGABIT_PER_SEC) { + t = n / GIGABIT_PER_SEC; + u = "Gbps"; + } else if (n >= MEGABIT_PER_SEC) { + t = n / MEGABIT_PER_SEC; + u = "Mbps"; + } else if (n >= KILOBIT_PER_SEC) { + t = n / KILOBIT_PER_SEC; + u = "Kbps"; + } else { + t = n; + u = "bps "; + } + + snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u); + return (buf); +} + +#define NSEC_PER_SEC 1000000000 /* nanosecond per second */ +#define USEC_PER_SEC 1000000 /* microsecond per second */ +#define MSEC_PER_SEC 1000 /* millisecond per second */ + +static char * +ns_to_str(unsigned long long nsec) +{ + static char buf[32]; + const char *u; + long double n = nsec, t; + + if (nsec >= NSEC_PER_SEC) { + t = n / NSEC_PER_SEC; + u = "sec "; + } else if (n >= USEC_PER_SEC) { + t = n / USEC_PER_SEC; + u = "msec"; + } else if (n >= MSEC_PER_SEC) { + t = n / MSEC_PER_SEC; + u = "usec"; + } else { + t = n; + u = "nsec"; + } + + snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u); + return (buf); +} + +static void +tunnel_status(int s) +{ + af_all_tunnel_status(s); +} + +static void +clat46_addr(int s, char * if_name) +{ + struct if_clat46req ifr; + char buf[MAXHOSTNAMELEN]; + + bzero(&ifr, sizeof (ifr)); + strlcpy(ifr.ifclat46_name, if_name, sizeof(ifr.ifclat46_name)); + + if (ioctl(s, SIOCGIFCLAT46ADDR, &ifr) < 0) { + if (errno != ENOENT) + syslog(LOG_WARNING, "ioctl (SIOCGIFCLAT46ADDR): %d", errno); + return; + } + + if (inet_ntop(AF_INET6, &ifr.ifclat46_addr.v6_address, buf, sizeof(buf)) != NULL) + printf("\tinet6 %s prefixlen %d clat46\n", + buf, ifr.ifclat46_addr.v6_prefixlen); +} + +static void +nat64_status(int s, char * if_name) +{ + int i; + struct if_nat64req ifr; + char buf[MAXHOSTNAMELEN]; + + bzero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifnat64_name, if_name, sizeof(ifr.ifnat64_name)); + + if (ioctl(s, SIOCGIFNAT64PREFIX, &ifr) < 0) { + if (errno != ENOENT) + syslog(LOG_WARNING, "ioctl(SIOCGIFNAT64PREFIX): %d", errno); + return; + } + + for (i = 0; i < NAT64_MAX_NUM_PREFIXES; i++) { + if (ifr.ifnat64_prefixes[i].prefix_len > 0) { + inet_ntop(AF_INET6, &ifr.ifnat64_prefixes[i].ipv6_prefix, buf, sizeof(buf)); + printf("\tnat64 prefix %s prefixlen %d\n", + buf, ifr.ifnat64_prefixes[i].prefix_len << 3); + } + } +} + +void +Perror(const char *cmd) +{ + switch (errno) { + + case ENXIO: + errx(1, "%s: no such interface", cmd); + break; + + case EPERM: + errx(1, "%s: permission denied", cmd); + break; + + default: + err(1, "%s", cmd); + } +} + +/* + * Print a value a la the %b format of the kernel's printf + */ +void +printb(const char *s, unsigned v, const char *bits) +{ + int i, any = 0; + char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v); + else + printf("%s=%x", s, v); + bits++; + if (bits) { + putchar('<'); + while ((i = *bits++) != '\0') { + if (v & (1 << (i-1))) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else + for (; *bits > 32; bits++) + ; + } + putchar('>'); + } +} + +#ifndef __APPLE__ +void +ifmaybeload(const char *name) +{ +#define MOD_PREFIX_LEN 3 /* "if_" */ + struct module_stat mstat; + int fileid, modid; + char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp; + const char *cp; + + /* loading suppressed by the user */ + if (noload) + return; + + /* trim the interface number off the end */ + strlcpy(ifname, name, sizeof(ifname)); + for (dp = ifname; *dp != 0; dp++) + if (isdigit(*dp)) { + *dp = 0; + break; + } + + /* turn interface and unit into module name */ + strlcpy(ifkind, "if_", sizeof(ifkind)); + strlcpy(ifkind + MOD_PREFIX_LEN, ifname, + sizeof(ifkind) - MOD_PREFIX_LEN); + + /* scan files in kernel */ + mstat.version = sizeof(struct module_stat); + for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { + /* scan modules in file */ + for (modid = kldfirstmod(fileid); modid > 0; + modid = modfnext(modid)) { + if (modstat(modid, &mstat) < 0) + continue; + /* strip bus name if present */ + if ((cp = strchr(mstat.name, '/')) != NULL) { + cp++; + } else { + cp = mstat.name; + } + /* already loaded? */ + if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 || + strncmp(ifkind, cp, strlen(ifkind) + 1) == 0) + return; + } + } + + /* not present, we should try to load it */ + kldload(ifkind); +} +#endif + +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), +#ifdef IFF_PPROMISC + DEF_CMD("promisc", IFF_PPROMISC, setifflags), + DEF_CMD("-promisc", -IFF_PPROMISC, setifflags), +#endif /* IFF_PPROMISC */ + DEF_CMD("add", IFF_UP, notealias), + DEF_CMD("alias", IFF_UP, notealias), + DEF_CMD("-alias", -IFF_UP, notealias), + DEF_CMD("delete", -IFF_UP, notealias), + DEF_CMD("remove", -IFF_UP, notealias), +#ifdef notdef +#define EN_SWABIPS 0x1000 + DEF_CMD("swabips", EN_SWABIPS, setifflags), + DEF_CMD("-swabips", -EN_SWABIPS, setifflags), +#endif + DEF_CMD_ARG("netmask", setifnetmask), + DEF_CMD_ARG("metric", setifmetric), + DEF_CMD_ARG("broadcast", setifbroadaddr), + DEF_CMD_ARG("ipdst", setifipdst), + DEF_CMD_ARG2("tunnel", settunnel), + DEF_CMD("-tunnel", 0, deletetunnel), + DEF_CMD("deletetunnel", 0, deletetunnel), + DEF_CMD("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 IFF_MONITOR + DEF_CMD("monitor", IFF_MONITOR:, setifflags), + DEF_CMD("-monitor", -IFF_MONITOR, setifflags), +#endif /* IFF_MONITOR */ + DEF_CMD("mpklog", 1, setifmpklog), + DEF_CMD("-mpklog", 0, setifmpklog), +#ifdef IFF_STATICARP + DEF_CMD("staticarp", IFF_STATICARP, setifflags), + DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), +#endif /* IFF_STATICARP */ +#ifdef IFCAP_RXCSUM + DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), + DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), +#endif /* IFCAP_RXCSUM */ +#ifdef IFCAP_TXCSUM + DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), + DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), +#endif /* IFCAP_TXCSUM */ +#ifdef IFCAP_NETCONS + DEF_CMD("netcons", IFCAP_NETCONS, setifcap), + DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), +#endif /* IFCAP_NETCONS */ +#ifdef IFCAP_POLLING + DEF_CMD("polling", IFCAP_POLLING, setifcap), + DEF_CMD("-polling", -IFCAP_POLLING, setifcap), +#endif /* IFCAP_POLLING */ +#ifdef IFCAP_TSO + DEF_CMD("tso", IFCAP_TSO, setifcap), + DEF_CMD("-tso", -IFCAP_TSO, setifcap), +#endif /* IFCAP_TSO */ +#ifdef IFCAP_LRO + DEF_CMD("lro", IFCAP_LRO, setifcap), + DEF_CMD("-lro", -IFCAP_LRO, setifcap), +#endif /* IFCAP_LRO */ +#ifdef IFCAP_WOL + DEF_CMD("wol", IFCAP_WOL, setifcap), + DEF_CMD("-wol", -IFCAP_WOL, setifcap), +#endif /* IFCAP_WOL */ +#ifdef IFCAP_WOL_UCAST + DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), + DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap), +#endif /* IFCAP_WOL_UCAST */ +#ifdef IFCAP_WOL_MCAST + DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap), + DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap), +#endif /* IFCAP_WOL_MCAST */ +#ifdef IFCAP_WOL_MAGIC + DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap), + DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap), +#endif /* IFCAP_WOL_MAGIC */ + DEF_CMD("normal", -IFF_LINK0, setifflags), + DEF_CMD("compress", IFF_LINK0, setifflags), + DEF_CMD("noicmp", IFF_LINK1, setifflags), + DEF_CMD_ARG("mtu", setifmtu), +#ifdef notdef + DEF_CMD_ARG("name", setifname), +#endif /* notdef */ +#ifdef IFCAP_AV + DEF_CMD("av", IFCAP_AV, setifcap), + DEF_CMD("-av", -IFCAP_AV, setifcap), +#endif /* IFCAP_AV */ + DEF_CMD("router", 1, setrouter), + DEF_CMD("-router", 0, setrouter), + DEF_CMD_VA("routermode", routermode), + DEF_CMD_ARG("desc", setifdesc), + DEF_CMD_ARG("tbr", settbr), + DEF_CMD_VA("netem", setnetem), + DEF_CMD_ARG("throttle", setthrottle), + DEF_CMD_ARG("log", setlog), + DEF_CMD("cl2k", 1, setcl2k), + DEF_CMD("-cl2k", 0, setcl2k), + DEF_CMD("expensive", 1, setexpensive), + DEF_CMD("-expensive", 0, setexpensive), +#ifdef SIOCSIFCONSTRAINED + DEF_CMD("constrained", 1, setconstrained), + DEF_CMD("-constrained", 0, setconstrained), +#endif + DEF_CMD("timestamp", 1, settimestamp), + DEF_CMD("-timestamp", 0, settimestamp), + DEF_CMD_ARG("ecn", setecnmode), + DEF_CMD_ARG2("fastlane", setfastlane), + DEF_CMD_ARG2("qosmarking", setqosmarking), + DEF_CMD_ARG("disable_output", setdisableoutput), + DEF_CMD("probe_connectivity", 1, setprobeconnectivity), + DEF_CMD("-probe_connectivity", 0, setprobeconnectivity), + DEF_CMD("lowpowermode", 1, setlowpowermode), + DEF_CMD("-lowpowermode", 0, setlowpowermode), + DEF_CMD_ARG("subfamily", setifsubfamily), + DEF_CMD("available", 1, setifavailability), + DEF_CMD("-available", 0, setifavailability), + DEF_CMD("unavailable", 0, setifavailability), +}; + +static __constructor void +ifconfig_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(basic_cmds); i++) + cmd_register(&basic_cmds[i]); +#undef N +} + +static char * +sched2str(unsigned int s) +{ + char *c; + + switch (s) { + case PKTSCHEDT_NONE: + c = "NONE"; + break; + case PKTSCHEDT_FQ_CODEL: + c = "FQ_CODEL"; + break; + default: + c = "UNKNOWN"; + break; + } + + return (c); +} + +static char * +tl2str(unsigned int s) +{ + char *c; + + switch (s) { + case IFNET_THROTTLE_OFF: + c = "off"; + break; + case IFNET_THROTTLE_OPPORTUNISTIC: + c = "opportunistic"; + break; + default: + c = "unknown"; + break; + } + + return (c); +} + +static char * +ift2str(unsigned int t, unsigned int f, unsigned int sf) +{ + static char buf[256]; + char *c = NULL; + + switch (t) { + case IFT_ETHER: + switch (sf) { + case IFRTYPE_SUBFAMILY_USB: + c = "USB Ethernet"; + break; + case IFRTYPE_SUBFAMILY_BLUETOOTH: + c = "Bluetooth PAN"; + break; + case IFRTYPE_SUBFAMILY_WIFI: + c = "Wi-Fi"; + break; + case IFRTYPE_SUBFAMILY_THUNDERBOLT: + c = "IP over Thunderbolt"; + break; + case IFRTYPE_SUBFAMILY_ANY: + default: + c = "Ethernet"; + break; + } + break; + + case IFT_IEEE1394: + c = "IP over FireWire"; + break; + + case IFT_PKTAP: + c = "Packet capture"; + break; + + case IFT_CELLULAR: + c = "Cellular"; + break; + + case IFT_OTHER: + if (ifr.ifr_type.ift_family == APPLE_IF_FAM_IPSEC) { + if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_BLUETOOTH) { + c = "Companion Link Bluetooth"; + } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_QUICKRELAY) { + c = "Companion Link QuickRelay"; + } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_WIFI) { + c = "Companion Link Wi-Fi"; + } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_DEFAULT) { + c = "Companion Link Default"; + } + } + break; + + case IFT_BRIDGE: + case IFT_PFLOG: + case IFT_PFSYNC: + case IFT_PPP: + case IFT_LOOP: + case IFT_GIF: + case IFT_STF: + case IFT_L2VLAN: + case IFT_IEEE8023ADLAG: + default: + break; + } + + if (verbose > 1) { + if (c == NULL) { + (void) snprintf(buf, sizeof (buf), + "0x%x family: %u subfamily: %u", + ifr.ifr_type.ift_type, ifr.ifr_type.ift_family, + ifr.ifr_type.ift_subfamily); + } else { + (void) snprintf(buf, sizeof (buf), + "%s (0x%x) family: %u subfamily: %u", c, + ifr.ifr_type.ift_type, ifr.ifr_type.ift_family, + ifr.ifr_type.ift_subfamily); + } + c = buf; + } + + return (c); +} + +static char * +iffunct2str(u_int32_t functional_type) +{ + char *str = NULL; + + switch (functional_type) { + case IFRTYPE_FUNCTIONAL_UNKNOWN: + break; + + case IFRTYPE_FUNCTIONAL_LOOPBACK: + str = "loopback"; + break; + + case IFRTYPE_FUNCTIONAL_WIRED: + str = "wired"; + break; + + case IFRTYPE_FUNCTIONAL_WIFI_INFRA: + str = "wifi"; + break; + + case IFRTYPE_FUNCTIONAL_WIFI_AWDL: + str = "awdl"; + break; + + case IFRTYPE_FUNCTIONAL_CELLULAR: + str = "cellular"; + break; + + case IFRTYPE_FUNCTIONAL_INTCOPROC: + break; + + case IFRTYPE_FUNCTIONAL_COMPANIONLINK: + str = "companionlink"; + break; + + default: + break; + } + return str; +} diff --git a/network_cmds/ifconfig.tproj/ifconfig.h b/network_cmds/ifconfig.tproj/ifconfig.h new file mode 100644 index 0000000..5d4a7e0 --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifconfig.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2009-2018 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (c) 1997 Peter Wemm. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the FreeBSD Project + * by Peter Wemm. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * so there! + * + * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.21.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $ + */ + +#define __constructor __attribute__((constructor)) + +struct afswtch; +struct cmd; + +typedef void c_func(const char *cmd, int arg, int s, const struct afswtch *afp); +typedef void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp); +typedef int c_funcv(int argc, char *const *argv, 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 */ +#define VAARGS 0xfffffc /* has variable following args */ + union { + c_func *c_func; + c_func2 *c_func2; + c_funcv *c_funcv; + } c_u; + int c_iscloneop; + struct cmd *c_next; +}; +void cmd_register(struct cmd *); + +typedef void callback_func(int s, void *); +void callback_register(callback_func *, void *); + +/* + * Macros for declaring command functions and initializing entries. + */ +#define DECL_CMD_FUNC(name, cmd, arg) \ + void name(const char *cmd, int arg, int s, const struct afswtch *afp) +#define DECL_CMD_FUNC2(name, arg1, arg2) \ + void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp) + +#define DEF_CMD(name, param, func) { name, param, { .c_func = func } } +#define DEF_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func } } +#define DEF_CMD_OPTARG(name, func) { name, OPTARG, { .c_func = func } } +#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func } } +#define DEF_CMD_VA(name, func) { name, VAARGS, { .c_funcv = func } } +#define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1 } +#define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1 } + +struct ifaddrs; +struct addrinfo; + +enum { + RIDADDR, + ADDR, + MASK, + DSTADDR, +}; + +struct afswtch { + const char *af_name; /* as given on cmd line, e.g. "inet" */ + short af_af; /* AF_* */ + /* + * Status is handled one of two ways; if there is an + * address associated with the interface then the + * associated address family af_status method is invoked + * with the appropriate addressin info. Otherwise, if + * all possible info is to be displayed and af_other_status + * is defined then it is invoked after all address status + * is presented. + */ + void (*af_status)(int, const struct ifaddrs *); + void (*af_other_status)(int); + /* parse address method */ + void (*af_getaddr)(const char *, int); + /* parse prefix method (IPv6) */ + void (*af_getprefix)(const char *, int); + void (*af_postproc)(int s, const struct afswtch *); + u_long af_difaddr; /* set dst if address ioctl */ + u_long af_aifaddr; /* set if address ioctl */ + void *af_ridreq; /* */ + void *af_addreq; /* */ + struct afswtch *af_next; + + /* XXX doesn't fit model */ + void (*af_status_tunnel)(int); + void (*af_settunnel)(int s, struct addrinfo *srcres, + struct addrinfo *dstres); + + void (*af_setrouter)(int, int); + int (*af_routermode)(int, int, char *const *); +}; +void af_register(struct afswtch *); + +struct option { + const char *opt; + const char *opt_usage; + void (*cb)(const char *arg); + struct option *next; +}; +void opt_register(struct option *); + +extern struct ifreq ifr; +extern char name[IFNAMSIZ]; /* name of interface */ +extern int allmedia; +extern int supmedia; +extern int printkeys; +extern int newaddr; +extern int verbose; +extern int all; + +void setifcap(const char *, int value, int s, const struct afswtch *); + +void Perror(const char *cmd); +void printb(const char *s, unsigned value, const char *bits); + +void ifmaybeload(const char *name); + +typedef void clone_callback_func(int, struct ifreq *); +void clone_setcallback(clone_callback_func *); + +/* + * XXX expose this so modules that neeed to know of any pending + * operations on ifmedia can avoid cmd line ordering confusion. + */ +struct ifmediareq *ifmedia_getstate(int s); diff --git a/network_cmds/ifconfig.tproj/iffake.c b/network_cmds/ifconfig.tproj/iffake.c new file mode 100644 index 0000000..c8065a2 --- /dev/null +++ b/network_cmds/ifconfig.tproj/iffake.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * iffake.c + * - manage fake interfaces that pretend to be e.g. ethernet + */ + +/* + * Modification History: + * + * January 17, 2017 Dieter Siegmund (dieter@apple.com) + * - created + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_fake_var.h> + +#include <net/route.h> + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> + +#include "ifconfig.h" + +static void +fake_status(int s) +{ + struct ifdrv ifd; + struct if_fake_request iffr; + + bzero((char *)&ifd, sizeof(ifd)); + bzero((char *)&iffr, sizeof(iffr)); + strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); + ifd.ifd_cmd = IF_FAKE_G_CMD_GET_PEER; + ifd.ifd_len = sizeof(iffr); + ifd.ifd_data = &iffr; + if (ioctl(s, SIOCGDRVSPEC, &ifd) < 0) { + return; + } + if (iffr.iffr_peer_name[0] == '\0') { + printf("\tpeer: <none>\n"); + } else { + printf("\tpeer: %s\n", iffr.iffr_peer_name); + } + return; +} + +static void +set_peer(int s, const char * operation, const char * val) +{ + struct ifdrv ifd; + struct if_fake_request iffr; + + bzero((char *)&ifd, sizeof(ifd)); + bzero((char *)&iffr, sizeof(iffr)); + strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); + ifd.ifd_cmd = IF_FAKE_S_CMD_SET_PEER; + ifd.ifd_len = sizeof(iffr); + ifd.ifd_data = &iffr; + if (val != NULL) { + strlcpy(iffr.iffr_peer_name, val, sizeof(iffr.iffr_peer_name)); + } + if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) { + err(1, "SIOCDRVSPEC %s peer", operation); + } + return; +} + +static +DECL_CMD_FUNC(setpeer, val, d) +{ + set_peer(s, "set", val); + return; +} + +static +DECL_CMD_FUNC(unsetpeer, val, d) +{ + set_peer(s, "unset", NULL); + return; +} + +static struct cmd fake_cmds[] = { + DEF_CLONE_CMD_ARG("peer", setpeer), + DEF_CMD_OPTARG("-peer", unsetpeer), +}; +static struct afswtch af_fake = { + .af_name = "af_fake", + .af_af = AF_UNSPEC, + .af_other_status = fake_status, +}; + +static __constructor void +fake_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(fake_cmds); i++) + cmd_register(&fake_cmds[i]); + af_register(&af_fake); +#undef N +} + diff --git a/network_cmds/ifconfig.tproj/ifmedia.c b/network_cmds/ifconfig.tproj/ifmedia.c new file mode 100644 index 0000000..713c136 --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifmedia.c @@ -0,0 +1,872 @@ +/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ +/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.25.6.1 2008/11/25 02:59:29 kensmith Exp $ */ + +/* + * Copyright (c) 1997 Jason R. Thorpe. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Jason R. Thorpe. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_media.h> +#include <net/route.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ifconfig.h" + +static void domediaopt(const char *, int, int); +static int get_media_subtype(int, const char *); +#ifdef notdef +static int get_media_mode(int, const char *); +#endif +static int get_media_options(int, const char *); +static int lookup_media_word(struct ifmedia_description *, const char *); +static void print_media_word(int, int); +static void print_media_word_ifconfig(int); + +static struct ifmedia_description *get_toptype_desc(int); +static struct ifmedia_type_to_subtype *get_toptype_ttos(int); +static struct ifmedia_description *get_subtype_desc(int, + struct ifmedia_type_to_subtype *ttos); + +static void +media_status(int s) +{ + struct ifmediareq ifmr; + int *media_list, i; + + (void) memset(&ifmr, 0, sizeof(ifmr)); + (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); + + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) { + /* + * Interface doesn't support SIOC{G,S}IFMEDIA. + */ + return; + } + + if (ifmr.ifm_count == 0) { + warnx("%s: no media types?", name); + return; + } + + media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); + if (media_list == NULL) + err(1, "malloc"); + ifmr.ifm_ulist = media_list; + + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) + err(1, "SIOCGIFXMEDIA"); + + printf("\tmedia: "); + print_media_word(ifmr.ifm_current, 1); + if (ifmr.ifm_active != ifmr.ifm_current) { + putchar(' '); + putchar('('); + print_media_word(ifmr.ifm_active, 0); + putchar(')'); + } + + putchar('\n'); + + if (ifmr.ifm_status & IFM_AVALID) { + printf("\tstatus: "); +#ifdef notdef + switch (IFM_TYPE(ifmr.ifm_active)) { + case IFM_ETHER: + case IFM_ATM: + if (ifmr.ifm_status & IFM_ACTIVE) + printf("active"); + else + printf("no carrier"); + break; + + case IFM_FDDI: + case IFM_TOKEN: + if (ifmr.ifm_status & IFM_ACTIVE) + printf("inserted"); + else + printf("no ring"); + break; + + case IFM_IEEE80211: + /* XXX: Different value for adhoc? */ + if (ifmr.ifm_status & IFM_ACTIVE) + printf("associated"); + else + printf("no carrier"); + break; + } +#else + if (ifmr.ifm_status & IFM_ACTIVE) + printf("active"); + else + printf("inactive"); +#endif + putchar('\n'); + } + + if (ifmr.ifm_count > 0 && supmedia) { + printf("\tsupported media:\n"); + for (i = 0; i < ifmr.ifm_count; i++) { + printf("\t\t"); + print_media_word_ifconfig(media_list[i]); + putchar('\n'); + } + } + + free(media_list); +} + +struct ifmediareq * +ifmedia_getstate(int s) +{ + static struct ifmediareq *ifmr = NULL; + int *mwords; + + if (ifmr == NULL) { + ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq)); + if (ifmr == NULL) + err(1, "malloc"); + + (void) memset(ifmr, 0, sizeof(struct ifmediareq)); + (void) strlcpy(ifmr->ifm_name, name, + sizeof(ifmr->ifm_name)); + + ifmr->ifm_count = 0; + ifmr->ifm_ulist = NULL; + + /* + * We must go through the motions of reading all + * supported media because we need to know both + * the current media type and the top-level type. + */ + + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) { + err(1, "SIOCGIFXMEDIA"); + } + + 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, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) + err(1, "SIOCGIFXMEDIA"); + } + + return ifmr; +} + +static void +setifmediacallback(int s, void *arg) +{ + struct ifmediareq *ifmr = (struct ifmediareq *)arg; + static int did_it = 0; + + if (!did_it) { + ifr.ifr_media = ifmr->ifm_current; + if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) + err(1, "SIOCSIFMEDIA (media)"); + free(ifmr->ifm_ulist); + free(ifmr); + did_it = 1; + } +} + +static void +setmedia(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifmediareq *ifmr; + int subtype; + + ifmr = ifmedia_getstate(s); + + /* + * We are primarily concerned with the top-level type. + * However, "current" may be only IFM_NONE, so we just look + * for the top-level type in the first "supported type" + * entry. + * + * (I'm assuming that all supported media types for a given + * interface will be the same top-level type..) + */ + subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val); + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) | + IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; + + if ((ifr.ifr_media & IFM_TMASK) == 0) { + ifr.ifr_media &= ~IFM_GMASK; + } + + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} + +static void +setmediaopt(const char *val, int d, int s, const struct afswtch *afp) +{ + + domediaopt(val, 0, s); +} + +static void +unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) +{ + + domediaopt(val, 1, s); +} + +static void +domediaopt(const char *val, int clear, int s) +{ + struct ifmediareq *ifmr; + int options; + + ifmr = ifmedia_getstate(s); + + options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val); + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = ifmr->ifm_current; + if (clear) + ifr.ifr_media &= ~options; + else { + if (options & IFM_HDX) { + ifr.ifr_media &= ~IFM_FDX; + options &= ~IFM_HDX; + } + ifr.ifr_media |= options; + } + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} + +static void +setmediainst(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifmediareq *ifmr; + int inst; + + ifmr = ifmedia_getstate(s); + + inst = atoi(val); + if (inst < 0 || inst > IFM_INST_MAX) + errx(1, "invalid media instance: %s", val); + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; + + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} + +#ifdef notdef +static void +setmediamode(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifmediareq *ifmr; + int mode; + + ifmr = ifmedia_getstate(s); + + mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val); + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode; + + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} +#endif + +/********************************************************************** + * A good chunk of this is duplicated from sys/net/ifmedia.c + **********************************************************************/ + +static struct ifmedia_description ifm_type_descriptions[] = + IFM_TYPE_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = + IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_ethernet_aliases[] = + IFM_SUBTYPE_ETHERNET_ALIASES; + +static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = + IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = + IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_tokenring_aliases[] = + IFM_SUBTYPE_TOKENRING_ALIASES; + +static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = + IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_fddi_descriptions[] = + IFM_SUBTYPE_FDDI_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_fddi_aliases[] = + IFM_SUBTYPE_FDDI_ALIASES; + +static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = + IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = + IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = + IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; + +#ifdef notdef +static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = +IFM_SUBTYPE_IEEE80211_ALIASES; + +struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = + IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = + IFM_SUBTYPE_IEEE80211_MODE_ALIASES; + +static struct ifmedia_description ifm_subtype_atm_descriptions[] = + IFM_SUBTYPE_ATM_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_atm_aliases[] = + IFM_SUBTYPE_ATM_ALIASES; + +static struct ifmedia_description ifm_subtype_atm_option_descriptions[] = + IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; +#endif + +static struct ifmedia_description ifm_subtype_shared_descriptions[] = + IFM_SUBTYPE_SHARED_DESCRIPTIONS; + +static struct ifmedia_description ifm_subtype_shared_aliases[] = + IFM_SUBTYPE_SHARED_ALIASES; + +static struct ifmedia_description ifm_shared_option_descriptions[] = + IFM_SHARED_OPTION_DESCRIPTIONS; + +struct ifmedia_type_to_subtype { + struct { + struct ifmedia_description *desc; + int alias; + } subtypes[5]; + struct { + struct ifmedia_description *desc; + int alias; + } options[3]; + struct { + struct ifmedia_description *desc; + int alias; + } modes[3]; +}; + +/* must be in the same order as IFM_TYPE_DESCRIPTIONS */ +static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { + { + { + { &ifm_subtype_shared_descriptions[0], 0 }, + { &ifm_subtype_shared_aliases[0], 1 }, + { &ifm_subtype_ethernet_descriptions[0], 0 }, + { &ifm_subtype_ethernet_aliases[0], 1 }, + { NULL, 0 }, + }, + { + { &ifm_shared_option_descriptions[0], 0 }, + { &ifm_subtype_ethernet_option_descriptions[0], 0 }, + { NULL, 0 }, + }, + { + { NULL, 0 }, + }, + }, + { + { + { &ifm_subtype_shared_descriptions[0], 0 }, + { &ifm_subtype_shared_aliases[0], 1 }, + { &ifm_subtype_tokenring_descriptions[0], 0 }, + { &ifm_subtype_tokenring_aliases[0], 1 }, + { NULL, 0 }, + }, + { + { &ifm_shared_option_descriptions[0], 0 }, + { &ifm_subtype_tokenring_option_descriptions[0], 0 }, + { NULL, 0 }, + }, + { + { NULL, 0 }, + }, + }, + { + { + { &ifm_subtype_shared_descriptions[0], 0 }, + { &ifm_subtype_shared_aliases[0], 1 }, + { &ifm_subtype_fddi_descriptions[0], 0 }, + { &ifm_subtype_fddi_aliases[0], 1 }, + { NULL, 0 }, + }, + { + { &ifm_shared_option_descriptions[0], 0 }, + { &ifm_subtype_fddi_option_descriptions[0], 0 }, + { NULL, 0 }, + }, + { + { NULL, 0 }, + }, + }, +#ifdef __APPLE__ + { + { + { &ifm_subtype_shared_descriptions[0], 0 }, + { &ifm_subtype_shared_aliases[0], 1 }, + { &ifm_subtype_ieee80211_descriptions[0], 0 }, + { NULL, 0 }, + }, + { + { &ifm_shared_option_descriptions[0], 0 }, + { &ifm_subtype_ieee80211_option_descriptions[0], 1 }, + { NULL, 0 }, + }, + { + { NULL, 0 }, + }, + }, +#else /* __APPLE__ */ +#ifdef notdef + { + { + { &ifm_subtype_shared_descriptions[0], 0 }, + { &ifm_subtype_shared_aliases[0], 1 }, + { &ifm_subtype_ieee80211_descriptions[0], 0 }, + { &ifm_subtype_ieee80211_aliases[0], 1 }, + { NULL, 0 }, + }, + { + { &ifm_shared_option_descriptions[0], 0 }, + { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, + { NULL, 0 }, + }, + { + { &ifm_subtype_ieee80211_mode_descriptions[0], 0 }, + { &ifm_subtype_ieee80211_mode_aliases[0], 0 }, + { NULL, 0 }, + }, + }, + { + { + { &ifm_subtype_shared_descriptions[0], 0 }, + { &ifm_subtype_shared_aliases[0], 1 }, + { &ifm_subtype_atm_descriptions[0], 0 }, + { &ifm_subtype_atm_aliases[0], 1 }, + { NULL, 0 }, + }, + { + { &ifm_shared_option_descriptions[0], 0 }, + { &ifm_subtype_atm_option_descriptions[0], 0 }, + { NULL, 0 }, + }, + { + { NULL, 0 }, + }, + }, +#endif +#endif /* __APPLE__ */ +}; + +static int +get_media_subtype(int type, const char *val) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + int rval, i; + + /* Find the top-level interface type. */ + for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; + desc->ifmt_string != NULL; desc++, ttos++) + if (type == desc->ifmt_word) + break; + if (desc->ifmt_string == NULL) + errx(1, "unknown media type 0x%x", type); + + for (i = 0; ttos->subtypes[i].desc != NULL; i++) { + rval = lookup_media_word(ttos->subtypes[i].desc, val); + if (rval != -1) + return (rval); + } + errx(1, "unknown media subtype: %s", val); + /*NOTREACHED*/ +} + +#ifdef notdef +static int +get_media_mode(int type, const char *val) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + int rval, i; + + /* Find the top-level interface type. */ + for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; + desc->ifmt_string != NULL; desc++, ttos++) + if (type == desc->ifmt_word) + break; + if (desc->ifmt_string == NULL) + errx(1, "unknown media mode 0x%x", type); + + for (i = 0; ttos->modes[i].desc != NULL; i++) { + rval = lookup_media_word(ttos->modes[i].desc, val); + if (rval != -1) + return (rval); + } + return -1; +} +#endif + +static int +get_media_options(int type, const char *val) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + char *optlist, *optptr; + int option = 0, i, rval = 0; + + /* We muck with the string, so copy it. */ + optlist = strdup(val); + if (optlist == NULL) + err(1, "strdup"); + + /* Find the top-level interface type. */ + for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; + desc->ifmt_string != NULL; desc++, ttos++) + if (type == desc->ifmt_word) + break; + if (desc->ifmt_string == NULL) + errx(1, "unknown media type 0x%x", type); + + /* + * Look up the options in the user-provided comma-separated + * list. + */ + optptr = optlist; + for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) { + for (i = 0; ttos->options[i].desc != NULL; i++) { + option = lookup_media_word(ttos->options[i].desc, optptr); + if (option != -1) + break; + } + if (option == 0) + errx(1, "unknown option: %s", optptr); + rval |= option; + } + + free(optlist); + return (rval); +} + +static int +lookup_media_word(struct ifmedia_description *desc, const char *val) +{ + + for (; desc->ifmt_string != NULL; desc++) + if (strcasecmp(desc->ifmt_string, val) == 0) + return (desc->ifmt_word); + + return (-1); +} + +static struct ifmedia_description *get_toptype_desc(int ifmw) +{ + struct ifmedia_description *desc; + + for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) + if (IFM_TYPE(ifmw) == desc->ifmt_word) + break; + + return desc; +} + +static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + + for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; + desc->ifmt_string != NULL; desc++, ttos++) + if (IFM_TYPE(ifmw) == desc->ifmt_word) + break; + + return ttos; +} + +static struct ifmedia_description *get_subtype_desc(int ifmw, + struct ifmedia_type_to_subtype *ttos) +{ + int i; + struct ifmedia_description *desc; + + for (i = 0; ttos->subtypes[i].desc != NULL; i++) { + if (ttos->subtypes[i].alias) + continue; + for (desc = ttos->subtypes[i].desc; + desc->ifmt_string != NULL; desc++) { + if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) + return desc; + } + } + + return NULL; +} + +#ifdef notdef +static struct ifmedia_description *get_mode_desc(int ifmw, + struct ifmedia_type_to_subtype *ttos) +{ + int i; + struct ifmedia_description *desc; + + for (i = 0; ttos->modes[i].desc != NULL; i++) { + if (ttos->modes[i].alias) + continue; + for (desc = ttos->modes[i].desc; + desc->ifmt_string != NULL; desc++) { + if (IFM_MODE(ifmw) == desc->ifmt_word) + return desc; + } + } + + return NULL; +} +#endif + +static void +print_media_word(int ifmw, int print_toptype) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + int seen_option = 0, i; + + /* Find the top-level interface type. */ + desc = get_toptype_desc(ifmw); + ttos = get_toptype_ttos(ifmw); + if (desc->ifmt_string == NULL) { + printf("<unknown type>"); + return; +#ifdef notdef + } else if (print_toptype) { + printf("%s", desc->ifmt_string); +#endif + } + + /* + * Don't print the top-level type; it's not like we can + * change it, or anything. + */ + + /* Find subtype. */ + desc = get_subtype_desc(ifmw, ttos); + if (desc == NULL) { + printf("<unknown subtype>"); + return; + } + +#ifdef notdef + if (print_toptype) + putchar(' '); +#endif + + printf("%s", desc->ifmt_string); + +#ifdef notdef + if (print_toptype) { + desc = get_mode_desc(ifmw, ttos); + if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string)) + printf(" mode %s", desc->ifmt_string); + } +#endif + /* Find options. */ + for (i = 0; ttos->options[i].desc != NULL; i++) { + if (ttos->options[i].alias) + continue; + for (desc = ttos->options[i].desc; + desc->ifmt_string != NULL; desc++) { + if (ifmw & desc->ifmt_word) { + if (seen_option == 0) + printf(" <"); + printf("%s%s", seen_option++ ? "," : "", + desc->ifmt_string); + } + } + } + printf("%s", seen_option ? ">" : ""); + +#ifdef notdef + if (print_toptype && IFM_INST(ifmw) != 0) + printf(" instance %d", IFM_INST(ifmw)); +#endif +} + +static void +print_media_word_ifconfig(int ifmw) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + int i; + + /* Find the top-level interface type. */ + desc = get_toptype_desc(ifmw); + ttos = get_toptype_ttos(ifmw); + if (desc->ifmt_string == NULL) { + printf("<unknown type>"); + return; + } + + /* + * Don't print the top-level type; it's not like we can + * change it, or anything. + */ + + /* Find subtype. */ + desc = get_subtype_desc(ifmw, ttos); + if (desc == NULL) { + printf("<unknown subtype>"); + return; + } + + printf("media %s", desc->ifmt_string); + +#ifdef notdef + desc = get_mode_desc(ifmw, ttos); + if (desc != NULL) + printf(" mode %s", desc->ifmt_string); +#endif + + /* Find options. */ + for (i = 0; ttos->options[i].desc != NULL; i++) { + if (ttos->options[i].alias) + continue; + for (desc = ttos->options[i].desc; + desc->ifmt_string != NULL; desc++) { + if (ifmw & desc->ifmt_word) { + printf(" mediaopt %s", desc->ifmt_string); + } + } + } + + if (IFM_INST(ifmw) != 0) + printf(" instance %d", IFM_INST(ifmw)); +} + +/********************************************************************** + * ...until here. + **********************************************************************/ + +static struct cmd media_cmds[] = { + DEF_CMD_ARG("media", setmedia), +#ifdef notdef + DEF_CMD_ARG("mode", setmediamode), +#endif + DEF_CMD_ARG("mediaopt", setmediaopt), + DEF_CMD_ARG("-mediaopt",unsetmediaopt), + DEF_CMD_ARG("inst", setmediainst), + DEF_CMD_ARG("instance", setmediainst), +}; +static struct afswtch af_media = { + .af_name = "af_media", + .af_af = AF_UNSPEC, + .af_other_status = media_status, +}; + +static __constructor void +ifmedia_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(media_cmds); i++) + cmd_register(&media_cmds[i]); + af_register(&af_media); +#undef N +} diff --git a/network_cmds/ifconfig.tproj/ifvlan.c b/network_cmds/ifconfig.tproj/ifvlan.c new file mode 100644 index 0000000..9ec0a0a --- /dev/null +++ b/network_cmds/ifconfig.tproj/ifvlan.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_vlan_var.h> +#include <net/route.h> + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> + +#include "ifconfig.h" + +#include <sys/cdefs.h> + +#define NOTAG ((u_short) -1) + +static struct vlanreq params = { + .vlr_tag = NOTAG, +}; + +static int +getvlan(int s, struct ifreq *ifr, struct vlanreq *vreq) +{ + bzero((char *)vreq, sizeof(*vreq)); + ifr->ifr_data = (caddr_t)vreq; + + return ioctl(s, SIOCGETVLAN, (caddr_t)ifr); +} + +static void +vlan_status(int s) +{ + struct vlanreq vreq; + + if (getvlan(s, &ifr, &vreq) != -1) + printf("\tvlan: %d parent interface: %s\n", + vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ? + "<none>" : vreq.vlr_parent); +} + +static void +vlan_create(int s, struct ifreq *ifr) +{ + if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') { + /* + * One or both parameters were specified, make sure both. + */ + if (params.vlr_tag == NOTAG) + errx(1, "must specify a tag for vlan create"); + if (params.vlr_parent[0] == '\0') + errx(1, "must specify a parent device for vlan create"); + ifr->ifr_data = (caddr_t) ¶ms; + } +#ifdef SIOCIFCREATE2 + if (ioctl(s, SIOCIFCREATE2, ifr) < 0) + err(1, "SIOCIFCREATE2"); +#else + if (ioctl(s, SIOCIFCREATE, ifr) < 0) + err(1, "SIOCIFCREATE"); +#endif +} + +static void +vlan_cb(int s, void *arg) +{ + if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0')) + errx(1, "both vlan and vlandev must be specified"); +} + +static void +vlan_set(int s, struct ifreq *ifr) +{ + if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') { + ifr->ifr_data = (caddr_t) ¶ms; + if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1) + err(1, "SIOCSETVLAN"); + } +} + +static +DECL_CMD_FUNC(setvlantag, val, d) +{ + struct vlanreq vreq; + u_long ul; + char *endp; + + ul = strtoul(val, &endp, 0); + if (*endp != '\0') + errx(1, "invalid value for vlan"); + params.vlr_tag = ul; + /* check if the value can be represented in vlr_tag */ + if (params.vlr_tag != ul) + errx(1, "value for vlan out of range"); + + if (getvlan(s, &ifr, &vreq) != -1) + vlan_set(s, &ifr); + else + clone_setcallback(vlan_create); +} + +static +DECL_CMD_FUNC(setvlandev, val, d) +{ + struct vlanreq vreq; + + strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent)); + + if (getvlan(s, &ifr, &vreq) != -1) + vlan_set(s, &ifr); + else + clone_setcallback(vlan_create); +} + +static +DECL_CMD_FUNC(unsetvlandev, val, d) +{ + struct vlanreq vreq; + + bzero((char *)&vreq, sizeof(struct vlanreq)); + ifr.ifr_data = (caddr_t)&vreq; + + if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCGETVLAN"); + + bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent)); + vreq.vlr_tag = 0; + + if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCSETVLAN"); +} + +static struct cmd vlan_cmds[] = { + DEF_CLONE_CMD_ARG("vlan", setvlantag), + DEF_CLONE_CMD_ARG("vlandev", setvlandev), + /* XXX For compatibility. Should become DEF_CMD() some day. */ + DEF_CMD_OPTARG("-vlandev", unsetvlandev), +#ifdef IFCAP_VLAN_MTU + DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap), + DEF_CMD("-vlanmtu", -IFCAP_VLAN_MTU, setifcap), +#endif /* IFCAP_VLAN_MTU */ +#ifdef IFCAP_VLAN_HWTAGGING + DEF_CMD("vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap), + DEF_CMD("-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap), +#endif /* IFCAP_VLAN_HWTAGGING */ +}; +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/network_cmds/ifconfig.tproj/nexus.c b/network_cmds/ifconfig.tproj/nexus.c new file mode 100644 index 0000000..3df9842 --- /dev/null +++ b/network_cmds/ifconfig.tproj/nexus.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * nexus.c + * - report information about attached nexus + */ + +/* + * Modification History: + * + * April 10, 2017 Dieter Siegmund (dieter@apple.com) + * - created + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_fake_var.h> + +#include <net/route.h> + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> + +#include "ifconfig.h" + +static void +nexus_status(int s) +{ + struct if_nexusreq ifnr; + uuid_string_t flowswitch; + uuid_string_t netif; + + if (!verbose) { + return; + } + bzero((char *)&ifnr, sizeof(ifnr)); + strlcpy(ifnr.ifnr_name, ifr.ifr_name, sizeof(ifnr.ifnr_name)); + if (ioctl(s, SIOCGIFNEXUS, &ifnr) < 0) { + return; + } + if (uuid_is_null(ifnr.ifnr_netif)) { + /* technically, this shouldn't happen */ + return; + } + uuid_unparse_upper(ifnr.ifnr_netif, netif); + printf("\tnetif: %s\n", netif); + if (uuid_is_null(ifnr.ifnr_flowswitch) == 0) { + uuid_unparse_upper(ifnr.ifnr_flowswitch, flowswitch); + printf("\tflowswitch: %s\n", flowswitch); + } + return; +} + +static struct afswtch af_fake = { + .af_name = "af_fake", + .af_af = AF_UNSPEC, + .af_other_status = nexus_status, +}; + +static __constructor void +fake_ctor(void) +{ + af_register(&af_fake); +} + |