ifconfig.c revision 1.250
1/* $NetBSD: ifconfig.c,v 1.250 2024/01/03 18:10:42 andvar 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.250 2024/01/03 18:10:42 andvar 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("unnumbered", IFF_UNNUMBERED) 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 addresses", and is 755 * mutually exclusive with 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 prop_dictionary_t env, oenv; 854 int idx; 855 char *p; 856 857 if (env0 == NULL) 858 env = prop_dictionary_create(); 859 else 860 env = prop_dictionary_copy_mutable(env0); 861 862 oenv = prop_dictionary_create(); 863 864 if (env == NULL || oenv == NULL) 865 errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__); 866 867 if (getifaddrs(&ifap) != 0) 868 err(EXIT_FAILURE, "getifaddrs"); 869 p = NULL; 870 idx = 0; 871 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 872 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) 873 continue; 874 if (p && strcmp(p, ifa->ifa_name) == 0) 875 continue; 876 if (!prop_dictionary_set_string(env, "if", ifa->ifa_name)) 877 continue; 878 p = ifa->ifa_name; 879 880 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0) 881 continue; 882 if (dflag && (ifa->ifa_flags & IFF_UP) != 0) 883 continue; 884 if (uflag && (ifa->ifa_flags & IFF_UP) == 0) 885 continue; 886 887 if (sflag && carrier(env) == LINK_STATE_DOWN) 888 continue; 889 idx++; 890 /* 891 * Are we just listing the interfaces? 892 */ 893 if (lflag) { 894 if (idx > 1) 895 printf(" "); 896 fputs(ifa->ifa_name, stdout); 897 continue; 898 } 899 900 status(env, oenv); 901 } 902 if (lflag) 903 printf("\n"); 904 prop_object_release((prop_object_t)env); 905 prop_object_release((prop_object_t)oenv); 906 freeifaddrs(ifap); 907} 908 909static int 910list_cloners(prop_dictionary_t env, prop_dictionary_t oenv) 911{ 912 struct if_clonereq ifcr; 913 char *cp, *buf; 914 int idx, s; 915 916 memset(&ifcr, 0, sizeof(ifcr)); 917 918 s = getsock(AF_INET); 919 920 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 921 err(EXIT_FAILURE, "SIOCIFGCLONERS for count"); 922 923 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 924 if (buf == NULL) 925 err(EXIT_FAILURE, "unable to allocate cloner name buffer"); 926 927 ifcr.ifcr_count = ifcr.ifcr_total; 928 ifcr.ifcr_buffer = buf; 929 930 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 931 err(EXIT_FAILURE, "SIOCIFGCLONERS for names"); 932 933 /* 934 * In case some disappeared in the mean time, clamp it down. 935 */ 936 if (ifcr.ifcr_count > ifcr.ifcr_total) 937 ifcr.ifcr_count = ifcr.ifcr_total; 938 939 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 940 if (idx > 0) 941 printf(" "); 942 printf("%s", cp); 943 } 944 945 printf("\n"); 946 free(buf); 947 exit(EXIT_SUCCESS); 948} 949 950static int 951clone_command(prop_dictionary_t env, prop_dictionary_t oenv) 952{ 953 int64_t cmd; 954 955 if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) { 956 errno = ENOENT; 957 return -1; 958 } 959 960 if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) { 961 warn("%s", __func__); 962 return -1; 963 } 964 return 0; 965} 966 967/*ARGSUSED*/ 968static int 969setifaddr(prop_dictionary_t env, prop_dictionary_t oenv) 970{ 971 const struct paddr_prefix *pfx0; 972 struct paddr_prefix *pfx; 973 prop_data_t d; 974 int af; 975 976 if ((af = getaf(env)) == -1) 977 af = AF_INET; 978 979 d = (prop_data_t)prop_dictionary_get(env, "address"); 980 assert(d != NULL); 981 pfx0 = prop_data_value(d); 982 983 if (pfx0->pfx_len >= 0) { 984 pfx = prefixlen_to_mask(af, pfx0->pfx_len); 985 if (pfx == NULL) 986 err(EXIT_FAILURE, "prefixlen_to_mask"); 987 free(pfx); 988 } 989 990 return 0; 991} 992 993static int 994setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv) 995{ 996 prop_data_t d; 997 998 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 999 assert(d != NULL); 1000 1001 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 1002 return -1; 1003 1004 return 0; 1005} 1006 1007static int 1008setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv) 1009{ 1010 prop_data_t d; 1011 unsigned short flags; 1012 1013 if (getifflags(env, oenv, &flags) == -1) 1014 err(EXIT_FAILURE, "%s: getifflags", __func__); 1015 1016 if ((flags & IFF_BROADCAST) == 0) 1017 errx(EXIT_FAILURE, "not a broadcast interface"); 1018 1019 d = (prop_data_t)prop_dictionary_get(env, "broadcast"); 1020 assert(d != NULL); 1021 1022 if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d)) 1023 return -1; 1024 1025 return 0; 1026} 1027 1028/*ARGSUSED*/ 1029static int 1030notrailers(prop_dictionary_t env, prop_dictionary_t oenv) 1031{ 1032 puts("Note: trailers are no longer sent, but always received"); 1033 return 0; 1034} 1035 1036/*ARGSUSED*/ 1037static int 1038setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv) 1039{ 1040 const char *key; 1041 prop_data_t d; 1042 unsigned short flags; 1043 1044 if (getifflags(env, oenv, &flags) == -1) 1045 err(EXIT_FAILURE, "%s: getifflags", __func__); 1046 1047 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 1048 assert(d != NULL); 1049 1050 if ((flags & IFF_BROADCAST) == 0) { 1051 key = "dst"; 1052 } else { 1053 key = "netmask"; 1054 } 1055 1056 if (!prop_dictionary_set(oenv, key, (prop_object_t)d)) 1057 return -1; 1058 1059 return 0; 1060} 1061 1062static int 1063setifflags(prop_dictionary_t env, prop_dictionary_t oenv) 1064{ 1065 struct ifreq ifr; 1066 int64_t ifflag; 1067 bool rc; 1068 1069 rc = prop_dictionary_get_int64(env, "ifflag", &ifflag); 1070 assert(rc); 1071 1072 if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) 1073 return -1; 1074 1075 if (ifflag < 0) { 1076 ifflag = -ifflag; 1077 ifr.ifr_flags &= ~ifflag; 1078 } else 1079 ifr.ifr_flags |= ifflag; 1080 1081 if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1) 1082 return -1; 1083 1084 return 0; 1085} 1086 1087static int 1088getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr) 1089{ 1090 bool rc; 1091 struct ifcapreq ifcr; 1092 const struct ifcapreq *tmpifcr; 1093 prop_data_t capdata; 1094 1095 capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps"); 1096 1097 if (capdata != NULL) { 1098 tmpifcr = prop_data_value(capdata); 1099 *oifcr = *tmpifcr; 1100 return 0; 1101 } 1102 1103 (void)direct_ioctl(env, SIOCGIFCAP, &ifcr); 1104 *oifcr = ifcr; 1105 1106 capdata = prop_data_create_copy(&ifcr, sizeof(ifcr)); 1107 1108 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1109 1110 prop_object_release((prop_object_t)capdata); 1111 1112 return rc ? 0 : -1; 1113} 1114 1115static int 1116setifcaps(prop_dictionary_t env, prop_dictionary_t oenv) 1117{ 1118 int64_t ifcap; 1119 bool rc; 1120 prop_data_t capdata; 1121 struct ifcapreq ifcr; 1122 1123 rc = prop_dictionary_get_int64(env, "ifcap", &ifcap); 1124 assert(rc); 1125 1126 if (getifcaps(env, oenv, &ifcr) == -1) 1127 return -1; 1128 1129 if (ifcap < 0) { 1130 ifcap = -ifcap; 1131 ifcr.ifcr_capenable &= ~ifcap; 1132 } else 1133 ifcr.ifcr_capenable |= ifcap; 1134 1135 if ((capdata = prop_data_create_copy(&ifcr, sizeof(ifcr))) == NULL) 1136 return -1; 1137 1138 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1139 prop_object_release((prop_object_t)capdata); 1140 1141 return rc ? 0 : -1; 1142} 1143 1144static int 1145setifmetric(prop_dictionary_t env, prop_dictionary_t oenv) 1146{ 1147 struct ifreq ifr; 1148 bool rc; 1149 int64_t metric; 1150 1151 rc = prop_dictionary_get_int64(env, "metric", &metric); 1152 assert(rc); 1153 1154 ifr.ifr_metric = metric; 1155 if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1) 1156 warn("SIOCSIFMETRIC"); 1157 return 0; 1158} 1159 1160static void 1161do_setifpreference(prop_dictionary_t env) 1162{ 1163 struct if_addrprefreq ifap; 1164 prop_data_t d; 1165 const struct paddr_prefix *pfx; 1166 1167 memset(&ifap, 0, sizeof(ifap)); 1168 1169 if (!prop_dictionary_get_int16(env, "preference", 1170 &ifap.ifap_preference)) 1171 return; 1172 1173 d = (prop_data_t)prop_dictionary_get(env, "address"); 1174 assert(d != NULL); 1175 1176 pfx = prop_data_value(d); 1177 1178 memcpy(&ifap.ifap_addr, &pfx->pfx_addr, 1179 MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len)); 1180 if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1) 1181 warn("SIOCSIFADDRPREF"); 1182} 1183 1184static int 1185setifmtu(prop_dictionary_t env, prop_dictionary_t oenv) 1186{ 1187 int64_t mtu; 1188 bool rc; 1189 struct ifreq ifr; 1190 1191 rc = prop_dictionary_get_int64(env, "mtu", &mtu); 1192 assert(rc); 1193 1194 ifr.ifr_mtu = mtu; 1195 if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1) 1196 warn("SIOCSIFMTU"); 1197 1198 return 0; 1199} 1200 1201static int 1202carrier(prop_dictionary_t env) 1203{ 1204 struct ifdatareq ifdr = { .ifdr_data.ifi_link_state = 0 }; 1205 1206 if (direct_ioctl(env, SIOCGIFDATA, &ifdr) == -1) 1207 return EXIT_FAILURE; 1208 1209 if (ifdr.ifdr_data.ifi_link_state == LINK_STATE_DOWN) 1210 return EXIT_FAILURE; 1211 else /* Assume UP if UNKNOWN */ 1212 return EXIT_SUCCESS; 1213} 1214 1215static void 1216print_plural(const char *prefix, uint64_t n, const char *unit) 1217{ 1218 printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s"); 1219} 1220 1221static void 1222print_human_bytes(bool humanize, uint64_t n) 1223{ 1224 char buf[5]; 1225 1226 if (humanize) { 1227 (void)humanize_number(buf, sizeof(buf), 1228 (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); 1229 printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s"); 1230 } else 1231 print_plural(", ", n, "byte"); 1232} 1233 1234/* 1235 * Print the status of the interface. If an address family was 1236 * specified, show it and it only; otherwise, show them all. 1237 */ 1238 1239#define MAX_PRINT_LEN 58 /* XXX need a better way to determine this! */ 1240 1241void 1242status(prop_dictionary_t env, prop_dictionary_t oenv) 1243{ 1244 status_func_t *status_f; 1245 statistics_func_t *statistics_f; 1246 struct ifdatareq ifdr; 1247 struct if_data *ifi; 1248 struct ifreq ifr; 1249 struct ifdrv ifdrv; 1250 char fbuf[BUFSIZ]; 1251 char *bp; 1252 int af, s; 1253 const char *ifname; 1254 struct ifcapreq ifcr; 1255 unsigned short flags; 1256 const struct afswtch *afp; 1257 char ifdescr[IFDESCRSIZE]; 1258 1259 if ((af = getaf(env)) == -1) { 1260 afp = NULL; 1261 af = AF_UNSPEC; 1262 } else 1263 afp = lookup_af_bynum(af); 1264 1265 /* get out early if the family is unsupported by the kernel */ 1266 if ((s = getsock(af)) == -1) 1267 err(EXIT_FAILURE, "%s: getsock", __func__); 1268 1269 if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 1270 err(EXIT_FAILURE, "%s: getifinfo", __func__); 1271 1272 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags); 1273 printf("%s: flags=%s", ifname, fbuf); 1274 1275 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1276 if (prog_ioctl(s, SIOCGIFMETRIC, &ifr) == -1) 1277 warn("SIOCGIFMETRIC %s", ifr.ifr_name); 1278 else if (ifr.ifr_metric != 0) 1279 printf(" metric %d", ifr.ifr_metric); 1280 1281 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1282 if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0) 1283 printf(" mtu %d", ifr.ifr_mtu); 1284 printf("\n"); 1285 1286 if (getifcaps(env, oenv, &ifcr) == -1) 1287 err(EXIT_FAILURE, "%s: getifcaps", __func__); 1288 1289 if (ifcr.ifcr_capabilities != 0) { 1290 (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS, 1291 ifcr.ifcr_capabilities, MAX_PRINT_LEN); 1292 bp = fbuf; 1293 while (*bp != '\0') { 1294 printf("\tcapabilities=%s\n", bp); 1295 bp += strlen(bp) + 1; 1296 } 1297 (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS, 1298 ifcr.ifcr_capenable, MAX_PRINT_LEN); 1299 bp = fbuf; 1300 while (*bp != '\0') { 1301 printf("\tenabled=%s\n", bp); 1302 bp += strlen(bp) + 1; 1303 } 1304 } 1305 1306 SIMPLEQ_FOREACH(status_f, &status_funcs, f_next) 1307 (*status_f->f_func)(env, oenv); 1308 1309 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1310 ifr.ifr_buf = &ifdescr; 1311 ifr.ifr_buflen = sizeof(ifdescr); 1312 if (prog_ioctl(s, SIOCGIFDESCR, &ifr) == 0) 1313 printf("\tdescription: \"%s\"\n", (char *)ifr.ifr_buf); 1314 1315 print_link_addresses(env, true); 1316 1317 estrlcpy(ifdrv.ifd_name, ifname, sizeof(ifdrv.ifd_name)); 1318 ifdrv.ifd_cmd = IFLINKSTR_QUERYLEN; 1319 ifdrv.ifd_len = 0; 1320 ifdrv.ifd_data = NULL; 1321 /* interface supports linkstr? */ 1322 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) != -1) { 1323 char *p; 1324 1325 p = malloc(ifdrv.ifd_len); 1326 if (p == NULL) 1327 err(EXIT_FAILURE, "malloc linkstr buf failed"); 1328 ifdrv.ifd_data = p; 1329 ifdrv.ifd_cmd = 0; 1330 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) == -1) 1331 err(EXIT_FAILURE, "failed to query linkstr"); 1332 printf("\tlinkstr: %s\n", (char *)ifdrv.ifd_data); 1333 free(p); 1334 } 1335 1336 media_status(env, oenv); 1337 1338 if (!vflag && !zflag) 1339 goto proto_status; 1340 1341 /* We already have if_data from SIOCGIFDATA in ifa_data. */ 1342 estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 1343 if (prog_ioctl(s, zflag ? SIOCZIFDATA : SIOCGIFDATA, &ifdr) == -1) 1344 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA"); 1345 ifi = &ifdr.ifdr_data; 1346 1347 print_plural("\tinput: ", ifi->ifi_ipackets, "packet"); 1348 print_human_bytes(hflag, ifi->ifi_ibytes); 1349 if (ifi->ifi_imcasts) 1350 print_plural(", ", ifi->ifi_imcasts, "multicast"); 1351 if (ifi->ifi_ierrors) 1352 print_plural(", ", ifi->ifi_ierrors, "error"); 1353 if (ifi->ifi_iqdrops) 1354 print_plural(", ", ifi->ifi_iqdrops, "queue drop"); 1355 if (ifi->ifi_noproto) 1356 printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto); 1357 print_plural("\n\toutput: ", ifi->ifi_opackets, "packet"); 1358 print_human_bytes(hflag, ifi->ifi_obytes); 1359 if (ifi->ifi_omcasts) 1360 print_plural(", ", ifi->ifi_omcasts, "multicast"); 1361 if (ifi->ifi_oerrors) 1362 print_plural(", ", ifi->ifi_oerrors, "error"); 1363 if (ifi->ifi_collisions) 1364 print_plural(", ", ifi->ifi_collisions, "collision"); 1365 printf("\n"); 1366 1367 SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next) 1368 (*statistics_f->f_func)(env); 1369 1370 proto_status: 1371 1372 if (afp != NULL) 1373 (*afp->af_status)(env, oenv, true); 1374 else SIMPLEQ_FOREACH(afp, &aflist, af_next) 1375 (*afp->af_status)(env, oenv, false); 1376} 1377 1378static int 1379setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv) 1380{ 1381 bool rc; 1382 int64_t plen; 1383 int af; 1384 struct paddr_prefix *pfx; 1385 prop_data_t d; 1386 1387 if ((af = getaf(env)) == -1) 1388 af = AF_INET; 1389 1390 rc = prop_dictionary_get_int64(env, "prefixlen", &plen); 1391 assert(rc); 1392 1393 pfx = prefixlen_to_mask(af, plen); 1394 if (pfx == NULL) 1395 err(EXIT_FAILURE, "prefixlen_to_mask"); 1396 1397 d = prop_data_create_copy(pfx, paddr_prefix_size(pfx)); 1398 if (d == NULL) 1399 err(EXIT_FAILURE, "%s: prop_data_create_copy", __func__); 1400 1401 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 1402 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 1403 1404 free(pfx); 1405 return 0; 1406} 1407 1408static int 1409setlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1410{ 1411 struct ifdrv ifdrv; 1412 size_t linkstrlen; 1413 prop_data_t data; 1414 char *linkstr; 1415 1416 data = (prop_data_t)prop_dictionary_get(env, "linkstr"); 1417 if (data == NULL) { 1418 errno = ENOENT; 1419 return -1; 1420 } 1421 linkstrlen = prop_data_size(data)+1; 1422 1423 linkstr = malloc(linkstrlen); 1424 if (linkstr == NULL) 1425 err(EXIT_FAILURE, "malloc linkstr space"); 1426 if (getargstr(env, "linkstr", linkstr, linkstrlen) == -1) 1427 errx(EXIT_FAILURE, "getargstr linkstr failed"); 1428 1429 ifdrv.ifd_cmd = 0; 1430 ifdrv.ifd_len = linkstrlen; 1431 ifdrv.ifd_data = __UNCONST(linkstr); 1432 1433 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1434 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1435 free(linkstr); 1436 1437 return 0; 1438} 1439 1440static int 1441unsetlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1442{ 1443 struct ifdrv ifdrv; 1444 1445 memset(&ifdrv, 0, sizeof(ifdrv)); 1446 ifdrv.ifd_cmd = IFLINKSTR_UNSET; 1447 1448 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1449 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1450 1451 return 0; 1452} 1453 1454static int 1455setifdescr(prop_dictionary_t env, prop_dictionary_t oenv) 1456{ 1457 struct ifreq ifr; 1458 size_t len; 1459 prop_data_t data; 1460 char *descr; 1461 1462 data = (prop_data_t)prop_dictionary_get(env, "descr"); 1463 if (data == NULL) { 1464 errno = ENOENT; 1465 return -1; 1466 } 1467 len = prop_data_size(data) + 1; 1468 1469 if (len > IFDESCRSIZE) 1470 err(EXIT_FAILURE, "description too long"); 1471 1472 descr = malloc(len); 1473 if (descr == NULL) 1474 err(EXIT_FAILURE, "malloc description space"); 1475 if (getargstr(env, "descr", descr, len) == -1) 1476 errx(EXIT_FAILURE, "getargstr descr failed"); 1477 1478 1479 ifr.ifr_buf = descr; 1480 ifr.ifr_buflen = len; 1481 if (direct_ioctl(env, SIOCSIFDESCR, &ifr) != 0) 1482 err(EXIT_FAILURE, "SIOCSIFDESCR"); 1483 1484 free(descr); 1485 1486 return 0; 1487} 1488 1489static int 1490unsetifdescr(prop_dictionary_t env, prop_dictionary_t oenv) 1491{ 1492 struct ifreq ifr; 1493 ifr.ifr_buf = NULL; 1494 ifr.ifr_buflen = 0; 1495 1496 if (direct_ioctl(env, SIOCSIFDESCR, &ifr) != 0) 1497 err(EXIT_FAILURE, "SIOCSIFDESCR"); 1498 1499 return 0; 1500} 1501 1502 1503static void 1504usage(void) 1505{ 1506 const char *progname = getprogname(); 1507 usage_func_t *usage_f; 1508 prop_dictionary_t env; 1509 1510 if ((env = prop_dictionary_create()) == NULL) 1511 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 1512 1513 fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n" 1514 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n" 1515 "\t\t[ alias | -alias ] ]\n" 1516 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname, 1517 flag_is_registered(gflags, 'm') ? "[-m] " : "", 1518 flag_is_registered(gflags, 'L') ? "[-L] " : ""); 1519 1520 SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next) 1521 (*usage_f->f_func)(env); 1522 1523 fprintf(stderr, 1524 "\t[ arp | -arp ]\n" 1525 "\t[ preference n ]\n" 1526 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n" 1527 "\t[ linkstr str | -linkstr ]\n" 1528 "\t[ unnumbered | -unnumbered ]\n" 1529 "\t[ description str | descr str | -description | -descr ]\n" 1530 " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n" 1531 " %s -l [-b] [-d] [-s] [-u]\n" 1532 " %s -C\n" 1533 " %s -w n\n" 1534 " %s interface create\n" 1535 " %s interface destroy\n", 1536 progname, flag_is_registered(gflags, 'm') ? "[-m] " : "", 1537 progname, progname, progname, progname, progname); 1538 1539 prop_object_release((prop_object_t)env); 1540 exit(EXIT_FAILURE); 1541} 1542