ifconfig.c revision 1.244
1/* $NetBSD: ifconfig.c,v 1.244 2020/09/23 02:09:18 roy Exp $ */ 2 3/*- 4 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * Copyright (c) 1983, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62#include <sys/cdefs.h> 63#ifndef lint 64__COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 65 The Regents of the University of California. All rights reserved."); 66__RCSID("$NetBSD: ifconfig.c,v 1.244 2020/09/23 02:09:18 roy Exp $"); 67#endif /* not lint */ 68 69#include <sys/param.h> 70#include <sys/queue.h> 71#include <sys/socket.h> 72#include <sys/ioctl.h> 73 74#include <net/if.h> 75#include <net/if_dl.h> 76#include <net/if_media.h> 77#include <net/if_ether.h> 78#include <netinet/in.h> /* XXX */ 79#include <netinet/in_var.h> /* XXX */ 80 81#include <netdb.h> 82 83#include <sys/protosw.h> 84 85#include <assert.h> 86#include <ctype.h> 87#include <err.h> 88#include <errno.h> 89#include <stdbool.h> 90#include <stddef.h> 91#include <stdio.h> 92#include <stdlib.h> 93#include <string.h> 94#include <unistd.h> 95#include <ifaddrs.h> 96#include <util.h> 97 98#include "extern.h" 99 100#include "media.h" 101#include "parse.h" 102#include "env.h" 103#include "prog_ops.h" 104 105#define WAIT_DAD 10000000 /* nanoseconds between each poll, 10ms */ 106 107static bool bflag, dflag, hflag, sflag, uflag, Wflag, wflag; 108bool lflag, Nflag, vflag, zflag; 109static long wflag_secs, Wflag_secs; 110 111static char gflags[10 + 26 * 2 + 1] = "AabCdhlNsuvW:w:z"; 112bool gflagset[10 + 26 * 2]; 113 114static int carrier(prop_dictionary_t); 115static int clone_command(prop_dictionary_t, prop_dictionary_t); 116static void do_setifpreference(prop_dictionary_t); 117static int flag_index(int); 118static void init_afs(void); 119static int list_cloners(prop_dictionary_t, prop_dictionary_t); 120static int media_status_exec(prop_dictionary_t, prop_dictionary_t); 121static int wait_dad_exec(prop_dictionary_t, prop_dictionary_t); 122static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t); 123static int notrailers(prop_dictionary_t, prop_dictionary_t); 124static void printall(const char *, prop_dictionary_t); 125static int setifaddr(prop_dictionary_t, prop_dictionary_t); 126static int setifbroadaddr(prop_dictionary_t, prop_dictionary_t); 127static int setifcaps(prop_dictionary_t, prop_dictionary_t); 128static int setifdstormask(prop_dictionary_t, prop_dictionary_t); 129static int setifflags(prop_dictionary_t, prop_dictionary_t); 130static int setifmetric(prop_dictionary_t, prop_dictionary_t); 131static int setifmtu(prop_dictionary_t, prop_dictionary_t); 132static int setifnetmask(prop_dictionary_t, prop_dictionary_t); 133static int setifprefixlen(prop_dictionary_t, prop_dictionary_t); 134static int setlinkstr(prop_dictionary_t, prop_dictionary_t); 135static int unsetlinkstr(prop_dictionary_t, prop_dictionary_t); 136static int setifdescr(prop_dictionary_t, prop_dictionary_t); 137static int unsetifdescr(prop_dictionary_t, prop_dictionary_t); 138static void status(const struct sockaddr_dl *, prop_dictionary_t, 139 prop_dictionary_t); 140__dead static void usage(void); 141 142static const struct kwinst ifflagskw[] = { 143 IFKW("arp", -IFF_NOARP) 144 , IFKW("debug", IFF_DEBUG) 145 , IFKW("link0", IFF_LINK0) 146 , IFKW("link1", IFF_LINK1) 147 , IFKW("link2", IFF_LINK2) 148 , {.k_word = "down", .k_type = KW_T_INT, .k_int = -IFF_UP} 149 , {.k_word = "up", .k_type = KW_T_INT, .k_int = IFF_UP} 150}; 151 152static const struct kwinst ifcapskw[] = { 153 IFKW("ip4csum-tx", IFCAP_CSUM_IPv4_Tx) 154 , IFKW("ip4csum-rx", IFCAP_CSUM_IPv4_Rx) 155 , IFKW("tcp4csum-tx", IFCAP_CSUM_TCPv4_Tx) 156 , IFKW("tcp4csum-rx", IFCAP_CSUM_TCPv4_Rx) 157 , IFKW("udp4csum-tx", IFCAP_CSUM_UDPv4_Tx) 158 , IFKW("udp4csum-rx", IFCAP_CSUM_UDPv4_Rx) 159 , IFKW("tcp6csum-tx", IFCAP_CSUM_TCPv6_Tx) 160 , IFKW("tcp6csum-rx", IFCAP_CSUM_TCPv6_Rx) 161 , IFKW("udp6csum-tx", IFCAP_CSUM_UDPv6_Tx) 162 , IFKW("udp6csum-rx", IFCAP_CSUM_UDPv6_Rx) 163 , IFKW("ip4csum", IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx) 164 , IFKW("tcp4csum", IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx) 165 , IFKW("udp4csum", IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx) 166 , IFKW("tcp6csum", IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx) 167 , IFKW("udp6csum", IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx) 168 , IFKW("tso4", IFCAP_TSOv4) 169 , IFKW("tso6", IFCAP_TSOv6) 170}; 171 172extern struct pbranch command_root; 173extern struct pbranch opt_command; 174extern struct pbranch opt_family, opt_silent_family; 175extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc; 176extern struct pstr parse_linkstr; 177 178struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10, 179 setifmetric, "metric", &command_root.pb_parser); 180 181struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10, 182 setifmtu, "mtu", &command_root.pb_parser); 183 184struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen, 185 "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser); 186 187struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference, 188 "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference", 189 &command_root.pb_parser); 190 191struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask", 192 setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser); 193 194struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast, 195 "broadcast address", 196 setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser); 197 198struct pstr parse_descr = PSTR_INITIALIZER1(&parse_descr, "descr", 199 setifdescr, "descr", false, &command_root.pb_parser); 200 201static const struct kwinst misckw[] = { 202 {.k_word = "alias", .k_key = "alias", .k_deact = "alias", 203 .k_type = KW_T_BOOL, .k_neg = true, 204 .k_bool = true, .k_negbool = false, 205 .k_nextparser = &command_root.pb_parser} 206 , {.k_word = "broadcast", .k_nextparser = &parse_broadcast.pa_parser} 207 , {.k_word = "delete", .k_key = "alias", .k_deact = "alias", 208 .k_type = KW_T_BOOL, .k_bool = false, 209 .k_nextparser = &command_root.pb_parser} 210 , {.k_word = "metric", .k_nextparser = &parse_metric.pi_parser} 211 , {.k_word = "mtu", .k_nextparser = &parse_mtu.pi_parser} 212 , {.k_word = "netmask", .k_nextparser = &parse_netmask.pa_parser} 213 , {.k_word = "preference", .k_act = "address", 214 .k_nextparser = &parse_preference.pi_parser} 215 , {.k_word = "prefixlen", .k_nextparser = &parse_prefixlen.pi_parser} 216 , {.k_word = "trailers", .k_neg = true, 217 .k_exec = notrailers, .k_nextparser = &command_root.pb_parser} 218 , {.k_word = "linkstr", .k_nextparser = &parse_linkstr.ps_parser } 219 , {.k_word = "-linkstr", .k_exec = unsetlinkstr, 220 .k_nextparser = &command_root.pb_parser } 221 , {.k_word = "descr", .k_nextparser = &parse_descr.ps_parser} 222 , {.k_word = "description", .k_nextparser = &parse_descr.ps_parser} 223 , {.k_word = "-descr", .k_exec = unsetifdescr, 224 .k_nextparser = &command_root.pb_parser} 225 , {.k_word = "-description", .k_exec = unsetifdescr, 226 .k_nextparser = &command_root.pb_parser} 227}; 228 229/* key: clonecmd */ 230static const struct kwinst clonekw[] = { 231 {.k_word = "create", .k_type = KW_T_INT, .k_int = SIOCIFCREATE, 232 .k_nextparser = &opt_silent_family.pb_parser}, 233 {.k_word = "destroy", .k_type = KW_T_INT, .k_int = SIOCIFDESTROY} 234}; 235 236static struct kwinst familykw[24]; 237 238struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners", 239 list_cloners, "none"); 240 241struct pterm wait_dad = PTERM_INITIALIZER(&wait_dad, "wait DAD", wait_dad_exec, 242 "none"); 243 244struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec, 245 "none"); 246 247struct pkw family_only = 248 PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw, 249 __arraycount(familykw), &no_cmds.pt_parser); 250 251struct paddr address = PADDR_INITIALIZER(&address, 252 "local address (address 1)", 253 setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser); 254 255struct paddr dstormask = PADDR_INITIALIZER(&dstormask, 256 "destination/netmask (address 2)", 257 setifdstormask, "dstormask", NULL, "address", "dstormask", 258 &command_root.pb_parser); 259 260struct paddr broadcast = PADDR_INITIALIZER(&broadcast, 261 "broadcast address (address 3)", 262 setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast", 263 &command_root.pb_parser); 264 265struct pstr parse_linkstr = PSTR_INITIALIZER(&parse_linkstr, "linkstr", 266 setlinkstr, "linkstr", &command_root.pb_parser); 267 268static SIMPLEQ_HEAD(, afswtch) aflist = SIMPLEQ_HEAD_INITIALIZER(aflist); 269 270static SIMPLEQ_HEAD(, usage_func) usage_funcs = 271 SIMPLEQ_HEAD_INITIALIZER(usage_funcs); 272static SIMPLEQ_HEAD(, status_func) status_funcs = 273 SIMPLEQ_HEAD_INITIALIZER(status_funcs); 274static SIMPLEQ_HEAD(, statistics_func) statistics_funcs = 275 SIMPLEQ_HEAD_INITIALIZER(statistics_funcs); 276static SIMPLEQ_HEAD(, cmdloop_branch) cmdloop_branches = 277 SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches); 278 279struct branch opt_clone_brs[] = { 280 {.b_nextparser = &cloning.pk_parser} 281 , {.b_nextparser = &opt_family.pb_parser} 282}, opt_silent_family_brs[] = { 283 {.b_nextparser = &silent_family.pk_parser} 284 , {.b_nextparser = &command_root.pb_parser} 285}, opt_family_brs[] = { 286 {.b_nextparser = &family.pk_parser} 287 , {.b_nextparser = &opt_command.pb_parser} 288}, command_root_brs[] = { 289 {.b_nextparser = &ifflags.pk_parser} 290 , {.b_nextparser = &ifcaps.pk_parser} 291 , {.b_nextparser = &kwmedia.pk_parser} 292 , {.b_nextparser = &misc.pk_parser} 293 , {.b_nextparser = &address.pa_parser} 294 , {.b_nextparser = &dstormask.pa_parser} 295 , {.b_nextparser = &broadcast.pa_parser} 296 , {.b_nextparser = NULL} 297}, opt_command_brs[] = { 298 {.b_nextparser = &no_cmds.pt_parser} 299 , {.b_nextparser = &command_root.pb_parser} 300}; 301 302struct branch opt_family_only_brs[] = { 303 {.b_nextparser = &no_cmds.pt_parser} 304 , {.b_nextparser = &family_only.pk_parser} 305}; 306struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only, 307 "opt-family-only", opt_family_only_brs, 308 __arraycount(opt_family_only_brs), true); 309struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command, 310 "optional command", 311 opt_command_brs, __arraycount(opt_command_brs), true); 312 313struct pbranch command_root = PBRANCH_INITIALIZER(&command_root, 314 "command-root", command_root_brs, __arraycount(command_root_brs), true); 315 316struct piface iface_opt_family_only = 317 PIFACE_INITIALIZER(&iface_opt_family_only, "iface-opt-family-only", 318 NULL, "if", &opt_family_only.pb_parser); 319 320struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af", 321 familykw, __arraycount(familykw), &opt_command.pb_parser); 322 323struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family", 324 NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser); 325 326struct pkw *family_users[] = {&family_only, &family, &silent_family}; 327 328struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps, 329 "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser); 330 331struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags, 332 "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser); 333 334struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command, 335 "clonecmd", clonekw, __arraycount(clonekw), NULL); 336 337struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL, 338 misckw, __arraycount(misckw), NULL); 339 340struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone, 341 "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true); 342 343struct pbranch opt_silent_family = PBRANCH_INITIALIZER(&opt_silent_family, 344 "optional silent family", opt_silent_family_brs, 345 __arraycount(opt_silent_family_brs), true); 346 347struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family, 348 "opt-family", opt_family_brs, __arraycount(opt_family_brs), true); 349 350struct piface iface_start = PIFACE_INITIALIZER(&iface_start, 351 "iface-opt-family", NULL, "if", &opt_clone.pb_parser); 352 353struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface", 354 media_status_exec, "if", NULL); 355 356static bool 357flag_is_registered(const char *flags, int flag) 358{ 359 return flags != NULL && strchr(flags, flag) != NULL; 360} 361 362static int 363check_flag(const char *flags, int flag) 364{ 365 if (flag_is_registered(flags, flag)) { 366 errno = EEXIST; 367 return -1; 368 } 369 370 if (flag >= '0' && flag <= '9') 371 return 0; 372 if (flag >= 'a' && flag <= 'z') 373 return 0; 374 if (flag >= 'A' && flag <= 'Z') 375 return 0; 376 377 errno = EINVAL; 378 return -1; 379} 380 381void 382cmdloop_branch_init(cmdloop_branch_t *b, struct parser *p) 383{ 384 b->b_parser = p; 385} 386 387void 388statistics_func_init(statistics_func_t *f, statistics_cb_t func) 389{ 390 f->f_func = func; 391} 392 393void 394status_func_init(status_func_t *f, status_cb_t func) 395{ 396 f->f_func = func; 397} 398 399void 400usage_func_init(usage_func_t *f, usage_cb_t func) 401{ 402 f->f_func = func; 403} 404 405int 406register_cmdloop_branch(cmdloop_branch_t *b) 407{ 408 SIMPLEQ_INSERT_TAIL(&cmdloop_branches, b, b_next); 409 return 0; 410} 411 412int 413register_statistics(statistics_func_t *f) 414{ 415 SIMPLEQ_INSERT_TAIL(&statistics_funcs, f, f_next); 416 return 0; 417} 418 419int 420register_status(status_func_t *f) 421{ 422 SIMPLEQ_INSERT_TAIL(&status_funcs, f, f_next); 423 return 0; 424} 425 426int 427register_usage(usage_func_t *f) 428{ 429 SIMPLEQ_INSERT_TAIL(&usage_funcs, f, f_next); 430 return 0; 431} 432 433int 434register_family(struct afswtch *af) 435{ 436 SIMPLEQ_INSERT_TAIL(&aflist, af, af_next); 437 return 0; 438} 439 440int 441register_flag(int flag) 442{ 443 if (check_flag(gflags, flag) == -1) 444 return -1; 445 446 if (strlen(gflags) + 1 >= sizeof(gflags)) { 447 errno = ENOMEM; 448 return -1; 449 } 450 451 gflags[strlen(gflags)] = flag; 452 453 return 0; 454} 455 456static int 457flag_index(int flag) 458{ 459 if (flag >= '0' && flag <= '9') 460 return flag - '0'; 461 if (flag >= 'a' && flag <= 'z') 462 return 10 + flag - 'a'; 463 if (flag >= 'A' && flag <= 'Z') 464 return 10 + 26 + flag - 'a'; 465 466 errno = EINVAL; 467 return -1; 468} 469 470static bool 471set_flag(int flag) 472{ 473 int idx; 474 475 if ((idx = flag_index(flag)) == -1) 476 return false; 477 478 return gflagset[idx] = true; 479} 480 481bool 482get_flag(int flag) 483{ 484 int idx; 485 486 if ((idx = flag_index(flag)) == -1) 487 return false; 488 489 return gflagset[idx]; 490} 491 492static struct parser * 493init_parser(void) 494{ 495 cmdloop_branch_t *b; 496 497 if (parser_init(&iface_opt_family_only.pif_parser) == -1) 498 err(EXIT_FAILURE, "parser_init(iface_opt_family_only)"); 499 if (parser_init(&iface_only.pif_parser) == -1) 500 err(EXIT_FAILURE, "parser_init(iface_only)"); 501 if (parser_init(&iface_start.pif_parser) == -1) 502 err(EXIT_FAILURE, "parser_init(iface_start)"); 503 504 SIMPLEQ_FOREACH(b, &cmdloop_branches, b_next) 505 pbranch_addbranch(&command_root, b->b_parser); 506 507 return &iface_start.pif_parser; 508} 509 510static int 511no_cmds_exec(prop_dictionary_t env, prop_dictionary_t oenv) 512{ 513 const char *ifname; 514 unsigned short ignore; 515 516 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */ 517 if ((ifname = getifname(env)) == NULL) 518 ; 519 else if (getifflags(env, oenv, &ignore) == -1) 520 err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname); 521 522 printall(ifname, env); 523 exit(EXIT_SUCCESS); 524} 525 526static int 527wait_dad_exec(prop_dictionary_t env, prop_dictionary_t oenv) 528{ 529 bool waiting; 530 struct ifaddrs *ifaddrs, *ifa; 531 const struct timespec ts = { .tv_sec = 0, .tv_nsec = WAIT_DAD }; 532 struct timespec now, end_det, end; 533 const struct afswtch *afp; 534 535 if (wflag_secs) { 536 const struct timespec tent = 537 { .tv_sec = wflag_secs, .tv_nsec = 0}; 538 const struct timespec det = 539 { .tv_sec = Wflag_secs, .tv_nsec = 0}; 540 541 if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) 542 err(EXIT_FAILURE, "clock_gettime"); 543 timespecadd(&now, &tent, &end); 544 if (Wflag_secs) 545 timespecadd(&now, &det, &end_det); 546 else 547 timespecclear(&end_det); 548 } else { 549 timespecclear(&end_det); 550 timespecclear(&end); 551 } 552 553 if (getifaddrs(&ifaddrs) == -1) 554 err(EXIT_FAILURE, "getifaddrs"); 555 556 for (;;) { 557 waiting = false; 558 for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { 559 if (ifa->ifa_addr == NULL) 560 continue; 561 afp = lookup_af_bynum(ifa->ifa_addr->sa_family); 562 if (afp && 563 ((afp->af_addr_tentative_or_detached && 564 ifa->ifa_flags & IFF_UP && 565 timespecisset(&end_det) && 566 timespeccmp(&now, &end_det, <) && 567 afp->af_addr_tentative_or_detached(ifa)) || 568 (afp->af_addr_tentative && 569 afp->af_addr_tentative(ifa)))) 570 { 571 waiting = true; 572 break; 573 } 574 } 575 if (!waiting) 576 break; 577 nanosleep(&ts, NULL); 578 if (wflag_secs) { 579 if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) 580 err(EXIT_FAILURE, "clock_gettime"); 581 if (timespeccmp(&now, &end, >)) 582 errx(EXIT_FAILURE, "timed out"); 583 } 584 } 585 586 freeifaddrs(ifaddrs); 587 exit(EXIT_SUCCESS); 588} 589 590static int 591media_status_exec(prop_dictionary_t env, prop_dictionary_t oenv) 592{ 593 const char *ifname; 594 unsigned short ignore; 595 596 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */ 597 if ((ifname = getifname(env)) == NULL) 598 ; 599 else if (getifflags(env, oenv, &ignore) == -1) 600 err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname); 601 602 exit(carrier(env)); 603} 604 605static void 606do_setifcaps(prop_dictionary_t env) 607{ 608 struct ifcapreq ifcr; 609 prop_data_t d; 610 611 d = (prop_data_t )prop_dictionary_get(env, "ifcaps"); 612 if (d == NULL) 613 return; 614 615 assert(sizeof(ifcr) == prop_data_size(d)); 616 617 memcpy(&ifcr, prop_data_value(d), sizeof(ifcr)); 618 if (direct_ioctl(env, SIOCSIFCAP, &ifcr) == -1) 619 err(EXIT_FAILURE, "SIOCSIFCAP"); 620} 621 622int 623main(int argc, char **argv) 624{ 625 const struct afswtch *afp; 626 int af, s, e; 627 bool aflag = false, Cflag = false; 628 struct match match[32]; 629 size_t nmatch; 630 struct parser *start; 631 int ch, narg = 0, rc; 632 prop_dictionary_t env, oenv; 633 const char *ifname; 634 635 memset(match, 0, sizeof(match)); 636 637 init_afs(); 638 639 start = init_parser(); 640 641 /* Parse command-line options */ 642 Nflag = vflag = zflag = false; 643 aflag = argc == 1 ? true : false; 644 if (aflag) 645 start = &opt_family_only.pb_parser; 646 647 while ((ch = getopt(argc, argv, gflags)) != -1) { 648 switch (ch) { 649 case 'A': 650 warnx("-A is deprecated"); 651 break; 652 653 case 'a': 654 aflag = true; 655 break; 656 657 case 'b': 658 bflag = true; 659 break; 660 661 case 'C': 662 Cflag = true; 663 break; 664 665 case 'd': 666 dflag = true; 667 break; 668 case 'h': 669 hflag = true; 670 break; 671 case 'l': 672 lflag = true; 673 break; 674 case 'N': 675 Nflag = true; 676 break; 677 678 case 's': 679 sflag = true; 680 break; 681 682 case 'u': 683 uflag = true; 684 break; 685 686 case 'v': 687 vflag = true; 688 break; 689 690 case 'w': 691 wflag = true; 692 wflag_secs = strtoi(optarg, NULL, 10, 0, INT32_MAX, &e); 693 if (e) 694 errx(EXIT_FAILURE, "%s: not a number", optarg); 695 break; 696 697 case 'W': 698 Wflag = true; 699 Wflag_secs = strtoi(optarg, NULL, 10, 0, INT32_MAX, &e); 700 if (e) 701 errx(EXIT_FAILURE, "%s: not a number", optarg); 702 break; 703 704 case 'z': 705 zflag = true; 706 break; 707 708 default: 709 if (!set_flag(ch)) 710 usage(); 711 break; 712 } 713 switch (ch) { 714 case 'a': 715 start = &opt_family_only.pb_parser; 716 break; 717 718 case 'L': 719 case 'm': 720 case 'z': 721 if (start != &opt_family_only.pb_parser) 722 start = &iface_opt_family_only.pif_parser; 723 break; 724 case 'C': 725 start = &cloneterm.pt_parser; 726 break; 727 case 'l': 728 start = &no_cmds.pt_parser; 729 break; 730 case 's': 731 if (start != &no_cmds.pt_parser && 732 start != &opt_family_only.pb_parser) 733 start = &iface_only.pif_parser; 734 break; 735 case 'w': 736 start = &wait_dad.pt_parser; 737 break; 738 default: 739 break; 740 } 741 } 742 argc -= optind; 743 argv += optind; 744 745 /* 746 * -l means "list all interfaces", and is mutually exclusive with 747 * all other flags/commands. 748 * 749 * -C means "list all names of cloners", and it mutually exclusive 750 * with all other flags/commands. 751 * 752 * -a means "print status of all interfaces". 753 * 754 * -w means "spin until DAD completes for all addreseses", and is 755 * mutually exclusivewith all other flags/commands. 756 */ 757 if ((lflag || Cflag || wflag) && 758 (aflag || get_flag('m') || vflag || zflag)) 759 usage(); 760 if ((lflag || Cflag || wflag) && get_flag('L')) 761 usage(); 762 if ((lflag && Cflag) || (lflag & wflag) || (Cflag && wflag)) 763 usage(); 764 765 nmatch = __arraycount(match); 766 767 rc = parse(argc, argv, start, match, &nmatch, &narg); 768 if (rc != 0) 769 usage(); 770 771 if (prog_init && prog_init() == -1) 772 err(1, "rump client init"); 773 774 if ((oenv = prop_dictionary_create()) == NULL) 775 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 776 777 if (matches_exec(match, oenv, nmatch) == -1) 778 err(EXIT_FAILURE, "exec_matches"); 779 780 argc -= narg; 781 argv += narg; 782 783 env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL; 784 if (env == NULL) 785 env = oenv; 786 else { 787 env = prop_dictionary_augment(env, oenv); 788 if (env == NULL) 789 err(EXIT_FAILURE, "%s: prop_dictionary_augment", 790 __func__); 791 } 792 793 /* Process any media commands that may have been issued. */ 794 process_media_commands(env); 795 796 if ((af = getaf(env)) == -1) 797 af = AF_INET; 798 799 if ((s = getsock(af)) == -1) 800 err(EXIT_FAILURE, "%s: getsock", __func__); 801 802 if ((ifname = getifname(env)) == NULL) 803 err(EXIT_FAILURE, "%s: getifname", __func__); 804 805 if ((afp = lookup_af_bynum(af)) == NULL) 806 errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__); 807 808 assert(afp->af_addr_commit != NULL); 809 (*afp->af_addr_commit)(env, oenv); 810 811 do_setifpreference(env); 812 do_setifcaps(env); 813 do_setethercaps(env); 814 815 exit(EXIT_SUCCESS); 816} 817 818static void 819init_afs(void) 820{ 821 size_t i; 822 const struct afswtch *afp; 823 struct kwinst kw = {.k_type = KW_T_INT}; 824 825 SIMPLEQ_FOREACH(afp, &aflist, af_next) { 826 kw.k_word = afp->af_name; 827 kw.k_int = afp->af_af; 828 for (i = 0; i < __arraycount(familykw); i++) { 829 if (familykw[i].k_word == NULL) { 830 familykw[i] = kw; 831 break; 832 } 833 } 834 } 835} 836 837const struct afswtch * 838lookup_af_bynum(int afnum) 839{ 840 const struct afswtch *afp; 841 842 SIMPLEQ_FOREACH(afp, &aflist, af_next) { 843 if (afp->af_af == afnum) 844 break; 845 } 846 return afp; 847} 848 849void 850printall(const char *ifname, prop_dictionary_t env0) 851{ 852 struct ifaddrs *ifap, *ifa; 853 struct ifreq ifr; 854 const struct sockaddr_dl *sdl = NULL; 855 prop_dictionary_t env, oenv; 856 int idx; 857 char *p; 858 859 if (env0 == NULL) 860 env = prop_dictionary_create(); 861 else 862 env = prop_dictionary_copy_mutable(env0); 863 864 oenv = prop_dictionary_create(); 865 866 if (env == NULL || oenv == NULL) 867 errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__); 868 869 if (getifaddrs(&ifap) != 0) 870 err(EXIT_FAILURE, "getifaddrs"); 871 p = NULL; 872 idx = 0; 873 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 874 memset(&ifr, 0, sizeof(ifr)); 875 estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); 876 if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 877 memcpy(&ifr.ifr_addr, ifa->ifa_addr, 878 ifa->ifa_addr->sa_len); 879 } 880 881 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) 882 continue; 883 if (ifa->ifa_addr->sa_family == AF_LINK) 884 sdl = (const struct sockaddr_dl *)ifa->ifa_addr; 885 if (p && strcmp(p, ifa->ifa_name) == 0) 886 continue; 887 if (!prop_dictionary_set_string(env, "if", ifa->ifa_name)) 888 continue; 889 p = ifa->ifa_name; 890 891 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0) 892 continue; 893 if (dflag && (ifa->ifa_flags & IFF_UP) != 0) 894 continue; 895 if (uflag && (ifa->ifa_flags & IFF_UP) == 0) 896 continue; 897 898 if (sflag && carrier(env)) 899 continue; 900 idx++; 901 /* 902 * Are we just listing the interfaces? 903 */ 904 if (lflag) { 905 if (idx > 1) 906 printf(" "); 907 fputs(ifa->ifa_name, stdout); 908 continue; 909 } 910 911 status(sdl, env, oenv); 912 sdl = NULL; 913 } 914 if (lflag) 915 printf("\n"); 916 prop_object_release((prop_object_t)env); 917 prop_object_release((prop_object_t)oenv); 918 freeifaddrs(ifap); 919} 920 921static int 922list_cloners(prop_dictionary_t env, prop_dictionary_t oenv) 923{ 924 struct if_clonereq ifcr; 925 char *cp, *buf; 926 int idx, s; 927 928 memset(&ifcr, 0, sizeof(ifcr)); 929 930 s = getsock(AF_INET); 931 932 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 933 err(EXIT_FAILURE, "SIOCIFGCLONERS for count"); 934 935 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 936 if (buf == NULL) 937 err(EXIT_FAILURE, "unable to allocate cloner name buffer"); 938 939 ifcr.ifcr_count = ifcr.ifcr_total; 940 ifcr.ifcr_buffer = buf; 941 942 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 943 err(EXIT_FAILURE, "SIOCIFGCLONERS for names"); 944 945 /* 946 * In case some disappeared in the mean time, clamp it down. 947 */ 948 if (ifcr.ifcr_count > ifcr.ifcr_total) 949 ifcr.ifcr_count = ifcr.ifcr_total; 950 951 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 952 if (idx > 0) 953 printf(" "); 954 printf("%s", cp); 955 } 956 957 printf("\n"); 958 free(buf); 959 exit(EXIT_SUCCESS); 960} 961 962static int 963clone_command(prop_dictionary_t env, prop_dictionary_t oenv) 964{ 965 int64_t cmd; 966 967 if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) { 968 errno = ENOENT; 969 return -1; 970 } 971 972 if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) { 973 warn("%s", __func__); 974 return -1; 975 } 976 return 0; 977} 978 979/*ARGSUSED*/ 980static int 981setifaddr(prop_dictionary_t env, prop_dictionary_t oenv) 982{ 983 const struct paddr_prefix *pfx0; 984 struct paddr_prefix *pfx; 985 prop_data_t d; 986 int af; 987 988 if ((af = getaf(env)) == -1) 989 af = AF_INET; 990 991 d = (prop_data_t)prop_dictionary_get(env, "address"); 992 assert(d != NULL); 993 pfx0 = prop_data_value(d); 994 995 if (pfx0->pfx_len >= 0) { 996 pfx = prefixlen_to_mask(af, pfx0->pfx_len); 997 if (pfx == NULL) 998 err(EXIT_FAILURE, "prefixlen_to_mask"); 999 free(pfx); 1000 } 1001 1002 return 0; 1003} 1004 1005static int 1006setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv) 1007{ 1008 prop_data_t d; 1009 1010 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 1011 assert(d != NULL); 1012 1013 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 1014 return -1; 1015 1016 return 0; 1017} 1018 1019static int 1020setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv) 1021{ 1022 prop_data_t d; 1023 unsigned short flags; 1024 1025 if (getifflags(env, oenv, &flags) == -1) 1026 err(EXIT_FAILURE, "%s: getifflags", __func__); 1027 1028 if ((flags & IFF_BROADCAST) == 0) 1029 errx(EXIT_FAILURE, "not a broadcast interface"); 1030 1031 d = (prop_data_t)prop_dictionary_get(env, "broadcast"); 1032 assert(d != NULL); 1033 1034 if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d)) 1035 return -1; 1036 1037 return 0; 1038} 1039 1040/*ARGSUSED*/ 1041static int 1042notrailers(prop_dictionary_t env, prop_dictionary_t oenv) 1043{ 1044 puts("Note: trailers are no longer sent, but always received"); 1045 return 0; 1046} 1047 1048/*ARGSUSED*/ 1049static int 1050setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv) 1051{ 1052 const char *key; 1053 prop_data_t d; 1054 unsigned short flags; 1055 1056 if (getifflags(env, oenv, &flags) == -1) 1057 err(EXIT_FAILURE, "%s: getifflags", __func__); 1058 1059 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 1060 assert(d != NULL); 1061 1062 if ((flags & IFF_BROADCAST) == 0) { 1063 key = "dst"; 1064 } else { 1065 key = "netmask"; 1066 } 1067 1068 if (!prop_dictionary_set(oenv, key, (prop_object_t)d)) 1069 return -1; 1070 1071 return 0; 1072} 1073 1074static int 1075setifflags(prop_dictionary_t env, prop_dictionary_t oenv) 1076{ 1077 struct ifreq ifr; 1078 int64_t ifflag; 1079 bool rc; 1080 1081 rc = prop_dictionary_get_int64(env, "ifflag", &ifflag); 1082 assert(rc); 1083 1084 if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) 1085 return -1; 1086 1087 if (ifflag < 0) { 1088 ifflag = -ifflag; 1089 ifr.ifr_flags &= ~ifflag; 1090 } else 1091 ifr.ifr_flags |= ifflag; 1092 1093 if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1) 1094 return -1; 1095 1096 return 0; 1097} 1098 1099static int 1100getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr) 1101{ 1102 bool rc; 1103 struct ifcapreq ifcr; 1104 const struct ifcapreq *tmpifcr; 1105 prop_data_t capdata; 1106 1107 capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps"); 1108 1109 if (capdata != NULL) { 1110 tmpifcr = prop_data_value(capdata); 1111 *oifcr = *tmpifcr; 1112 return 0; 1113 } 1114 1115 (void)direct_ioctl(env, SIOCGIFCAP, &ifcr); 1116 *oifcr = ifcr; 1117 1118 capdata = prop_data_create_copy(&ifcr, sizeof(ifcr)); 1119 1120 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1121 1122 prop_object_release((prop_object_t)capdata); 1123 1124 return rc ? 0 : -1; 1125} 1126 1127static int 1128setifcaps(prop_dictionary_t env, prop_dictionary_t oenv) 1129{ 1130 int64_t ifcap; 1131 bool rc; 1132 prop_data_t capdata; 1133 struct ifcapreq ifcr; 1134 1135 rc = prop_dictionary_get_int64(env, "ifcap", &ifcap); 1136 assert(rc); 1137 1138 if (getifcaps(env, oenv, &ifcr) == -1) 1139 return -1; 1140 1141 if (ifcap < 0) { 1142 ifcap = -ifcap; 1143 ifcr.ifcr_capenable &= ~ifcap; 1144 } else 1145 ifcr.ifcr_capenable |= ifcap; 1146 1147 if ((capdata = prop_data_create_copy(&ifcr, sizeof(ifcr))) == NULL) 1148 return -1; 1149 1150 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1151 prop_object_release((prop_object_t)capdata); 1152 1153 return rc ? 0 : -1; 1154} 1155 1156static int 1157setifmetric(prop_dictionary_t env, prop_dictionary_t oenv) 1158{ 1159 struct ifreq ifr; 1160 bool rc; 1161 int64_t metric; 1162 1163 rc = prop_dictionary_get_int64(env, "metric", &metric); 1164 assert(rc); 1165 1166 ifr.ifr_metric = metric; 1167 if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1) 1168 warn("SIOCSIFMETRIC"); 1169 return 0; 1170} 1171 1172static void 1173do_setifpreference(prop_dictionary_t env) 1174{ 1175 struct if_addrprefreq ifap; 1176 prop_data_t d; 1177 const struct paddr_prefix *pfx; 1178 1179 memset(&ifap, 0, sizeof(ifap)); 1180 1181 if (!prop_dictionary_get_int16(env, "preference", 1182 &ifap.ifap_preference)) 1183 return; 1184 1185 d = (prop_data_t)prop_dictionary_get(env, "address"); 1186 assert(d != NULL); 1187 1188 pfx = prop_data_value(d); 1189 1190 memcpy(&ifap.ifap_addr, &pfx->pfx_addr, 1191 MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len)); 1192 if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1) 1193 warn("SIOCSIFADDRPREF"); 1194} 1195 1196static int 1197setifmtu(prop_dictionary_t env, prop_dictionary_t oenv) 1198{ 1199 int64_t mtu; 1200 bool rc; 1201 struct ifreq ifr; 1202 1203 rc = prop_dictionary_get_int64(env, "mtu", &mtu); 1204 assert(rc); 1205 1206 ifr.ifr_mtu = mtu; 1207 if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1) 1208 warn("SIOCSIFMTU"); 1209 1210 return 0; 1211} 1212 1213static int 1214carrier(prop_dictionary_t env) 1215{ 1216 struct ifmediareq ifmr = { .ifm_status = 0 }; 1217 1218 if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) { 1219 /* 1220 * Interface doesn't support SIOC{G,S}IFMEDIA; 1221 * check link state. 1222 */ 1223 struct ifdatareq ifdr = { .ifdr_data.ifi_link_state = 0 }; 1224 1225 if (direct_ioctl(env, SIOCGIFDATA, &ifdr) == -1) 1226 return EXIT_FAILURE; 1227 if (ifdr.ifdr_data.ifi_link_state == LINK_STATE_UP) 1228 return EXIT_SUCCESS; 1229 else 1230 return EXIT_FAILURE; 1231 } 1232 if ((ifmr.ifm_status & IFM_AVALID) == 0) { 1233 /* 1234 * Interface doesn't report media-valid status. 1235 * assume ok. 1236 */ 1237 return EXIT_SUCCESS; 1238 } 1239 /* otherwise, return ok for active, not-ok if not active. */ 1240 if (ifmr.ifm_status & IFM_ACTIVE) 1241 return EXIT_SUCCESS; 1242 else 1243 return EXIT_FAILURE; 1244} 1245 1246static void 1247print_plural(const char *prefix, uint64_t n, const char *unit) 1248{ 1249 printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s"); 1250} 1251 1252static void 1253print_human_bytes(bool humanize, uint64_t n) 1254{ 1255 char buf[5]; 1256 1257 if (humanize) { 1258 (void)humanize_number(buf, sizeof(buf), 1259 (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); 1260 printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s"); 1261 } else 1262 print_plural(", ", n, "byte"); 1263} 1264 1265/* 1266 * Print the status of the interface. If an address family was 1267 * specified, show it and it only; otherwise, show them all. 1268 */ 1269 1270#define MAX_PRINT_LEN 58 /* XXX need a better way to determine this! */ 1271 1272void 1273status(const struct sockaddr_dl *sdl, prop_dictionary_t env, 1274 prop_dictionary_t oenv) 1275{ 1276 const struct if_data *ifi; 1277 status_func_t *status_f; 1278 statistics_func_t *statistics_f; 1279 struct ifdatareq ifdr; 1280 struct ifreq ifr; 1281 struct ifdrv ifdrv; 1282 char fbuf[BUFSIZ]; 1283 char *bp; 1284 int af, s; 1285 const char *ifname; 1286 struct ifcapreq ifcr; 1287 unsigned short flags; 1288 const struct afswtch *afp; 1289 char ifdescr[IFDESCRSIZE]; 1290 1291 if ((af = getaf(env)) == -1) { 1292 afp = NULL; 1293 af = AF_UNSPEC; 1294 } else 1295 afp = lookup_af_bynum(af); 1296 1297 /* get out early if the family is unsupported by the kernel */ 1298 if ((s = getsock(af)) == -1) 1299 err(EXIT_FAILURE, "%s: getsock", __func__); 1300 1301 if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 1302 err(EXIT_FAILURE, "%s: getifinfo", __func__); 1303 1304 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags); 1305 printf("%s: flags=%s", ifname, fbuf); 1306 1307 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1308 if (prog_ioctl(s, SIOCGIFMETRIC, &ifr) == -1) 1309 warn("SIOCGIFMETRIC %s", ifr.ifr_name); 1310 else if (ifr.ifr_metric != 0) 1311 printf(" metric %d", ifr.ifr_metric); 1312 1313 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1314 if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0) 1315 printf(" mtu %d", ifr.ifr_mtu); 1316 printf("\n"); 1317 1318 if (getifcaps(env, oenv, &ifcr) == -1) 1319 err(EXIT_FAILURE, "%s: getifcaps", __func__); 1320 1321 if (ifcr.ifcr_capabilities != 0) { 1322 (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS, 1323 ifcr.ifcr_capabilities, MAX_PRINT_LEN); 1324 bp = fbuf; 1325 while (*bp != '\0') { 1326 printf("\tcapabilities=%s\n", bp); 1327 bp += strlen(bp) + 1; 1328 } 1329 (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS, 1330 ifcr.ifcr_capenable, MAX_PRINT_LEN); 1331 bp = fbuf; 1332 while (*bp != '\0') { 1333 printf("\tenabled=%s\n", bp); 1334 bp += strlen(bp) + 1; 1335 } 1336 } 1337 1338 SIMPLEQ_FOREACH(status_f, &status_funcs, f_next) 1339 (*status_f->f_func)(env, oenv); 1340 1341 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1342 ifr.ifr_buf = &ifdescr; 1343 ifr.ifr_buflen = sizeof(ifdescr); 1344 if (prog_ioctl(s, SIOCGIFDESCR, &ifr) == 0) 1345 printf("\tdescription: \"%s\"\n", (char *)ifr.ifr_buf); 1346 1347 print_link_addresses(env, true); 1348 1349 estrlcpy(ifdrv.ifd_name, ifname, sizeof(ifdrv.ifd_name)); 1350 ifdrv.ifd_cmd = IFLINKSTR_QUERYLEN; 1351 ifdrv.ifd_len = 0; 1352 ifdrv.ifd_data = NULL; 1353 /* interface supports linkstr? */ 1354 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) != -1) { 1355 char *p; 1356 1357 p = malloc(ifdrv.ifd_len); 1358 if (p == NULL) 1359 err(EXIT_FAILURE, "malloc linkstr buf failed"); 1360 ifdrv.ifd_data = p; 1361 ifdrv.ifd_cmd = 0; 1362 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) == -1) 1363 err(EXIT_FAILURE, "failed to query linkstr"); 1364 printf("\tlinkstr: %s\n", (char *)ifdrv.ifd_data); 1365 free(p); 1366 } 1367 1368 estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 1369 1370 if (prog_ioctl(s, zflag ? SIOCZIFDATA : SIOCGIFDATA, &ifdr) == -1) 1371 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA"); 1372 1373 ifi = &ifdr.ifdr_data; 1374 1375 media_status(sdl->sdl_type, ifi->ifi_link_state, env, oenv); 1376 1377 if (!vflag && !zflag) 1378 goto proto_status; 1379 1380 print_plural("\tinput: ", ifi->ifi_ipackets, "packet"); 1381 print_human_bytes(hflag, ifi->ifi_ibytes); 1382 if (ifi->ifi_imcasts) 1383 print_plural(", ", ifi->ifi_imcasts, "multicast"); 1384 if (ifi->ifi_ierrors) 1385 print_plural(", ", ifi->ifi_ierrors, "error"); 1386 if (ifi->ifi_iqdrops) 1387 print_plural(", ", ifi->ifi_iqdrops, "queue drop"); 1388 if (ifi->ifi_noproto) 1389 printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto); 1390 print_plural("\n\toutput: ", ifi->ifi_opackets, "packet"); 1391 print_human_bytes(hflag, ifi->ifi_obytes); 1392 if (ifi->ifi_omcasts) 1393 print_plural(", ", ifi->ifi_omcasts, "multicast"); 1394 if (ifi->ifi_oerrors) 1395 print_plural(", ", ifi->ifi_oerrors, "error"); 1396 if (ifi->ifi_collisions) 1397 print_plural(", ", ifi->ifi_collisions, "collision"); 1398 printf("\n"); 1399 1400 SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next) 1401 (*statistics_f->f_func)(env); 1402 1403 proto_status: 1404 1405 if (afp != NULL) 1406 (*afp->af_status)(env, oenv, true); 1407 else SIMPLEQ_FOREACH(afp, &aflist, af_next) 1408 (*afp->af_status)(env, oenv, false); 1409} 1410 1411static int 1412setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv) 1413{ 1414 bool rc; 1415 int64_t plen; 1416 int af; 1417 struct paddr_prefix *pfx; 1418 prop_data_t d; 1419 1420 if ((af = getaf(env)) == -1) 1421 af = AF_INET; 1422 1423 rc = prop_dictionary_get_int64(env, "prefixlen", &plen); 1424 assert(rc); 1425 1426 pfx = prefixlen_to_mask(af, plen); 1427 if (pfx == NULL) 1428 err(EXIT_FAILURE, "prefixlen_to_mask"); 1429 1430 d = prop_data_create_copy(pfx, paddr_prefix_size(pfx)); 1431 if (d == NULL) 1432 err(EXIT_FAILURE, "%s: prop_data_create_copy", __func__); 1433 1434 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 1435 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 1436 1437 free(pfx); 1438 return 0; 1439} 1440 1441static int 1442setlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1443{ 1444 struct ifdrv ifdrv; 1445 size_t linkstrlen; 1446 prop_data_t data; 1447 char *linkstr; 1448 1449 data = (prop_data_t)prop_dictionary_get(env, "linkstr"); 1450 if (data == NULL) { 1451 errno = ENOENT; 1452 return -1; 1453 } 1454 linkstrlen = prop_data_size(data)+1; 1455 1456 linkstr = malloc(linkstrlen); 1457 if (linkstr == NULL) 1458 err(EXIT_FAILURE, "malloc linkstr space"); 1459 if (getargstr(env, "linkstr", linkstr, linkstrlen) == -1) 1460 errx(EXIT_FAILURE, "getargstr linkstr failed"); 1461 1462 ifdrv.ifd_cmd = 0; 1463 ifdrv.ifd_len = linkstrlen; 1464 ifdrv.ifd_data = __UNCONST(linkstr); 1465 1466 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1467 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1468 free(linkstr); 1469 1470 return 0; 1471} 1472 1473static int 1474unsetlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1475{ 1476 struct ifdrv ifdrv; 1477 1478 memset(&ifdrv, 0, sizeof(ifdrv)); 1479 ifdrv.ifd_cmd = IFLINKSTR_UNSET; 1480 1481 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1482 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1483 1484 return 0; 1485} 1486 1487static int 1488setifdescr(prop_dictionary_t env, prop_dictionary_t oenv) 1489{ 1490 struct ifreq ifr; 1491 size_t len; 1492 prop_data_t data; 1493 char *descr; 1494 1495 data = (prop_data_t)prop_dictionary_get(env, "descr"); 1496 if (data == NULL) { 1497 errno = ENOENT; 1498 return -1; 1499 } 1500 len = prop_data_size(data) + 1; 1501 1502 if (len > IFDESCRSIZE) 1503 err(EXIT_FAILURE, "description too long"); 1504 1505 descr = malloc(len); 1506 if (descr == NULL) 1507 err(EXIT_FAILURE, "malloc description space"); 1508 if (getargstr(env, "descr", descr, len) == -1) 1509 errx(EXIT_FAILURE, "getargstr descr failed"); 1510 1511 1512 ifr.ifr_buf = descr; 1513 ifr.ifr_buflen = len; 1514 if (direct_ioctl(env, SIOCSIFDESCR, &ifr) != 0) 1515 err(EXIT_FAILURE, "SIOCSIFDESCR"); 1516 1517 free(descr); 1518 1519 return 0; 1520} 1521 1522static int 1523unsetifdescr(prop_dictionary_t env, prop_dictionary_t oenv) 1524{ 1525 struct ifreq ifr; 1526 ifr.ifr_buf = NULL; 1527 ifr.ifr_buflen = 0; 1528 1529 if (direct_ioctl(env, SIOCSIFDESCR, &ifr) != 0) 1530 err(EXIT_FAILURE, "SIOCSIFDESCR"); 1531 1532 return 0; 1533} 1534 1535 1536static void 1537usage(void) 1538{ 1539 const char *progname = getprogname(); 1540 usage_func_t *usage_f; 1541 prop_dictionary_t env; 1542 1543 if ((env = prop_dictionary_create()) == NULL) 1544 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 1545 1546 fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n" 1547 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n" 1548 "\t\t[ alias | -alias ] ]\n" 1549 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname, 1550 flag_is_registered(gflags, 'm') ? "[-m] " : "", 1551 flag_is_registered(gflags, 'L') ? "[-L] " : ""); 1552 1553 SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next) 1554 (*usage_f->f_func)(env); 1555 1556 fprintf(stderr, 1557 "\t[ arp | -arp ]\n" 1558 "\t[ preference n ]\n" 1559 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n" 1560 "\t[ linkstr str | -linkstr ]\n" 1561 "\t[ description str | descr str | -description | -descr ]\n" 1562 " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n" 1563 " %s -l [-b] [-d] [-s] [-u]\n" 1564 " %s -C\n" 1565 " %s -w n\n" 1566 " %s interface create\n" 1567 " %s interface destroy\n", 1568 progname, flag_is_registered(gflags, 'm') ? "[-m] " : "", 1569 progname, progname, progname, progname, progname); 1570 1571 prop_object_release((prop_object_t)env); 1572 exit(EXIT_FAILURE); 1573} 1574