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