1/* $NetBSD: ifconfig.c,v 1.226 2011/08/29 14:35:00 joerg 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.226 2011/08/29 14:35:00 joerg 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 105static bool bflag, dflag, hflag, sflag, uflag; 106bool lflag, Nflag, vflag, zflag; 107 108static char gflags[10 + 26 * 2 + 1] = "AabCdhlNsuvz"; 109bool gflagset[10 + 26 * 2]; 110 111static int carrier(prop_dictionary_t); 112static int clone_command(prop_dictionary_t, prop_dictionary_t); 113static void do_setifpreference(prop_dictionary_t); 114static int flag_index(int); 115static void init_afs(void); 116static int list_cloners(prop_dictionary_t, prop_dictionary_t); 117static int media_status_exec(prop_dictionary_t, prop_dictionary_t); 118static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t); 119static int notrailers(prop_dictionary_t, prop_dictionary_t); 120static void printall(const char *, prop_dictionary_t); 121static int setifaddr(prop_dictionary_t, prop_dictionary_t); 122static int setifbroadaddr(prop_dictionary_t, prop_dictionary_t); 123static int setifcaps(prop_dictionary_t, prop_dictionary_t); 124static int setifdstormask(prop_dictionary_t, prop_dictionary_t); 125static int setifflags(prop_dictionary_t, prop_dictionary_t); 126static int setifmetric(prop_dictionary_t, prop_dictionary_t); 127static int setifmtu(prop_dictionary_t, prop_dictionary_t); 128static int setifnetmask(prop_dictionary_t, prop_dictionary_t); 129static int setifprefixlen(prop_dictionary_t, prop_dictionary_t); 130static int setlinkstr(prop_dictionary_t, prop_dictionary_t); 131static int unsetlinkstr(prop_dictionary_t, prop_dictionary_t); 132static void status(const struct sockaddr *, prop_dictionary_t, 133 prop_dictionary_t); 134__dead static void usage(void); 135 136static 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 146static 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 166extern struct pbranch command_root; 167extern struct pbranch opt_command; 168extern struct pbranch opt_family, opt_silent_family; 169extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc; 170extern struct pstr parse_linkstr; 171 172struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10, 173 setifmetric, "metric", &command_root.pb_parser); 174 175struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10, 176 setifmtu, "mtu", &command_root.pb_parser); 177 178struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen, 179 "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser); 180 181struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference, 182 "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference", 183 &command_root.pb_parser); 184 185struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask", 186 setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser); 187 188struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast, 189 "broadcast address", 190 setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser); 191 192static 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 */ 215static 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 221static struct kwinst familykw[24]; 222 223struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners", 224 list_cloners, "none"); 225 226struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec, 227 "none"); 228 229struct pkw family_only = 230 PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw, 231 __arraycount(familykw), &no_cmds.pt_parser); 232 233struct paddr address = PADDR_INITIALIZER(&address, 234 "local address (address 1)", 235 setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser); 236 237struct paddr dstormask = PADDR_INITIALIZER(&dstormask, 238 "destination/netmask (address 2)", 239 setifdstormask, "dstormask", NULL, "address", "dstormask", 240 &command_root.pb_parser); 241 242struct paddr broadcast = PADDR_INITIALIZER(&broadcast, 243 "broadcast address (address 3)", 244 setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast", 245 &command_root.pb_parser); 246 247struct pstr parse_linkstr = PSTR_INITIALIZER(&parse_linkstr, "linkstr", 248 setlinkstr, "linkstr", &command_root.pb_parser); 249 250static SIMPLEQ_HEAD(, afswtch) aflist = SIMPLEQ_HEAD_INITIALIZER(aflist); 251 252static SIMPLEQ_HEAD(, usage_func) usage_funcs = 253 SIMPLEQ_HEAD_INITIALIZER(usage_funcs); 254static SIMPLEQ_HEAD(, status_func) status_funcs = 255 SIMPLEQ_HEAD_INITIALIZER(status_funcs); 256static SIMPLEQ_HEAD(, statistics_func) statistics_funcs = 257 SIMPLEQ_HEAD_INITIALIZER(statistics_funcs); 258static SIMPLEQ_HEAD(, cmdloop_branch) cmdloop_branches = 259 SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches); 260 261struct 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 284struct branch opt_family_only_brs[] = { 285 {.b_nextparser = &no_cmds.pt_parser} 286 , {.b_nextparser = &family_only.pk_parser} 287}; 288struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only, 289 "opt-family-only", opt_family_only_brs, 290 __arraycount(opt_family_only_brs), true); 291struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command, 292 "optional command", 293 opt_command_brs, __arraycount(opt_command_brs), true); 294 295struct pbranch command_root = PBRANCH_INITIALIZER(&command_root, 296 "command-root", command_root_brs, __arraycount(command_root_brs), true); 297 298struct 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 302struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af", 303 familykw, __arraycount(familykw), &opt_command.pb_parser); 304 305struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family", 306 NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser); 307 308struct pkw *family_users[] = {&family_only, &family, &silent_family}; 309 310struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps, 311 "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser); 312 313struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags, 314 "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser); 315 316struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command, 317 "clonecmd", clonekw, __arraycount(clonekw), NULL); 318 319struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL, 320 misckw, __arraycount(misckw), NULL); 321 322struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone, 323 "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true); 324 325struct 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 329struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family, 330 "opt-family", opt_family_brs, __arraycount(opt_family_brs), true); 331 332struct piface iface_start = PIFACE_INITIALIZER(&iface_start, 333 "iface-opt-family", NULL, "if", &opt_clone.pb_parser); 334 335struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface", 336 media_status_exec, "if", NULL); 337 338static bool 339flag_is_registered(const char *flags, int flag) 340{ 341 return flags != NULL && strchr(flags, flag) != NULL; 342} 343 344static int 345check_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 363void 364cmdloop_branch_init(cmdloop_branch_t *b, struct parser *p) 365{ 366 b->b_parser = p; 367} 368 369void 370statistics_func_init(statistics_func_t *f, statistics_cb_t func) 371{ 372 f->f_func = func; 373} 374 375void 376status_func_init(status_func_t *f, status_cb_t func) 377{ 378 f->f_func = func; 379} 380 381void 382usage_func_init(usage_func_t *f, usage_cb_t func) 383{ 384 f->f_func = func; 385} 386 387int 388register_cmdloop_branch(cmdloop_branch_t *b) 389{ 390 SIMPLEQ_INSERT_TAIL(&cmdloop_branches, b, b_next); 391 return 0; 392} 393 394int 395register_statistics(statistics_func_t *f) 396{ 397 SIMPLEQ_INSERT_TAIL(&statistics_funcs, f, f_next); 398 return 0; 399} 400 401int 402register_status(status_func_t *f) 403{ 404 SIMPLEQ_INSERT_TAIL(&status_funcs, f, f_next); 405 return 0; 406} 407 408int 409register_usage(usage_func_t *f) 410{ 411 SIMPLEQ_INSERT_TAIL(&usage_funcs, f, f_next); 412 return 0; 413} 414 415int 416register_family(struct afswtch *af) 417{ 418 SIMPLEQ_INSERT_TAIL(&aflist, af, af_next); 419 return 0; 420} 421 422int 423register_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 438static int 439flag_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 452static bool 453set_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 463bool 464get_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 474static struct parser * 475init_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 492static int 493no_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 508static int 509media_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 523static void 524do_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 540int 541main(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 'v': 625 case 'z': 626 if (start != &opt_family_only.pb_parser) 627 start = &iface_opt_family_only.pif_parser; 628 break; 629 case 'C': 630 start = &cloneterm.pt_parser; 631 break; 632 case 'l': 633 start = &no_cmds.pt_parser; 634 break; 635 case 's': 636 if (start != &no_cmds.pt_parser && 637 start != &opt_family_only.pb_parser) 638 start = &iface_only.pif_parser; 639 break; 640 default: 641 break; 642 } 643 } 644 argc -= optind; 645 argv += optind; 646 647 /* 648 * -l means "list all interfaces", and is mutally exclusive with 649 * all other flags/commands. 650 * 651 * -C means "list all names of cloners", and it mutually exclusive 652 * with all other flags/commands. 653 * 654 * -a means "print status of all interfaces". 655 */ 656 if ((lflag || Cflag) && (aflag || get_flag('m') || vflag || zflag)) 657 usage(); 658 if ((lflag || Cflag) && get_flag('L')) 659 usage(); 660 if (lflag && Cflag) 661 usage(); 662 663 nmatch = __arraycount(match); 664 665 rc = parse(argc, argv, start, match, &nmatch, &narg); 666 if (rc != 0) 667 usage(); 668 669 if (prog_init && prog_init() == -1) 670 err(1, "rump client init"); 671 672 if ((oenv = prop_dictionary_create()) == NULL) 673 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 674 675 if (matches_exec(match, oenv, nmatch) == -1) 676 err(EXIT_FAILURE, "exec_matches"); 677 678 argc -= narg; 679 argv += narg; 680 681 env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL; 682 if (env == NULL) 683 env = oenv; 684 else 685 env = prop_dictionary_augment(env, oenv); 686 687 /* Process any media commands that may have been issued. */ 688 process_media_commands(env); 689 690 if ((af = getaf(env)) == -1) 691 af = AF_INET; 692 693 if ((s = getsock(af)) == -1) 694 err(EXIT_FAILURE, "%s: getsock", __func__); 695 696 if ((ifname = getifname(env)) == NULL) 697 err(EXIT_FAILURE, "%s: getifname", __func__); 698 699 if ((afp = lookup_af_bynum(af)) == NULL) 700 errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__); 701 702 assert(afp->af_addr_commit != NULL); 703 (*afp->af_addr_commit)(env, oenv); 704 705 do_setifpreference(env); 706 do_setifcaps(env); 707 708 exit(EXIT_SUCCESS); 709} 710 711static void 712init_afs(void) 713{ 714 size_t i; 715 const struct afswtch *afp; 716 struct kwinst kw = {.k_type = KW_T_INT}; 717 718 SIMPLEQ_FOREACH(afp, &aflist, af_next) { 719 kw.k_word = afp->af_name; 720 kw.k_int = afp->af_af; 721 for (i = 0; i < __arraycount(familykw); i++) { 722 if (familykw[i].k_word == NULL) { 723 familykw[i] = kw; 724 break; 725 } 726 } 727 } 728} 729 730const struct afswtch * 731lookup_af_bynum(int afnum) 732{ 733 const struct afswtch *afp; 734 735 SIMPLEQ_FOREACH(afp, &aflist, af_next) { 736 if (afp->af_af == afnum) 737 break; 738 } 739 return afp; 740} 741 742void 743printall(const char *ifname, prop_dictionary_t env0) 744{ 745 struct ifaddrs *ifap, *ifa; 746 struct ifreq ifr; 747 const struct sockaddr *sdl = NULL; 748 prop_dictionary_t env, oenv; 749 int idx; 750 char *p; 751 752 if (env0 == NULL) 753 env = prop_dictionary_create(); 754 else 755 env = prop_dictionary_copy_mutable(env0); 756 757 oenv = prop_dictionary_create(); 758 759 if (env == NULL || oenv == NULL) 760 errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__); 761 762 if (getifaddrs(&ifap) != 0) 763 err(EXIT_FAILURE, "getifaddrs"); 764 p = NULL; 765 idx = 0; 766 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 767 memset(&ifr, 0, sizeof(ifr)); 768 estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); 769 if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 770 memcpy(&ifr.ifr_addr, ifa->ifa_addr, 771 ifa->ifa_addr->sa_len); 772 } 773 774 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) 775 continue; 776 if (ifa->ifa_addr->sa_family == AF_LINK) 777 sdl = ifa->ifa_addr; 778 if (p && strcmp(p, ifa->ifa_name) == 0) 779 continue; 780 if (!prop_dictionary_set_cstring(env, "if", ifa->ifa_name)) 781 continue; 782 p = ifa->ifa_name; 783 784 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0) 785 continue; 786 if (dflag && (ifa->ifa_flags & IFF_UP) != 0) 787 continue; 788 if (uflag && (ifa->ifa_flags & IFF_UP) == 0) 789 continue; 790 791 if (sflag && carrier(env)) 792 continue; 793 idx++; 794 /* 795 * Are we just listing the interfaces? 796 */ 797 if (lflag) { 798 if (idx > 1) 799 printf(" "); 800 fputs(ifa->ifa_name, stdout); 801 continue; 802 } 803 804 status(sdl, env, oenv); 805 sdl = NULL; 806 } 807 if (lflag) 808 printf("\n"); 809 prop_object_release((prop_object_t)env); 810 prop_object_release((prop_object_t)oenv); 811 freeifaddrs(ifap); 812} 813 814static int 815list_cloners(prop_dictionary_t env, prop_dictionary_t oenv) 816{ 817 struct if_clonereq ifcr; 818 char *cp, *buf; 819 int idx, s; 820 821 memset(&ifcr, 0, sizeof(ifcr)); 822 823 s = getsock(AF_INET); 824 825 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 826 err(EXIT_FAILURE, "SIOCIFGCLONERS for count"); 827 828 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 829 if (buf == NULL) 830 err(EXIT_FAILURE, "unable to allocate cloner name buffer"); 831 832 ifcr.ifcr_count = ifcr.ifcr_total; 833 ifcr.ifcr_buffer = buf; 834 835 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 836 err(EXIT_FAILURE, "SIOCIFGCLONERS for names"); 837 838 /* 839 * In case some disappeared in the mean time, clamp it down. 840 */ 841 if (ifcr.ifcr_count > ifcr.ifcr_total) 842 ifcr.ifcr_count = ifcr.ifcr_total; 843 844 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 845 if (idx > 0) 846 printf(" "); 847 printf("%s", cp); 848 } 849 850 printf("\n"); 851 free(buf); 852 exit(EXIT_SUCCESS); 853} 854 855static int 856clone_command(prop_dictionary_t env, prop_dictionary_t oenv) 857{ 858 int64_t cmd; 859 860 if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) { 861 errno = ENOENT; 862 return -1; 863 } 864 865 if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) { 866 warn("%s", __func__); 867 return -1; 868 } 869 return 0; 870} 871 872/*ARGSUSED*/ 873static int 874setifaddr(prop_dictionary_t env, prop_dictionary_t oenv) 875{ 876 const struct paddr_prefix *pfx0; 877 struct paddr_prefix *pfx; 878 prop_data_t d; 879 int af; 880 881 if ((af = getaf(env)) == -1) 882 af = AF_INET; 883 884 d = (prop_data_t)prop_dictionary_get(env, "address"); 885 assert(d != NULL); 886 pfx0 = prop_data_data_nocopy(d); 887 888 if (pfx0->pfx_len >= 0) { 889 pfx = prefixlen_to_mask(af, pfx0->pfx_len); 890 if (pfx == NULL) 891 err(EXIT_FAILURE, "prefixlen_to_mask"); 892 free(pfx); 893 } 894 895 return 0; 896} 897 898static int 899setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv) 900{ 901 const struct paddr_prefix *pfx; 902 prop_data_t d; 903 904 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 905 assert(d != NULL); 906 pfx = prop_data_data_nocopy(d); 907 908 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 909 return -1; 910 911 return 0; 912} 913 914static int 915setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv) 916{ 917 const struct paddr_prefix *pfx; 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 pfx = prop_data_data_nocopy(d); 930 931 if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d)) 932 return -1; 933 934 return 0; 935} 936 937/*ARGSUSED*/ 938static int 939notrailers(prop_dictionary_t env, prop_dictionary_t oenv) 940{ 941 puts("Note: trailers are no longer sent, but always received"); 942 return 0; 943} 944 945/*ARGSUSED*/ 946static int 947setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv) 948{ 949 const char *key; 950 const struct paddr_prefix *pfx; 951 prop_data_t d; 952 unsigned short flags; 953 954 if (getifflags(env, oenv, &flags) == -1) 955 err(EXIT_FAILURE, "%s: getifflags", __func__); 956 957 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 958 assert(d != NULL); 959 pfx = prop_data_data_nocopy(d); 960 961 if ((flags & IFF_BROADCAST) == 0) { 962 key = "dst"; 963 } else { 964 key = "netmask"; 965 } 966 967 if (!prop_dictionary_set(oenv, key, (prop_object_t)d)) 968 return -1; 969 970 return 0; 971} 972 973static int 974setifflags(prop_dictionary_t env, prop_dictionary_t oenv) 975{ 976 struct ifreq ifr; 977 int64_t ifflag; 978 bool rc; 979 980 rc = prop_dictionary_get_int64(env, "ifflag", &ifflag); 981 assert(rc); 982 983 if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) 984 return -1; 985 986 if (ifflag < 0) { 987 ifflag = -ifflag; 988 ifr.ifr_flags &= ~ifflag; 989 } else 990 ifr.ifr_flags |= ifflag; 991 992 if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1) 993 return -1; 994 995 return 0; 996} 997 998static int 999getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr) 1000{ 1001 bool rc; 1002 struct ifcapreq ifcr; 1003 const struct ifcapreq *tmpifcr; 1004 prop_data_t capdata; 1005 1006 capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps"); 1007 1008 if (capdata != NULL) { 1009 tmpifcr = prop_data_data_nocopy(capdata); 1010 *oifcr = *tmpifcr; 1011 return 0; 1012 } 1013 1014 (void)direct_ioctl(env, SIOCGIFCAP, &ifcr); 1015 *oifcr = ifcr; 1016 1017 capdata = prop_data_create_data(&ifcr, sizeof(ifcr)); 1018 1019 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1020 1021 prop_object_release((prop_object_t)capdata); 1022 1023 return rc ? 0 : -1; 1024} 1025 1026static int 1027setifcaps(prop_dictionary_t env, prop_dictionary_t oenv) 1028{ 1029 int64_t ifcap; 1030 int s; 1031 bool rc; 1032 prop_data_t capdata; 1033 struct ifcapreq ifcr; 1034 1035 s = getsock(AF_INET); 1036 1037 rc = prop_dictionary_get_int64(env, "ifcap", &ifcap); 1038 assert(rc); 1039 1040 if (getifcaps(env, oenv, &ifcr) == -1) 1041 return -1; 1042 1043 if (ifcap < 0) { 1044 ifcap = -ifcap; 1045 ifcr.ifcr_capenable &= ~ifcap; 1046 } else 1047 ifcr.ifcr_capenable |= ifcap; 1048 1049 if ((capdata = prop_data_create_data(&ifcr, sizeof(ifcr))) == NULL) 1050 return -1; 1051 1052 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1053 prop_object_release((prop_object_t)capdata); 1054 1055 return rc ? 0 : -1; 1056} 1057 1058static int 1059setifmetric(prop_dictionary_t env, prop_dictionary_t oenv) 1060{ 1061 struct ifreq ifr; 1062 bool rc; 1063 int64_t metric; 1064 1065 rc = prop_dictionary_get_int64(env, "metric", &metric); 1066 assert(rc); 1067 1068 ifr.ifr_metric = metric; 1069 if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1) 1070 warn("SIOCSIFMETRIC"); 1071 return 0; 1072} 1073 1074static void 1075do_setifpreference(prop_dictionary_t env) 1076{ 1077 struct if_addrprefreq ifap; 1078 prop_data_t d; 1079 const struct paddr_prefix *pfx; 1080 1081 memset(&ifap, 0, sizeof(ifap)); 1082 1083 if (!prop_dictionary_get_int16(env, "preference", 1084 &ifap.ifap_preference)) 1085 return; 1086 1087 d = (prop_data_t)prop_dictionary_get(env, "address"); 1088 assert(d != NULL); 1089 1090 pfx = prop_data_data_nocopy(d); 1091 1092 memcpy(&ifap.ifap_addr, &pfx->pfx_addr, 1093 MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len)); 1094 if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1) 1095 warn("SIOCSIFADDRPREF"); 1096} 1097 1098static int 1099setifmtu(prop_dictionary_t env, prop_dictionary_t oenv) 1100{ 1101 int64_t mtu; 1102 bool rc; 1103 struct ifreq ifr; 1104 1105 rc = prop_dictionary_get_int64(env, "mtu", &mtu); 1106 assert(rc); 1107 1108 ifr.ifr_mtu = mtu; 1109 if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1) 1110 warn("SIOCSIFMTU"); 1111 1112 return 0; 1113} 1114 1115static int 1116carrier(prop_dictionary_t env) 1117{ 1118 struct ifmediareq ifmr; 1119 1120 memset(&ifmr, 0, sizeof(ifmr)); 1121 1122 if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) { 1123 /* 1124 * Interface doesn't support SIOC{G,S}IFMEDIA; 1125 * assume ok. 1126 */ 1127 return EXIT_SUCCESS; 1128 } 1129 if ((ifmr.ifm_status & IFM_AVALID) == 0) { 1130 /* 1131 * Interface doesn't report media-valid status. 1132 * assume ok. 1133 */ 1134 return EXIT_SUCCESS; 1135 } 1136 /* otherwise, return ok for active, not-ok if not active. */ 1137 if (ifmr.ifm_status & IFM_ACTIVE) 1138 return EXIT_SUCCESS; 1139 else 1140 return EXIT_FAILURE; 1141} 1142 1143static void 1144print_plural(const char *prefix, uint64_t n, const char *unit) 1145{ 1146 printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s"); 1147} 1148 1149static void 1150print_human_bytes(bool humanize, uint64_t n) 1151{ 1152 char buf[5]; 1153 1154 if (humanize) { 1155 (void)humanize_number(buf, sizeof(buf), 1156 (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); 1157 printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s"); 1158 } else 1159 print_plural(", ", n, "byte"); 1160} 1161 1162/* 1163 * Print the status of the interface. If an address family was 1164 * specified, show it and it only; otherwise, show them all. 1165 */ 1166void 1167status(const struct sockaddr *sdl, prop_dictionary_t env, 1168 prop_dictionary_t oenv) 1169{ 1170 const struct if_data *ifi; 1171 status_func_t *status_f; 1172 statistics_func_t *statistics_f; 1173 struct ifdatareq ifdr; 1174 struct ifreq ifr; 1175 struct ifdrv ifdrv; 1176 char fbuf[BUFSIZ]; 1177 int af, s; 1178 const char *ifname; 1179 struct ifcapreq ifcr; 1180 unsigned short flags; 1181 const struct afswtch *afp; 1182 1183 if ((af = getaf(env)) == -1) { 1184 afp = NULL; 1185 af = AF_UNSPEC; 1186 } else 1187 afp = lookup_af_bynum(af); 1188 1189 /* get out early if the family is unsupported by the kernel */ 1190 if ((s = getsock(af)) == -1) 1191 err(EXIT_FAILURE, "%s: getsock", __func__); 1192 1193 if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 1194 err(EXIT_FAILURE, "%s: getifinfo", __func__); 1195 1196 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags); 1197 printf("%s: flags=%s", ifname, &fbuf[2]); 1198 1199 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1200 if (prog_ioctl(s, SIOCGIFMETRIC, &ifr) == -1) 1201 warn("SIOCGIFMETRIC %s", ifr.ifr_name); 1202 else if (ifr.ifr_metric != 0) 1203 printf(" metric %d", ifr.ifr_metric); 1204 1205 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1206 if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0) 1207 printf(" mtu %d", ifr.ifr_mtu); 1208 printf("\n"); 1209 1210 if (getifcaps(env, oenv, &ifcr) == -1) 1211 err(EXIT_FAILURE, "%s: getifcaps", __func__); 1212 1213 if (ifcr.ifcr_capabilities != 0) { 1214 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 1215 ifcr.ifcr_capabilities); 1216 printf("\tcapabilities=%s\n", &fbuf[2]); 1217 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 1218 ifcr.ifcr_capenable); 1219 printf("\tenabled=%s\n", &fbuf[2]); 1220 } 1221 1222 SIMPLEQ_FOREACH(status_f, &status_funcs, f_next) 1223 (*status_f->f_func)(env, oenv); 1224 1225 print_link_addresses(env, true); 1226 1227 estrlcpy(ifdrv.ifd_name, ifname, sizeof(ifdrv.ifd_name)); 1228 ifdrv.ifd_cmd = IFLINKSTR_QUERYLEN; 1229 ifdrv.ifd_len = 0; 1230 ifdrv.ifd_data = NULL; 1231 /* interface supports linkstr? */ 1232 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) != -1) { 1233 char *p; 1234 1235 p = malloc(ifdrv.ifd_len); 1236 if (p == NULL) 1237 err(EXIT_FAILURE, "malloc linkstr buf failed"); 1238 ifdrv.ifd_data = p; 1239 ifdrv.ifd_cmd = 0; 1240 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) == -1) 1241 err(EXIT_FAILURE, "failed to query linkstr"); 1242 printf("\tlinkstr: %s\n", (char *)ifdrv.ifd_data); 1243 free(p); 1244 } 1245 1246 media_status(env, oenv); 1247 1248 if (!vflag && !zflag) 1249 goto proto_status; 1250 1251 estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 1252 1253 if (prog_ioctl(s, zflag ? SIOCZIFDATA : SIOCGIFDATA, &ifdr) == -1) 1254 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA"); 1255 1256 ifi = &ifdr.ifdr_data; 1257 1258 print_plural("\tinput: ", ifi->ifi_ipackets, "packet"); 1259 print_human_bytes(hflag, ifi->ifi_ibytes); 1260 if (ifi->ifi_imcasts) 1261 print_plural(", ", ifi->ifi_imcasts, "multicast"); 1262 if (ifi->ifi_ierrors) 1263 print_plural(", ", ifi->ifi_ierrors, "error"); 1264 if (ifi->ifi_iqdrops) 1265 print_plural(", ", ifi->ifi_iqdrops, "queue drop"); 1266 if (ifi->ifi_noproto) 1267 printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto); 1268 print_plural("\n\toutput: ", ifi->ifi_opackets, "packet"); 1269 print_human_bytes(hflag, ifi->ifi_obytes); 1270 if (ifi->ifi_omcasts) 1271 print_plural(", ", ifi->ifi_omcasts, "multicast"); 1272 if (ifi->ifi_oerrors) 1273 print_plural(", ", ifi->ifi_oerrors, "error"); 1274 if (ifi->ifi_collisions) 1275 print_plural(", ", ifi->ifi_collisions, "collision"); 1276 printf("\n"); 1277 1278 SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next) 1279 (*statistics_f->f_func)(env); 1280 1281 proto_status: 1282 1283 if (afp != NULL) 1284 (*afp->af_status)(env, oenv, true); 1285 else SIMPLEQ_FOREACH(afp, &aflist, af_next) 1286 (*afp->af_status)(env, oenv, false); 1287} 1288 1289static int 1290setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv) 1291{ 1292 bool rc; 1293 int64_t plen; 1294 int af; 1295 struct paddr_prefix *pfx; 1296 prop_data_t d; 1297 1298 if ((af = getaf(env)) == -1) 1299 af = AF_INET; 1300 1301 rc = prop_dictionary_get_int64(env, "prefixlen", &plen); 1302 assert(rc); 1303 1304 pfx = prefixlen_to_mask(af, plen); 1305 if (pfx == NULL) 1306 err(EXIT_FAILURE, "prefixlen_to_mask"); 1307 1308 d = prop_data_create_data(pfx, paddr_prefix_size(pfx)); 1309 if (d == NULL) 1310 err(EXIT_FAILURE, "%s: prop_data_create_data", __func__); 1311 1312 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 1313 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 1314 1315 free(pfx); 1316 return 0; 1317} 1318 1319static int 1320setlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1321{ 1322 struct ifdrv ifdrv; 1323 size_t linkstrlen; 1324 prop_data_t data; 1325 char *linkstr; 1326 1327 data = (prop_data_t)prop_dictionary_get(env, "linkstr"); 1328 if (data == NULL) { 1329 errno = ENOENT; 1330 return -1; 1331 } 1332 linkstrlen = prop_data_size(data)+1; 1333 1334 linkstr = malloc(linkstrlen); 1335 if (linkstr == NULL) 1336 err(EXIT_FAILURE, "malloc linkstr space"); 1337 if (getargstr(env, "linkstr", linkstr, linkstrlen) == -1) 1338 errx(EXIT_FAILURE, "getargstr linkstr failed"); 1339 1340 ifdrv.ifd_cmd = 0; 1341 ifdrv.ifd_len = linkstrlen; 1342 ifdrv.ifd_data = __UNCONST(linkstr); 1343 1344 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1345 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1346 free(linkstr); 1347 1348 return 0; 1349} 1350 1351static int 1352unsetlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1353{ 1354 struct ifdrv ifdrv; 1355 1356 memset(&ifdrv, 0, sizeof(ifdrv)); 1357 ifdrv.ifd_cmd = IFLINKSTR_UNSET; 1358 1359 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1360 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1361 1362 return 0; 1363} 1364 1365static void 1366usage(void) 1367{ 1368 const char *progname = getprogname(); 1369 usage_func_t *usage_f; 1370 prop_dictionary_t env; 1371 1372 if ((env = prop_dictionary_create()) == NULL) 1373 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 1374 1375 fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n" 1376 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n" 1377 "\t\t[ alias | -alias ] ]\n" 1378 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname, 1379 flag_is_registered(gflags, 'm') ? "[-m] " : "", 1380 flag_is_registered(gflags, 'L') ? "[-L] " : ""); 1381 1382 SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next) 1383 (*usage_f->f_func)(env); 1384 1385 fprintf(stderr, 1386 "\t[ arp | -arp ]\n" 1387 "\t[ preference n ]\n" 1388 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n" 1389 " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n" 1390 " %s -l [-b] [-d] [-s] [-u]\n" 1391 " %s -C\n" 1392 " %s interface create\n" 1393 " %s interface destroy\n", 1394 progname, flag_is_registered(gflags, 'm') ? "[-m] " : "", 1395 progname, progname, progname, progname); 1396 1397 prop_object_release((prop_object_t)env); 1398 exit(EXIT_FAILURE); 1399} 1400