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