diff options
Diffstat (limited to 'sbin/ifconfig/ifconfig.c')
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 1203 |
1 files changed, 734 insertions, 469 deletions
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index ec8a3fd52803..2cbe7a881bd0 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -29,19 +29,11 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char copyright[] = -"@(#) Copyright (c) 1983, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#if 0 -static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; -#endif -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - #include <sys/param.h> #include <sys/ioctl.h> +#ifdef JAIL +#include <sys/jail.h> +#endif #include <sys/module.h> #include <sys/linker.h> #include <sys/nv.h> @@ -52,6 +44,7 @@ static const char rcsid[] = #include <net/ethernet.h> #include <net/if.h> #include <net/if_dl.h> +#include <net/if_strings.h> #include <net/if_types.h> #include <net/route.h> @@ -82,48 +75,34 @@ static const char rcsid[] = ifconfig_handle_t *lifh; -/* - * Since "struct ifreq" is composed of various union members, callers - * should pay special attention to interpret the value. - * (.e.g. little/big endian difference in the structure.) - */ -struct ifreq ifr; - -char name[IFNAMSIZ]; -char *descr = NULL; -size_t descrlen = 64; -int setaddr; -int setmask; -int doalias; -int clearaddr; -int newaddr = 1; -int verbose; -int noload; -int printifname = 0; - -int supmedia = 0; -int printkeys = 0; /* Print keying material for interfaces. */ +#ifdef WITHOUT_NETLINK +static char *descr = NULL; +static size_t descrlen = 64; +#endif +static int setaddr; +static int setmask; +static int doalias; +static int clearaddr; +static int newaddr = 1; + int exit_code = 0; +static char ifname_to_print[IFNAMSIZ]; /* Helper for printifnamemaybe() */ + /* Formatter Strings */ char *f_inet, *f_inet6, *f_ether, *f_addr; -static bool group_member(const char *ifname, const char *match, - const char *nomatch); -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, +#ifdef WITHOUT_NETLINK +static void list_interfaces_ioctl(if_ctx *ctx); +static void status(if_ctx *ctx, const struct sockaddr_dl *sdl, struct ifaddrs *ifa); -static void tunnel_status(int s); +#endif static _Noreturn void usage(void); +static void Perrorc(const char *cmd, int error); static int getifflags(const char *ifname, int us, bool err_ok); static struct afswtch *af_getbyname(const char *name); -static struct afswtch *af_getbyfamily(int af); -static void af_other_status(int); - -void printifnamemaybe(void); static struct option *opts = NULL; @@ -190,29 +169,59 @@ usage(void) } fprintf(stderr, - "usage: ifconfig [-f type:format] %sinterface address_family\n" + "usage: ifconfig [-j jail] [-f type:format] %sinterface address_family\n" " [address [dest_address]] [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", + " ifconfig [-j jail] interface create\n" + " ifconfig [-j jail] -a %s[-d] [-m] [-u] [-v] [address_family]\n" + " ifconfig [-j jail] -l [-d] [-u] [address_family]\n" + " ifconfig [-j jail] %s[-d] [-m] [-u] [-v]\n", options, options, options); exit(1); } +static void +ifname_update(if_ctx *ctx, const char *name) +{ + strlcpy(ctx->_ifname_storage_ioctl, name, sizeof(ctx->_ifname_storage_ioctl)); + ctx->ifname = ctx->_ifname_storage_ioctl; + + strlcpy(ifname_to_print, name, sizeof(ifname_to_print)); +} + +static void +ifr_set_name(struct ifreq *ifr, const char *name) +{ + strlcpy(ifr->ifr_name, name, sizeof(ifr->ifr_name)); +} + +int +ioctl_ctx_ifr(if_ctx *ctx, unsigned long cmd, struct ifreq *ifr) +{ + ifr_set_name(ifr, ctx->ifname); + return (ioctl_ctx(ctx, cmd, ifr)); +} + void -ioctl_ifcreate(int s, struct ifreq *ifr) +ifcreate_ioctl(if_ctx *ctx, struct ifreq *ifr) { - if (ioctl(s, SIOCIFCREATE2, ifr) < 0) { + char ifname_orig[IFNAMSIZ]; + + strlcpy(ifname_orig, ifr->ifr_name, sizeof(ifname_orig)); + + if (ioctl(ctx->io_s, SIOCIFCREATE2, ifr) < 0) { switch (errno) { case EEXIST: errx(1, "interface %s already exists", ifr->ifr_name); default: - err(1, "SIOCIFCREATE2"); + err(1, "SIOCIFCREATE2 (%s)", ifr->ifr_name); } } + + if (strncmp(ifname_orig, ifr->ifr_name, sizeof(ifname_orig)) != 0) + ifname_update(ctx, ifr->ifr_name); } +#ifdef WITHOUT_NETLINK static int calcorders(struct ifaddrs *ifa, struct ifa_queue *q) { @@ -299,6 +308,7 @@ cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q) return (0); } +#endif static void freeformat(void) { @@ -342,6 +352,7 @@ static void setformat(char *input) free(formatstr); } +#ifdef WITHOUT_NETLINK static struct ifaddrs * sortifaddrs(struct ifaddrs *list, int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *), @@ -396,59 +407,68 @@ sortifaddrs(struct ifaddrs *list, return (result); } +#endif -void printifnamemaybe() +static void +printifnamemaybe(void) { - if (printifname) - printf("%s\n", name); + if (ifname_to_print[0] != '\0') + printf("%s\n", ifname_to_print); } -int -main(int argc, char *argv[]) +static void +list_interfaces(if_ctx *ctx) { - int c, all, namesonly, downonly, uponly; - const struct afswtch *afp = NULL; - int ifindex; - struct ifaddrs *ifap, *sifap, *ifa; - struct ifreq paifr; - const struct sockaddr_dl *sdl; - char options[1024], *cp, *envformat, *namecp = NULL; - struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); - struct ifa_order_elt *cur, *tmp; - const char *ifname, *matchgroup, *nogroup; - struct option *p; - size_t iflen; - int flags; +#ifdef WITHOUT_NETLINK + list_interfaces_ioctl(ctx); +#else + list_interfaces_nl(ctx->args); +#endif +} - all = downonly = uponly = namesonly = noload = verbose = 0; - f_inet = f_inet6 = f_ether = f_addr = NULL; - matchgroup = nogroup = NULL; +static char * +args_peek(struct ifconfig_args *args) +{ + if (args->argc > 0) + return (args->argv[0]); + return (NULL); +} - lifh = ifconfig_open(); - if (lifh == NULL) - err(EXIT_FAILURE, "ifconfig_open"); +static char * +args_pop(struct ifconfig_args *args) +{ + if (args->argc == 0) + return (NULL); - envformat = getenv("IFCONFIG_FORMAT"); - if (envformat != NULL) - setformat(envformat); + char *arg = args->argv[0]; - /* - * Ensure we print interface name when expected to, - * even if we terminate early due to error. - */ - atexit(printifnamemaybe); + args->argc--; + args->argv++; + + return (arg); +} + +static void +args_parse(struct ifconfig_args *args, int argc, char *argv[]) +{ + char options[1024]; + struct option *p; + int c; /* Parse leading line options */ - strlcpy(options, "G:adf:klmnuv", sizeof(options)); + strlcpy(options, "G:adDf:j:klmnuv", sizeof(options)); for (p = opts; p != NULL; p = p->next) strlcat(options, p->opt, sizeof(options)); while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'a': /* scan all interfaces */ - all++; + args->all = true; break; case 'd': /* restrict scan to "down" interfaces */ - downonly++; + args->downonly = true; + break; + case 'D': /* Print driver name */ + args->drivername = true; break; case 'f': if (optarg == NULL) @@ -456,33 +476,42 @@ main(int argc, char *argv[]) setformat(optarg); break; case 'G': - if (optarg == NULL || all == 0) + if (optarg == NULL || args->all == 0) usage(); - nogroup = optarg; + args->nogroup = optarg; + break; + case 'j': +#ifdef JAIL + if (optarg == NULL) + usage(); + args->jail_name = optarg; +#else + Perror("not built with jail support"); +#endif break; case 'k': - printkeys++; + args->printkeys = true; break; case 'l': /* scan interface names only */ - namesonly++; + args->namesonly = true; break; case 'm': /* show media choices in status */ - supmedia = 1; + args->supmedia = true; break; case 'n': /* suppress module loading */ - noload++; + args->noload = true; break; case 'u': /* restrict scan to "up" interfaces */ - uponly++; + args->uponly = true; break; case 'v': - verbose++; + args->verbose++; break; case 'g': - if (all) { + if (args->all) { if (optarg == NULL) usage(); - matchgroup = optarg; + args->matchgroup = optarg; break; } /* FALLTHROUGH */ @@ -501,26 +530,25 @@ main(int argc, char *argv[]) argv += optind; /* -l cannot be used with -a or -m */ - if (namesonly && (all || supmedia)) + if (args->namesonly && (args->all || args->supmedia)) usage(); /* nonsense.. */ - if (uponly && downonly) + if (args->uponly && args->downonly) usage(); /* no arguments is equivalent to '-a' */ - if (!namesonly && argc < 1) - all = 1; + if (!args->namesonly && argc < 1) + args->all = 1; /* -a and -l allow an address family arg to limit the output */ - if (all || namesonly) { + if (args->all || args->namesonly) { if (argc > 1) usage(); - ifname = NULL; - ifindex = 0; if (argc == 1) { - afp = af_getbyname(*argv); + const struct afswtch *afp = af_getbyname(*argv); + if (afp == NULL) { warnx("Address family '%s' unknown.", *argv); usage(); @@ -528,32 +556,110 @@ main(int argc, char *argv[]) if (afp->af_name != NULL) argc--, argv++; /* leave with afp non-zero */ + args->afp = afp; } } else { /* not listing, need an argument */ if (argc < 1) usage(); + } - ifname = *argv; - argc--, argv++; + args->argc = argc; + args->argv = argv; +} + +static int +ifconfig(if_ctx *ctx, int iscreate, const struct afswtch *uafp) +{ +#ifdef WITHOUT_NETLINK + return (ifconfig_ioctl(ctx, iscreate, uafp)); +#else + return (ifconfig_nl(ctx, iscreate, uafp)); +#endif +} + +static bool +isargcreate(const char *arg) +{ + if (arg == NULL) + return (false); + + if (strcmp(arg, "create") == 0 || strcmp(arg, "plumb") == 0) + return (true); + + return (false); +} + +static bool +isnametoolong(const char *ifname) +{ + return (strlen(ifname) >= IFNAMSIZ); +} + +int +main(int ac, char *av[]) +{ + char *envformat; + int flags; +#ifdef JAIL + int jid; +#endif + struct ifconfig_args _args = {}; + struct ifconfig_args *args = &_args; + + struct ifconfig_context ctx = { + .args = args, + .io_s = -1, + }; + + f_inet = f_inet6 = f_ether = f_addr = NULL; + + lifh = ifconfig_open(); + if (lifh == NULL) + err(EXIT_FAILURE, "ifconfig_open"); + + envformat = getenv("IFCONFIG_FORMAT"); + if (envformat != NULL) + setformat(envformat); + + /* + * Ensure we print interface name when expected to, + * even if we terminate early due to error. + */ + atexit(printifnamemaybe); + + args_parse(args, ac, av); + +#ifdef JAIL + if (args->jail_name) { + jid = jail_getid(args->jail_name); + if (jid == -1) + Perror("jail not found"); + if (jail_attach(jid) != 0) + Perror("cannot attach to jail"); + } +#endif + + if (!args->all && !args->namesonly) { + /* not listing, need an argument */ + args->ifname = args_pop(args); + ctx.ifname = args->ifname; /* check and maybe load support for this interface */ - ifmaybeload(ifname); + ifmaybeload(args, args->ifname); - ifindex = if_nametoindex(ifname); - if (ifindex == 0) { + char *arg = args_peek(args); + if (if_nametoindex(args->ifname) == 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)) + if (isargcreate(arg)) { + if (isnametoolong(args->ifname)) errx(1, "%s: cloning name too long", - ifname); - ifconfig(argc, argv, 1, NULL); + args->ifname); + ifconfig(&ctx, 1, NULL); exit(exit_code); } #ifdef JAIL @@ -562,36 +668,34 @@ main(int argc, char *argv[]) * right here as we would otherwise fail when trying * to find the interface as it lives in another vnet. */ - if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) { - iflen = strlcpy(name, ifname, sizeof(name)); - if (iflen >= sizeof(name)) + if (arg != NULL && (strcmp(arg, "-vnet") == 0)) { + if (isnametoolong(args->ifname)) errx(1, "%s: interface name too long", - ifname); - ifconfig(argc, argv, 0, NULL); + args->ifname); + ifconfig(&ctx, 0, NULL); exit(exit_code); } #endif - errx(1, "interface %s does not exist", ifname); + errx(1, "interface %s does not exist", args->ifname); } else { /* * Do not allow use `create` command as hostname if * address family is not specified. */ - if (argc > 0 && (strcmp(argv[0], "create") == 0 || - strcmp(argv[0], "plumb") == 0)) { - if (argc == 1) + if (isargcreate(arg)) { + if (args->argc == 1) errx(1, "interface %s already exists", - ifname); - argc--, argv++; + args->ifname); + args_pop(args); } } } /* Check for address family */ - if (argc > 0) { - afp = af_getbyname(*argv); - if (afp != NULL) - argc--, argv++; + if (args->argc > 0) { + args->afp = af_getbyname(args_peek(args)); + if (args->afp != NULL) + args_pop(args); } /* @@ -599,24 +703,84 @@ main(int argc, char *argv[]) * which doesn't require building, sorting, and searching the entire * system address list */ - if ((argc > 0) && (ifname != NULL)) { - iflen = strlcpy(name, ifname, sizeof(name)); - if (iflen >= sizeof(name)) { - warnx("%s: interface name too long, skipping", ifname); - } else { - flags = getifflags(name, -1, false); + if ((args->argc > 0) && (args->ifname != NULL)) { + if (isnametoolong(args->ifname)) + warnx("%s: interface name too long, skipping", args->ifname); + else { + flags = getifflags(args->ifname, -1, false); if (!(((flags & IFF_CANTCONFIG) != 0) || - (downonly && (flags & IFF_UP) != 0) || - (uponly && (flags & IFF_UP) == 0))) - ifconfig(argc, argv, 0, afp); + (args->downonly && (flags & IFF_UP) != 0) || + (args->uponly && (flags & IFF_UP) == 0))) + ifconfig(&ctx, 0, args->afp); } goto done; } + args->allfamilies = args->afp == NULL; + + list_interfaces(&ctx); + +done: + freeformat(); + ifconfig_close(lifh); + exit(exit_code); +} + +bool +match_ether(const struct sockaddr_dl *sdl) +{ + switch (sdl->sdl_type) { + case IFT_ETHER: + case IFT_L2VLAN: + case IFT_BRIDGE: + if (sdl->sdl_alen == ETHER_ADDR_LEN) + return (true); + default: + return (false); + } +} + +bool +match_if_flags(struct ifconfig_args *args, int if_flags) +{ + if ((if_flags & IFF_CANTCONFIG) != 0) + return (false); + if (args->downonly && (if_flags & IFF_UP) != 0) + return (false); + if (args->uponly && (if_flags & IFF_UP) == 0) + return (false); + return (true); +} + +#ifdef WITHOUT_NETLINK +static bool +match_afp(const struct afswtch *afp, int sa_family, const struct sockaddr_dl *sdl) +{ + if (afp == NULL) + return (true); + /* special case for "ether" address family */ + if (!strcmp(afp->af_name, "ether")) { + if (sdl == NULL || !match_ether(sdl)) + return (false); + return (true); + } + return (afp->af_af == sa_family); +} + +static void +list_interfaces_ioctl(if_ctx *ctx) +{ + struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); + struct ifaddrs *ifap, *sifap, *ifa; + struct ifa_order_elt *cur, *tmp; + char *namecp = NULL; + int ifindex; + struct ifconfig_args *args = ctx->args; + if (getifaddrs(&ifap) != 0) err(EXIT_FAILURE, "getifaddrs"); - cp = NULL; + char *cp = NULL; if (calcorders(ifap, &q) != 0) err(EXIT_FAILURE, "calcorders"); @@ -628,95 +792,76 @@ main(int argc, char *argv[]) ifindex = 0; for (ifa = sifap; ifa; ifa = ifa->ifa_next) { - memset(&paifr, 0, sizeof(paifr)); + struct ifreq paifr = {}; + const struct sockaddr_dl *sdl; + 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) + if (args->ifname != NULL && strcmp(args->ifname, ifa->ifa_name) != 0) continue; if (ifa->ifa_addr->sa_family == AF_LINK) - sdl = (const struct sockaddr_dl *) ifa->ifa_addr; + sdl = satosdl_c(ifa->ifa_addr); else sdl = NULL; - if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !namesonly) + if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !args->namesonly) continue; - iflen = strlcpy(name, ifa->ifa_name, sizeof(name)); - if (iflen >= sizeof(name)) { + if (isnametoolong(ifa->ifa_name)) { warnx("%s: interface name too long, skipping", ifa->ifa_name); continue; } cp = ifa->ifa_name; - if ((ifa->ifa_flags & IFF_CANTCONFIG) != 0) + if (!match_if_flags(args, ifa->ifa_flags)) continue; - if (downonly && (ifa->ifa_flags & IFF_UP) != 0) - continue; - if (uponly && (ifa->ifa_flags & IFF_UP) == 0) - continue; - if (!group_member(ifa->ifa_name, matchgroup, nogroup)) + if (!group_member(ifa->ifa_name, args->matchgroup, args->nogroup)) continue; + ctx->ifname = cp; /* * Are we just listing the interfaces? */ - if (namesonly) { + if (args->namesonly) { if (namecp == cp) continue; - if (afp != NULL) { - /* special case for "ether" address family */ - if (!strcmp(afp->af_name, "ether")) { - if (sdl == NULL || - (sdl->sdl_type != IFT_ETHER && - sdl->sdl_type != IFT_L2VLAN && - sdl->sdl_type != IFT_BRIDGE) || - sdl->sdl_alen != ETHER_ADDR_LEN) - continue; - } else { - if (ifa->ifa_addr->sa_family - != afp->af_af) - continue; - } - } + if (!match_afp(args->afp, ifa->ifa_addr->sa_family, sdl)) + continue; namecp = cp; ifindex++; if (ifindex > 1) printf(" "); - fputs(name, stdout); + fputs(cp, stdout); continue; } ifindex++; - if (argc > 0) - ifconfig(argc, argv, 0, afp); + if (args->argc > 0) + ifconfig(ctx, 0, args->afp); else - status(afp, sdl, ifa); + status(ctx, sdl, ifa); } - if (namesonly) + if (args->namesonly) printf("\n"); freeifaddrs(ifap); - -done: - freeformat(); - ifconfig_close(lifh); - exit(exit_code); } +#endif /* * Returns true if an interface should be listed because any its groups * matches shell pattern "match" and none of groups matches pattern "nomatch". * If any pattern is NULL, corresponding condition is skipped. */ -static bool +bool group_member(const char *ifname, const char *match, const char *nomatch) { static int sock = -1; struct ifgroupreq ifgr; struct ifg_req *ifg; - int len; + unsigned int len; bool matched, nomatched; /* Sanity checks. */ @@ -757,11 +902,11 @@ group_member(const char *ifname, const char *match, const char *nomatch) matched = false; nomatched = true; for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(*ifg); ifg++) { - len -= sizeof(struct ifg_req); - if (match) - matched |= !fnmatch(match, ifg->ifgrq_group, 0); - if (nomatch) - nomatched &= fnmatch(nomatch, ifg->ifgrq_group, 0); + len -= sizeof(*ifg); + if (match && !matched) + matched = !fnmatch(match, ifg->ifgrq_group, 0); + if (nomatch && nomatched) + nomatched = fnmatch(nomatch, ifg->ifgrq_group, 0); } free(ifgr.ifgr_groups); @@ -792,7 +937,7 @@ af_getbyname(const char *name) return NULL; } -static struct afswtch * +struct afswtch * af_getbyfamily(int af) { struct afswtch *afp; @@ -803,8 +948,8 @@ af_getbyfamily(int af) return NULL; } -static void -af_other_status(int s) +void +af_other_status(if_ctx *ctx) { struct afswtch *afp; uint8_t afmask[howmany(AF_MAX, NBBY)]; @@ -815,13 +960,13 @@ af_other_status(int s) continue; if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) continue; - afp->af_other_status(s); + afp->af_other_status(ctx); setbit(afmask, afp->af_af); } } static void -af_all_tunnel_status(int s) +af_all_tunnel_status(if_ctx *ctx) { struct afswtch *afp; uint8_t afmask[howmany(AF_MAX, NBBY)]; @@ -832,7 +977,7 @@ af_all_tunnel_status(int s) continue; if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) continue; - afp->af_status_tunnel(s); + afp->af_status_tunnel(ctx); setbit(afmask, afp->af_af); } } @@ -886,22 +1031,80 @@ callback_register(callback_func *func, void *arg) } /* specially-handled commands */ -static void setifaddr(const char *, int, int, const struct afswtch *); +static void setifaddr(if_ctx *ctx, const char *addr, int param); static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); -static void setifdstaddr(const char *, int, int, const struct afswtch *); +static void setifdstaddr(if_ctx *ctx, const char *addr, int param __unused); static const struct cmd setifdstaddr_cmd = DEF_CMD("ifdstaddr", 0, setifdstaddr); -static int -ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp) +int +af_exec_ioctl(if_ctx *ctx, unsigned long action, void *data) +{ + struct ifreq *req = (struct ifreq *)data; + + strlcpy(req->ifr_name, ctx->ifname, sizeof(req->ifr_name)); + if (ioctl_ctx(ctx, action, req) == 0) + return (0); + return (errno); +} + +static void +delifaddr(if_ctx *ctx, const struct afswtch *afp) +{ + int error; + + if (afp->af_exec == NULL) { + warnx("interface %s cannot change %s addresses!", + ctx->ifname, afp->af_name); + clearaddr = 0; + return; + } + + error = afp->af_exec(ctx, afp->af_difaddr, afp->af_ridreq); + if (error != 0) { + if (error == EADDRNOTAVAIL && (doalias >= 0)) { + /* means no previous address for interface */ + } else + Perrorc("ioctl (SIOCDIFADDR)", error); + } +} + +static void +addifaddr(if_ctx *ctx, const struct afswtch *afp) +{ + if (afp->af_exec == NULL) { + warnx("interface %s cannot change %s addresses!", + ctx->ifname, afp->af_name); + newaddr = 0; + return; + } + + if (setaddr || setmask) { + int error = afp->af_exec(ctx, afp->af_aifaddr, afp->af_addreq); + if (error != 0) + Perrorc("ioctl (SIOCAIFADDR)", error); + } +} + +int +ifconfig_ioctl(if_ctx *orig_ctx, int iscreate, const struct afswtch *uafp) { const struct afswtch *afp, *nafp; const struct cmd *p; struct callback *cb; int s; - - strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + int argc = orig_ctx->args->argc; + char *const *argv = orig_ctx->args->argv; + struct ifconfig_context _ctx = { + .args = orig_ctx->args, + .io_ss = orig_ctx->io_ss, + .ifname = orig_ctx->ifname, + }; + struct ifconfig_context *ctx = &_ctx; + + struct ifreq ifr = {}; + strlcpy(ifr.ifr_name, ctx->ifname, sizeof ifr.ifr_name); afp = NULL; if (uafp != NULL) afp = uafp; @@ -926,6 +1129,7 @@ ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp) warnx("Please specify an address_family."); usage(); } + top: ifr.ifr_addr.sa_family = afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? @@ -936,6 +1140,9 @@ top: (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); + ctx->io_s = s; + ctx->afp = afp; + while (argc > 0) { p = cmd_lookup(*argv, iscreate); if (iscreate && p == NULL) { @@ -948,7 +1155,7 @@ top: if (cb == NULL) errx(1, "internal error, no callback"); callbacks = cb->cb_next; - cb->cb_func(s, cb->cb_arg); + cb->cb_func(ctx, cb->cb_arg); iscreate = 0; /* * Handle any address family spec that @@ -980,22 +1187,22 @@ top: if (argv[1] == NULL) errx(1, "'%s' requires argument", p->c_name); - p->c_u.c_func(argv[1], 0, s, afp); + p->c_u.c_func(ctx, argv[1], 0); argc--, argv++; } else if (p->c_parameter == OPTARG && p->c_u.c_func) { - p->c_u.c_func(argv[1], 0, s, afp); + p->c_u.c_func(ctx, argv[1], 0); if (argv[1] != NULL) argc--, argv++; } else if (p->c_parameter == NEXTARG2 && p->c_u.c_func2) { if (argc < 3) errx(1, "'%s' requires 2 arguments", p->c_name); - p->c_u.c_func2(argv[1], argv[2], s, afp); + p->c_u.c_func2(ctx, argv[1], argv[2]); argc -= 2, argv += 2; } else if (p->c_parameter == SPARAM && p->c_u.c_func3) { - p->c_u.c_func3(*argv, p->c_sparameter, s, afp); + p->c_u.c_func3(ctx, *argv, p->c_sparameter); } else if (p->c_u.c_func) - p->c_u.c_func(*argv, p->c_parameter, s, afp); + p->c_u.c_func(ctx, *argv, p->c_parameter); argc--, argv++; } @@ -1003,57 +1210,30 @@ top: * Do any post argument processing required by the address family. */ if (afp->af_postproc != NULL) - afp->af_postproc(s, afp, newaddr, getifflags(name, s, true)); + afp->af_postproc(ctx, newaddr, getifflags(ctx->ifname, s, true)); /* * 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); + cb->cb_func(ctx, 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) { - int ret; - strlcpy(((struct ifreq *)afp->af_ridreq)->ifr_name, 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(((struct ifreq *)afp->af_addreq)->ifr_name, name, - sizeof ifr.ifr_name); - if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) - Perror("ioctl (SIOCAIFADDR)"); - } + if (clearaddr) + delifaddr(ctx, afp); + if (newaddr) + addifaddr(ctx, afp); close(s); return(0); } -/*ARGSUSED*/ static void -setifaddr(const char *addr, int param, int s, const struct afswtch *afp) +setifaddr(if_ctx *ctx, const char *addr, int param __unused) { + const struct afswtch *afp = ctx->afp; + if (afp->af_getaddr == NULL) return; /* @@ -1068,8 +1248,9 @@ setifaddr(const char *addr, int param, int s, const struct afswtch *afp) } static void -settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) +settunnel(if_ctx *ctx, const char *src, const char *dst) { + const struct afswtch *afp = ctx->afp; struct addrinfo *srcres, *dstres; int ecode; @@ -1091,55 +1272,52 @@ settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) errx(1, "source and destination address families do not match"); - afp->af_settunnel(s, srcres, dstres); + afp->af_settunnel(ctx, srcres, dstres); freeaddrinfo(srcres); freeaddrinfo(dstres); } -/* ARGSUSED */ static void -deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) +deletetunnel(if_ctx *ctx, const char *vname __unused, int param __unused) { + struct ifreq ifr = {}; - if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) + if (ioctl_ctx_ifr(ctx, SIOCDIFPHYADDR, &ifr) < 0) err(1, "SIOCDIFPHYADDR"); } #ifdef JAIL static void -setifvnet(const char *jname, int dummy __unused, int s, - const struct afswtch *afp) +setifvnet(if_ctx *ctx, const char *jname, int dummy __unused) { - struct ifreq my_ifr; + struct ifreq ifr = {}; - memcpy(&my_ifr, &ifr, sizeof(my_ifr)); - my_ifr.ifr_jid = jail_getid(jname); - if (my_ifr.ifr_jid < 0) + ifr.ifr_jid = jail_getid(jname); + if (ifr.ifr_jid < 0) errx(1, "%s", jail_errmsg); - if (ioctl(s, SIOCSIFVNET, &my_ifr) < 0) + if (ioctl_ctx_ifr(ctx, SIOCSIFVNET, &ifr) < 0) err(1, "SIOCSIFVNET"); } static void -setifrvnet(const char *jname, int dummy __unused, int s, - const struct afswtch *afp) +setifrvnet(if_ctx *ctx, const char *jname, int dummy __unused) { - struct ifreq my_ifr; + struct ifreq ifr = {}; - memcpy(&my_ifr, &ifr, sizeof(my_ifr)); - my_ifr.ifr_jid = jail_getid(jname); - if (my_ifr.ifr_jid < 0) + ifr.ifr_jid = jail_getid(jname); + if (ifr.ifr_jid < 0) errx(1, "%s", jail_errmsg); - if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0) - err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name); + if (ioctl_ctx_ifr(ctx, SIOCSIFRVNET, &ifr) < 0) + err(1, "SIOCSIFRVNET(%d, %s)", ifr.ifr_jid, ifr.ifr_name); } #endif static void -setifnetmask(const char *addr, int dummy __unused, int s, - const struct afswtch *afp) +setifnetmask(if_ctx *ctx, const char *addr, int dummy __unused) { + const struct afswtch *afp = ctx->afp; + if (afp->af_getaddr != NULL) { setmask++; afp->af_getaddr(addr, MASK); @@ -1147,36 +1325,36 @@ setifnetmask(const char *addr, int dummy __unused, int s, } static void -setifbroadaddr(const char *addr, int dummy __unused, int s, - const struct afswtch *afp) +setifbroadaddr(if_ctx *ctx, const char *addr, int dummy __unused) { + const struct afswtch *afp = ctx->afp; + if (afp->af_getaddr != NULL) - afp->af_getaddr(addr, DSTADDR); + afp->af_getaddr(addr, BRDADDR); } 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); +notealias(if_ctx *ctx, const char *addr __unused, int param) +{ + const struct afswtch *afp = ctx->afp; + + if (setaddr && doalias == 0 && param < 0) { + if (afp->af_copyaddr != NULL) + afp->af_copyaddr(ctx, RIDADDR, ADDR); + } 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) +setifdstaddr(if_ctx *ctx, const char *addr, int param __unused) { + const struct afswtch *afp = ctx->afp; + if (afp->af_getaddr != NULL) afp->af_getaddr(addr, DSTADDR); } @@ -1211,59 +1389,90 @@ getifflags(const char *ifname, int us, bool err_ok) * Make a private copy so we can avoid that. */ static void -setifflags(const char *vname, int value, int s, const struct afswtch *afp) +clearifflags(if_ctx *ctx, const char *vname, int value) { struct ifreq my_ifr; int flags; - flags = getifflags(name, s, false); - if (value < 0) { - value = -value; - flags &= ~value; - } else - flags |= value; + flags = getifflags(ctx->ifname, ctx->io_s, false); + flags &= ~value; memset(&my_ifr, 0, sizeof(my_ifr)); - (void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); + strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name)); my_ifr.ifr_flags = flags & 0xffff; my_ifr.ifr_flagshigh = flags >> 16; - if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) + if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) + Perror(vname); +} + +static void +setifflags(if_ctx *ctx, const char *vname, int value) +{ + struct ifreq my_ifr; + int flags; + + flags = getifflags(ctx->ifname, ctx->io_s, false); + flags |= value; + memset(&my_ifr, 0, sizeof(my_ifr)); + strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name)); + my_ifr.ifr_flags = flags & 0xffff; + my_ifr.ifr_flagshigh = flags >> 16; + if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) Perror(vname); } void -setifcap(const char *vname, int value, int s, const struct afswtch *afp) +clearifcap(if_ctx *ctx, const char *vname, int value) { + struct ifreq ifr = {}; int flags; - if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) { + if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) { Perror("ioctl (SIOCGIFCAP)"); exit(1); } flags = ifr.ifr_curcap; - if (value < 0) { - value = -value; - flags &= ~value; - } else - flags |= value; + flags &= ~value; flags &= ifr.ifr_reqcap; /* Check for no change in capabilities. */ if (ifr.ifr_curcap == flags) return; ifr.ifr_reqcap = flags; - if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) + if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0) Perror(vname); } void -setifcapnv(const char *vname, const char *arg, int s, const struct afswtch *afp) +setifcap(if_ctx *ctx, const char *vname, int value) +{ + struct ifreq ifr = {}; + int flags; + + if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) { + Perror("ioctl (SIOCGIFCAP)"); + exit(1); + } + flags = ifr.ifr_curcap; + flags |= value; + flags &= ifr.ifr_reqcap; + /* Check for no change in capabilities. */ + if (ifr.ifr_curcap == flags) + return; + ifr.ifr_reqcap = flags; + if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0) + Perror(vname); +} + +void +setifcapnv(if_ctx *ctx, const char *vname, const char *arg) { nvlist_t *nvcap; void *buf; char *marg, *mopt; size_t nvbuflen; bool neg; + struct ifreq ifr = {}; - if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) + if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) Perror("ioctl (SIOCGIFCAP)"); if ((ifr.ifr_curcap & IFCAP_NV) == 0) { warnx("IFCAP_NV not supported"); @@ -1294,7 +1503,7 @@ setifcapnv(const char *vname, const char *arg, int s, const struct afswtch *afp) } ifr.ifr_cap_nv.buf_length = ifr.ifr_cap_nv.length = nvbuflen; ifr.ifr_cap_nv.buffer = buf; - if (ioctl(s, SIOCSIFCAPNV, (caddr_t)&ifr) < 0) + if (ioctl_ctx(ctx, SIOCSIFCAPNV, (caddr_t)&ifr) < 0) Perror(vname); free(buf); nvlist_destroy(nvcap); @@ -1302,28 +1511,29 @@ setifcapnv(const char *vname, const char *arg, int s, const struct afswtch *afp) } static void -setifmetric(const char *val, int dummy __unused, int s, - const struct afswtch *afp) +setifmetric(if_ctx *ctx, const char *val, int dummy __unused) { - strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + struct ifreq ifr = {}; + ifr.ifr_metric = atoi(val); - if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) + if (ioctl_ctx_ifr(ctx, SIOCSIFMETRIC, &ifr) < 0) err(1, "ioctl SIOCSIFMETRIC (set metric)"); } static void -setifmtu(const char *val, int dummy __unused, int s, - const struct afswtch *afp) +setifmtu(if_ctx *ctx, const char *val, int dummy __unused) { - strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + struct ifreq ifr = {}; + ifr.ifr_mtu = atoi(val); - if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) + if (ioctl_ctx_ifr(ctx, SIOCSIFMTU, &ifr) < 0) err(1, "ioctl SIOCSIFMTU (set mtu)"); } static void -setifpcp(const char *val, int arg __unused, int s, const struct afswtch *afp) +setifpcp(if_ctx *ctx, const char *val, int arg __unused) { + struct ifreq ifr = {}; u_long ul; char *endp; @@ -1333,50 +1543,45 @@ setifpcp(const char *val, int arg __unused, int s, const struct afswtch *afp) if (ul > 7) errx(1, "value for pcp out of range"); ifr.ifr_lan_pcp = ul; - if (ioctl(s, SIOCSLANPCP, (caddr_t)&ifr) == -1) + if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1) err(1, "SIOCSLANPCP"); } static void -disableifpcp(const char *val, int arg __unused, int s, - const struct afswtch *afp) +disableifpcp(if_ctx *ctx, const char *val __unused, int arg __unused) { + struct ifreq ifr = {}; ifr.ifr_lan_pcp = IFNET_PCP_NONE; - if (ioctl(s, SIOCSLANPCP, (caddr_t)&ifr) == -1) + if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1) err(1, "SIOCSLANPCP"); } static void -setifname(const char *val, int dummy __unused, int s, - const struct afswtch *afp) +setifname(if_ctx *ctx, const char *val, int dummy __unused) { + struct ifreq ifr = {}; char *newname; - - strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr_set_name(&ifr, ctx->ifname); newname = strdup(val); if (newname == NULL) err(1, "no memory to set ifname"); ifr.ifr_data = newname; - if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { + if (ioctl_ctx(ctx, SIOCSIFNAME, (caddr_t)&ifr) < 0) { free(newname); err(1, "ioctl SIOCSIFNAME (set name)"); } - printifname = 1; - strlcpy(name, newname, sizeof(name)); + ifname_update(ctx, newname); free(newname); } -/* ARGSUSED */ static void -setifdescr(const char *val, int dummy __unused, int s, - const struct afswtch *afp) +setifdescr(if_ctx *ctx, const char *val, int dummy __unused) { + struct ifreq ifr = {}; char *newdescr; - strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - ifr.ifr_buffer.length = strlen(val) + 1; if (ifr.ifr_buffer.length == 1) { ifr.ifr_buffer.buffer = newdescr = NULL; @@ -1390,20 +1595,20 @@ setifdescr(const char *val, int dummy __unused, int s, } } - if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) + if (ioctl_ctx_ifr(ctx, SIOCSIFDESCR, &ifr) < 0) err(1, "ioctl SIOCSIFDESCR (set descr)"); free(newdescr); } -/* ARGSUSED */ static void -unsetifdescr(const char *val, int value, int s, const struct afswtch *afp) +unsetifdescr(if_ctx *ctx, const char *val __unused, int value __unused) { - - setifdescr("", 0, s, 0); + setifdescr(ctx, "", 0); } +#ifdef WITHOUT_NETLINK + #define IFFBITS \ "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \ "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ @@ -1416,49 +1621,126 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp) "\26RXCSUM_IPV6\27TXCSUM_IPV6\31TXRTLMT\32HWRXTSTMP\33NOMAP\34TXTLS4\35TXTLS6" \ "\36VXLAN_HWCSUM\37VXLAN_HWTSO\40TXTLS_RTLMT" -/* - * 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) +print_ifcap_nv(if_ctx *ctx) { - struct ifaddrs *ift; - struct ifstat ifs; + struct ifreq ifr = {}; nvlist_t *nvcap; const char *nvname; void *buf, *cookie; - int allfamilies, s, type; bool first, val; + int type; - if (afp == NULL) { - allfamilies = 1; - ifr.ifr_addr.sa_family = AF_LOCAL; - } else { - allfamilies = 0; - ifr.ifr_addr.sa_family = - afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af; + buf = malloc(IFR_CAP_NV_MAXBUFSIZE); + if (buf == NULL) + Perror("malloc"); + ifr.ifr_cap_nv.buffer = buf; + ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE; + if (ioctl_ctx_ifr(ctx, SIOCGIFCAPNV, &ifr) != 0) + Perror("ioctl (SIOCGIFCAPNV)"); + nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer, + ifr.ifr_cap_nv.length, 0); + if (nvcap == NULL) + Perror("nvlist_unpack"); + printf("\toptions"); + cookie = NULL; + for (first = true;; first = false) { + nvname = nvlist_next(nvcap, &type, &cookie); + if (nvname == NULL) { + printf("\n"); + break; + } + if (type == NV_TYPE_BOOL) { + val = nvlist_get_bool(nvcap, nvname); + if (val) { + printf("%c%s", + first ? ' ' : ',', nvname); + } + } + } + if (ctx->args->supmedia) { + printf("\tcapabilities"); + cookie = NULL; + for (first = true;; first = false) { + nvname = nvlist_next(nvcap, &type, + &cookie); + if (nvname == NULL) { + printf("\n"); + break; + } + if (type == NV_TYPE_BOOL) + printf("%c%s", first ? ' ' : + ',', nvname); + } } - strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + nvlist_destroy(nvcap); + free(buf); - 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); + if (ioctl_ctx(ctx, SIOCGIFCAP, (caddr_t)&ifr) != 0) + Perror("ioctl (SIOCGIFCAP)"); +} - printf("%s: ", name); - printb("flags", ifa->ifa_flags, IFFBITS); - if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1) +static void +print_ifcap(if_ctx *ctx) +{ + struct ifreq ifr = {}; + + if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) != 0) + return; + + if ((ifr.ifr_curcap & IFCAP_NV) != 0) + print_ifcap_nv(ctx); + else { + printb("\toptions", ifr.ifr_curcap, IFCAPBITS); + putchar('\n'); + if (ctx->args->supmedia && ifr.ifr_reqcap != 0) { + printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); + putchar('\n'); + } + } +} +#endif + +void +print_ifstatus(if_ctx *ctx) +{ + struct ifstat ifs; + + strlcpy(ifs.ifs_name, ctx->ifname, sizeof ifs.ifs_name); + if (ioctl_ctx(ctx, SIOCGIFSTATUS, &ifs) == 0) + printf("%s", ifs.ascii); +} + +void +print_metric(if_ctx *ctx) +{ + struct ifreq ifr = {}; + + if (ioctl_ctx_ifr(ctx, SIOCGIFMETRIC, &ifr) != -1) printf(" metric %d", ifr.ifr_metric); - if (ioctl(s, SIOCGIFMTU, &ifr) != -1) +} + +#ifdef WITHOUT_NETLINK +static void +print_mtu(if_ctx *ctx) +{ + struct ifreq ifr = {}; + + if (ioctl_ctx_ifr(ctx, SIOCGIFMTU, &ifr) != -1) printf(" mtu %d", ifr.ifr_mtu); - putchar('\n'); +} +static void +print_description(if_ctx *ctx) +{ + struct ifreq ifr = {}; + + ifr_set_name(&ifr, ctx->ifname); for (;;) { if ((descr = reallocf(descr, descrlen)) != NULL) { ifr.ifr_buffer.buffer = descr; ifr.ifr_buffer.length = descrlen; - if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) { + if (ioctl_ctx(ctx, SIOCGIFDESCR, &ifr) == 0) { if (ifr.ifr_buffer.buffer == descr) { if (strlen(descr) > 0) printf("\tdescription: %s\n", @@ -1473,68 +1755,44 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, "description"); break; } +} - if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { - if ((ifr.ifr_curcap & IFCAP_NV) != 0) { - buf = malloc(IFR_CAP_NV_MAXBUFSIZE); - if (buf == NULL) - Perror("malloc"); - ifr.ifr_cap_nv.buffer = buf; - ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE; - if (ioctl(s, SIOCGIFCAPNV, (caddr_t)&ifr) != 0) - Perror("ioctl (SIOCGIFCAPNV)"); - nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer, - ifr.ifr_cap_nv.length, 0); - if (nvcap == NULL) - Perror("nvlist_unpack"); - printf("\toptions"); - cookie = NULL; - for (first = true;; first = false) { - nvname = nvlist_next(nvcap, &type, &cookie); - if (nvname == NULL) { - printf("\n"); - break; - } - if (type == NV_TYPE_BOOL) { - val = nvlist_get_bool(nvcap, nvname); - if (val) { - printf("%c%s", - first ? ' ' : ',', nvname); - } - } - } - if (supmedia) { - printf("\tcapabilities"); - cookie = NULL; - for (first = true;; first = false) { - nvname = nvlist_next(nvcap, &type, - &cookie); - if (nvname == NULL) { - printf("\n"); - break; - } - if (type == NV_TYPE_BOOL) - printf("%c%s", first ? ' ' : - ',', nvname); - } - } - nvlist_destroy(nvcap); - free(buf); +/* + * Print the status of the interface. If an address family was + * specified, show only it; otherwise, show them all. + */ +static void +status(if_ctx *ctx, const struct sockaddr_dl *sdl __unused, struct ifaddrs *ifa) +{ + struct ifaddrs *ift; + int s, old_s; + struct ifconfig_args *args = ctx->args; + bool allfamilies = args->afp == NULL; + struct ifreq ifr = {}; - if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) != 0) - Perror("ioctl (SIOCGIFCAP)"); - } else if (ifr.ifr_curcap != 0) { - printb("\toptions", ifr.ifr_curcap, IFCAPBITS); - putchar('\n'); - if (supmedia && ifr.ifr_reqcap != 0) { - printb("\tcapabilities", ifr.ifr_reqcap, - IFCAPBITS); - putchar('\n'); - } - } - } + if (args->afp == NULL) + ifr.ifr_addr.sa_family = AF_LOCAL; + else + ifr.ifr_addr.sa_family = + args->afp->af_af == AF_LINK ? AF_LOCAL : args->afp->af_af; - tunnel_status(s); + 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); + old_s = ctx->io_s; + ctx->io_s = s; + + printf("%s: ", ctx->ifname); + printb("flags", ifa->ifa_flags, IFFBITS); + print_metric(ctx); + print_mtu(ctx); + putchar('\n'); + + print_description(ctx); + + print_ifcap(ctx); + + tunnel_status(ctx); for (ift = ifa; ift != NULL; ift = ift->ifa_next) { if (ift->ifa_addr == NULL) @@ -1545,9 +1803,9 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, 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); + p->af_status(ctx, ift); + } else if (args->afp->af_af == ift->ifa_addr->sa_family) + args->afp->af_status(ctx, ift); } #if 0 if (allfamilies || afp->af_af == AF_LINK) { @@ -1567,29 +1825,28 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, } #endif if (allfamilies) - af_other_status(s); - else if (afp->af_other_status != NULL) - afp->af_other_status(s); + af_other_status(ctx); + else if (args->afp->af_other_status != NULL) + args->afp->af_other_status(ctx); - strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name); - if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) - printf("%s", ifs.ascii); - - if (verbose > 0) - sfp_status(s, &ifr, verbose); + print_ifstatus(ctx); + if (args->verbose > 0) + sfp_status(ctx); close(s); + ctx->io_s = old_s; return; } +#endif -static void -tunnel_status(int s) +void +tunnel_status(if_ctx *ctx) { - af_all_tunnel_status(s); + af_all_tunnel_status(ctx); } -void -Perror(const char *cmd) +static void +Perrorc(const char *cmd, int error) { switch (errno) { @@ -1602,10 +1859,16 @@ Perror(const char *cmd) break; default: - err(1, "%s", cmd); + errc(1, error, "%s", cmd); } } +void +Perror(const char *cmd) +{ + Perrorc(cmd, errno); +} + /* * Print a value a la the %b format of the kernel's printf */ @@ -1638,7 +1901,7 @@ printb(const char *s, unsigned v, const char *bits) } void -print_vhid(const struct ifaddrs *ifa, const char *s) +print_vhid(const struct ifaddrs *ifa) { struct if_data *ifd; @@ -1653,32 +1916,34 @@ print_vhid(const struct ifaddrs *ifa, const char *s) } void -ifmaybeload(const char *name) +ifmaybeload(struct ifconfig_args *args, const char *name) { #define MOD_PREFIX_LEN 3 /* "if_" */ struct module_stat mstat; - int i, fileid, modid; + int fileid, modid; char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp; const char *cp; struct module_map_entry *mme; bool found; /* loading suppressed by the user */ - if (noload) + if (args->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; + dp = ifname + strlen(ifname) - 1; + for (; dp > ifname; dp--) { + if (isdigit(*dp)) + *dp = '\0'; + else break; - } + } /* Either derive it from the map or guess otherwise */ *ifkind = '\0'; found = false; - for (i = 0; i < nitems(module_map); ++i) { + for (unsigned i = 0; i < nitems(module_map); ++i) { mme = &module_map[i]; if (strcmp(mme->ifname, ifname) == 0) { strlcpy(ifkind, mme->kldname, sizeof(ifkind)); @@ -1728,17 +1993,17 @@ ifmaybeload(const char *name) 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("down", IFF_UP, clearifflags), + DEF_CMD("arp", IFF_NOARP, clearifflags), DEF_CMD("-arp", IFF_NOARP, setifflags), DEF_CMD("debug", IFF_DEBUG, setifflags), - DEF_CMD("-debug", -IFF_DEBUG, setifflags), + DEF_CMD("-debug", IFF_DEBUG, clearifflags), DEF_CMD_ARG("description", setifdescr), DEF_CMD_ARG("descr", setifdescr), DEF_CMD("-description", 0, unsetifdescr), DEF_CMD("-descr", 0, unsetifdescr), DEF_CMD("promisc", IFF_PPROMISC, setifflags), - DEF_CMD("-promisc", -IFF_PPROMISC, setifflags), + DEF_CMD("-promisc", IFF_PPROMISC, clearifflags), DEF_CMD("add", IFF_UP, notealias), DEF_CMD("alias", IFF_UP, notealias), DEF_CMD("-alias", -IFF_UP, notealias), @@ -1747,7 +2012,7 @@ static struct cmd basic_cmds[] = { #ifdef notdef #define EN_SWABIPS 0x1000 DEF_CMD("swabips", EN_SWABIPS, setifflags), - DEF_CMD("-swabips", -EN_SWABIPS, setifflags), + DEF_CMD("-swabips", EN_SWABIPS, clearifflags), #endif DEF_CMD_ARG("netmask", setifnetmask), DEF_CMD_ARG("metric", setifmetric), @@ -1760,64 +2025,64 @@ static struct cmd basic_cmds[] = { DEF_CMD_ARG("-vnet", setifrvnet), #endif DEF_CMD("link0", IFF_LINK0, setifflags), - DEF_CMD("-link0", -IFF_LINK0, setifflags), + DEF_CMD("-link0", IFF_LINK0, clearifflags), DEF_CMD("link1", IFF_LINK1, setifflags), - DEF_CMD("-link1", -IFF_LINK1, setifflags), + DEF_CMD("-link1", IFF_LINK1, clearifflags), DEF_CMD("link2", IFF_LINK2, setifflags), - DEF_CMD("-link2", -IFF_LINK2, setifflags), + DEF_CMD("-link2", IFF_LINK2, clearifflags), DEF_CMD("monitor", IFF_MONITOR, setifflags), - DEF_CMD("-monitor", -IFF_MONITOR, setifflags), + DEF_CMD("-monitor", IFF_MONITOR, clearifflags), DEF_CMD("mextpg", IFCAP_MEXTPG, setifcap), - DEF_CMD("-mextpg", -IFCAP_MEXTPG, setifcap), + DEF_CMD("-mextpg", IFCAP_MEXTPG, clearifcap), DEF_CMD("staticarp", IFF_STATICARP, setifflags), - DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), + DEF_CMD("-staticarp", IFF_STATICARP, clearifflags), DEF_CMD("stickyarp", IFF_STICKYARP, setifflags), - DEF_CMD("-stickyarp", -IFF_STICKYARP, setifflags), + DEF_CMD("-stickyarp", IFF_STICKYARP, clearifflags), DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap), - DEF_CMD("-rxcsum6", -IFCAP_RXCSUM_IPV6, setifcap), + DEF_CMD("-rxcsum6", IFCAP_RXCSUM_IPV6, clearifcap), DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap), - DEF_CMD("-txcsum6", -IFCAP_TXCSUM_IPV6, setifcap), + DEF_CMD("-txcsum6", IFCAP_TXCSUM_IPV6, clearifcap), DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), - DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), + DEF_CMD("-rxcsum", IFCAP_RXCSUM, clearifcap), DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), - DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), + DEF_CMD("-txcsum", IFCAP_TXCSUM, clearifcap), DEF_CMD("netcons", IFCAP_NETCONS, setifcap), - DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), + DEF_CMD("-netcons", IFCAP_NETCONS, clearifcap), DEF_CMD_ARG("pcp", setifpcp), DEF_CMD("-pcp", 0, disableifpcp), DEF_CMD("polling", IFCAP_POLLING, setifcap), - DEF_CMD("-polling", -IFCAP_POLLING, setifcap), + DEF_CMD("-polling", IFCAP_POLLING, clearifcap), DEF_CMD("tso6", IFCAP_TSO6, setifcap), - DEF_CMD("-tso6", -IFCAP_TSO6, setifcap), + DEF_CMD("-tso6", IFCAP_TSO6, clearifcap), DEF_CMD("tso4", IFCAP_TSO4, setifcap), - DEF_CMD("-tso4", -IFCAP_TSO4, setifcap), + DEF_CMD("-tso4", IFCAP_TSO4, clearifcap), DEF_CMD("tso", IFCAP_TSO, setifcap), - DEF_CMD("-tso", -IFCAP_TSO, setifcap), + DEF_CMD("-tso", IFCAP_TSO, clearifcap), DEF_CMD("toe", IFCAP_TOE, setifcap), - DEF_CMD("-toe", -IFCAP_TOE, setifcap), + DEF_CMD("-toe", IFCAP_TOE, clearifcap), DEF_CMD("lro", IFCAP_LRO, setifcap), - DEF_CMD("-lro", -IFCAP_LRO, setifcap), + DEF_CMD("-lro", IFCAP_LRO, clearifcap), DEF_CMD("txtls", IFCAP_TXTLS, setifcap), - DEF_CMD("-txtls", -IFCAP_TXTLS, setifcap), + DEF_CMD("-txtls", IFCAP_TXTLS, clearifcap), DEF_CMD_SARG("rxtls", IFCAP2_RXTLS4_NAME "," IFCAP2_RXTLS6_NAME, setifcapnv), DEF_CMD_SARG("-rxtls", "-"IFCAP2_RXTLS4_NAME ",-" IFCAP2_RXTLS6_NAME, setifcapnv), DEF_CMD("wol", IFCAP_WOL, setifcap), - DEF_CMD("-wol", -IFCAP_WOL, setifcap), + DEF_CMD("-wol", IFCAP_WOL, clearifcap), DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), - DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap), + DEF_CMD("-wol_ucast", IFCAP_WOL_UCAST, clearifcap), DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap), - DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap), + DEF_CMD("-wol_mcast", IFCAP_WOL_MCAST, clearifcap), DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap), - DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap), + DEF_CMD("-wol_magic", IFCAP_WOL_MAGIC, clearifcap), DEF_CMD("txrtlmt", IFCAP_TXRTLMT, setifcap), - DEF_CMD("-txrtlmt", -IFCAP_TXRTLMT, setifcap), + DEF_CMD("-txrtlmt", IFCAP_TXRTLMT, clearifcap), DEF_CMD("txtlsrtlmt", IFCAP_TXTLS_RTLMT, setifcap), - DEF_CMD("-txtlsrtlmt", -IFCAP_TXTLS_RTLMT, setifcap), + DEF_CMD("-txtlsrtlmt", IFCAP_TXTLS_RTLMT, clearifcap), DEF_CMD("hwrxtstmp", IFCAP_HWRXTSTMP, setifcap), - DEF_CMD("-hwrxtstmp", -IFCAP_HWRXTSTMP, setifcap), - DEF_CMD("normal", -IFF_LINK0, setifflags), + DEF_CMD("-hwrxtstmp", IFCAP_HWRXTSTMP, clearifcap), + DEF_CMD("normal", IFF_LINK0, clearifflags), DEF_CMD("compress", IFF_LINK0, setifflags), DEF_CMD("noicmp", IFF_LINK1, setifflags), DEF_CMD_ARG("mtu", setifmtu), |