ifconfig.c revision 1.225
1/* $NetBSD: ifconfig.c,v 1.225 2010/12/14 10:51:51 pooka 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.225 2010/12/14 10:51:51 pooka 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); 134static 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 aflag = Nflag = vflag = zflag = false; 561 while ((ch = getopt(argc, argv, gflags)) != -1) { 562 switch (ch) { 563 case 'A': 564 warnx("-A is deprecated"); 565 break; 566 567 case 'a': 568 aflag = true; 569 break; 570 571 case 'b': 572 bflag = true; 573 break; 574 575 case 'C': 576 Cflag = true; 577 break; 578 579 case 'd': 580 dflag = true; 581 break; 582 case 'h': 583 hflag = true; 584 break; 585 case 'l': 586 lflag = true; 587 break; 588 case 'N': 589 Nflag = true; 590 break; 591 592 case 's': 593 sflag = true; 594 break; 595 596 case 'u': 597 uflag = true; 598 break; 599 600 case 'v': 601 vflag = true; 602 break; 603 604 case 'z': 605 zflag = true; 606 break; 607 608 default: 609 if (!set_flag(ch)) 610 usage(); 611 break; 612 } 613 switch (ch) { 614 case 'a': 615 start = &opt_family_only.pb_parser; 616 break; 617 618 case 'L': 619 case 'm': 620 case 'v': 621 case 'z': 622 if (start != &opt_family_only.pb_parser) 623 start = &iface_opt_family_only.pif_parser; 624 break; 625 case 'C': 626 start = &cloneterm.pt_parser; 627 break; 628 case 'l': 629 start = &no_cmds.pt_parser; 630 break; 631 case 's': 632 if (start != &no_cmds.pt_parser && 633 start != &opt_family_only.pb_parser) 634 start = &iface_only.pif_parser; 635 break; 636 default: 637 break; 638 } 639 } 640 argc -= optind; 641 argv += optind; 642 643 /* 644 * -l means "list all interfaces", and is mutally exclusive with 645 * all other flags/commands. 646 * 647 * -C means "list all names of cloners", and it mutually exclusive 648 * with all other flags/commands. 649 * 650 * -a means "print status of all interfaces". 651 */ 652 if ((lflag || Cflag) && (aflag || get_flag('m') || vflag || zflag)) 653 usage(); 654 if ((lflag || Cflag) && get_flag('L')) 655 usage(); 656 if (lflag && Cflag) 657 usage(); 658 659 nmatch = __arraycount(match); 660 661 rc = parse(argc, argv, start, match, &nmatch, &narg); 662 if (rc != 0) 663 usage(); 664 665 if (prog_init && prog_init() == -1) 666 err(1, "rump client init"); 667 668 if ((oenv = prop_dictionary_create()) == NULL) 669 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 670 671 if (matches_exec(match, oenv, nmatch) == -1) 672 err(EXIT_FAILURE, "exec_matches"); 673 674 argc -= narg; 675 argv += narg; 676 677 env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL; 678 if (env == NULL) 679 env = oenv; 680 else 681 env = prop_dictionary_augment(env, oenv); 682 683 /* Process any media commands that may have been issued. */ 684 process_media_commands(env); 685 686 if ((af = getaf(env)) == -1) 687 af = AF_INET; 688 689 if ((s = getsock(af)) == -1) 690 err(EXIT_FAILURE, "%s: getsock", __func__); 691 692 if ((ifname = getifname(env)) == NULL) 693 err(EXIT_FAILURE, "%s: getifname", __func__); 694 695 if ((afp = lookup_af_bynum(af)) == NULL) 696 errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__); 697 698 assert(afp->af_addr_commit != NULL); 699 (*afp->af_addr_commit)(env, oenv); 700 701 do_setifpreference(env); 702 do_setifcaps(env); 703 704 exit(EXIT_SUCCESS); 705} 706 707static void 708init_afs(void) 709{ 710 size_t i; 711 const struct afswtch *afp; 712 struct kwinst kw = {.k_type = KW_T_INT}; 713 714 SIMPLEQ_FOREACH(afp, &aflist, af_next) { 715 kw.k_word = afp->af_name; 716 kw.k_int = afp->af_af; 717 for (i = 0; i < __arraycount(familykw); i++) { 718 if (familykw[i].k_word == NULL) { 719 familykw[i] = kw; 720 break; 721 } 722 } 723 } 724} 725 726const struct afswtch * 727lookup_af_bynum(int afnum) 728{ 729 const struct afswtch *afp; 730 731 SIMPLEQ_FOREACH(afp, &aflist, af_next) { 732 if (afp->af_af == afnum) 733 break; 734 } 735 return afp; 736} 737 738void 739printall(const char *ifname, prop_dictionary_t env0) 740{ 741 struct ifaddrs *ifap, *ifa; 742 struct ifreq ifr; 743 const struct sockaddr *sdl = NULL; 744 prop_dictionary_t env, oenv; 745 int idx; 746 char *p; 747 748 if (env0 == NULL) 749 env = prop_dictionary_create(); 750 else 751 env = prop_dictionary_copy_mutable(env0); 752 753 oenv = prop_dictionary_create(); 754 755 if (env == NULL || oenv == NULL) 756 errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__); 757 758 if (getifaddrs(&ifap) != 0) 759 err(EXIT_FAILURE, "getifaddrs"); 760 p = NULL; 761 idx = 0; 762 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 763 memset(&ifr, 0, sizeof(ifr)); 764 estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); 765 if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 766 memcpy(&ifr.ifr_addr, ifa->ifa_addr, 767 ifa->ifa_addr->sa_len); 768 } 769 770 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) 771 continue; 772 if (ifa->ifa_addr->sa_family == AF_LINK) 773 sdl = ifa->ifa_addr; 774 if (p && strcmp(p, ifa->ifa_name) == 0) 775 continue; 776 if (!prop_dictionary_set_cstring(env, "if", ifa->ifa_name)) 777 continue; 778 p = ifa->ifa_name; 779 780 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0) 781 continue; 782 if (dflag && (ifa->ifa_flags & IFF_UP) != 0) 783 continue; 784 if (uflag && (ifa->ifa_flags & IFF_UP) == 0) 785 continue; 786 787 if (sflag && carrier(env)) 788 continue; 789 idx++; 790 /* 791 * Are we just listing the interfaces? 792 */ 793 if (lflag) { 794 if (idx > 1) 795 printf(" "); 796 fputs(ifa->ifa_name, stdout); 797 continue; 798 } 799 800 status(sdl, env, oenv); 801 sdl = NULL; 802 } 803 if (lflag) 804 printf("\n"); 805 prop_object_release((prop_object_t)env); 806 prop_object_release((prop_object_t)oenv); 807 freeifaddrs(ifap); 808} 809 810static int 811list_cloners(prop_dictionary_t env, prop_dictionary_t oenv) 812{ 813 struct if_clonereq ifcr; 814 char *cp, *buf; 815 int idx, s; 816 817 memset(&ifcr, 0, sizeof(ifcr)); 818 819 s = getsock(AF_INET); 820 821 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 822 err(EXIT_FAILURE, "SIOCIFGCLONERS for count"); 823 824 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 825 if (buf == NULL) 826 err(EXIT_FAILURE, "unable to allocate cloner name buffer"); 827 828 ifcr.ifcr_count = ifcr.ifcr_total; 829 ifcr.ifcr_buffer = buf; 830 831 if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 832 err(EXIT_FAILURE, "SIOCIFGCLONERS for names"); 833 834 /* 835 * In case some disappeared in the mean time, clamp it down. 836 */ 837 if (ifcr.ifcr_count > ifcr.ifcr_total) 838 ifcr.ifcr_count = ifcr.ifcr_total; 839 840 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 841 if (idx > 0) 842 printf(" "); 843 printf("%s", cp); 844 } 845 846 printf("\n"); 847 free(buf); 848 exit(EXIT_SUCCESS); 849} 850 851static int 852clone_command(prop_dictionary_t env, prop_dictionary_t oenv) 853{ 854 int64_t cmd; 855 856 if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) { 857 errno = ENOENT; 858 return -1; 859 } 860 861 if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) { 862 warn("%s", __func__); 863 return -1; 864 } 865 return 0; 866} 867 868/*ARGSUSED*/ 869static int 870setifaddr(prop_dictionary_t env, prop_dictionary_t oenv) 871{ 872 const struct paddr_prefix *pfx0; 873 struct paddr_prefix *pfx; 874 prop_data_t d; 875 int af; 876 877 if ((af = getaf(env)) == -1) 878 af = AF_INET; 879 880 d = (prop_data_t)prop_dictionary_get(env, "address"); 881 assert(d != NULL); 882 pfx0 = prop_data_data_nocopy(d); 883 884 if (pfx0->pfx_len >= 0) { 885 pfx = prefixlen_to_mask(af, pfx0->pfx_len); 886 if (pfx == NULL) 887 err(EXIT_FAILURE, "prefixlen_to_mask"); 888 free(pfx); 889 } 890 891 return 0; 892} 893 894static int 895setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv) 896{ 897 const struct paddr_prefix *pfx; 898 prop_data_t d; 899 900 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 901 assert(d != NULL); 902 pfx = prop_data_data_nocopy(d); 903 904 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 905 return -1; 906 907 return 0; 908} 909 910static int 911setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv) 912{ 913 const struct paddr_prefix *pfx; 914 prop_data_t d; 915 unsigned short flags; 916 917 if (getifflags(env, oenv, &flags) == -1) 918 err(EXIT_FAILURE, "%s: getifflags", __func__); 919 920 if ((flags & IFF_BROADCAST) == 0) 921 errx(EXIT_FAILURE, "not a broadcast interface"); 922 923 d = (prop_data_t)prop_dictionary_get(env, "broadcast"); 924 assert(d != NULL); 925 pfx = prop_data_data_nocopy(d); 926 927 if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d)) 928 return -1; 929 930 return 0; 931} 932 933/*ARGSUSED*/ 934static int 935notrailers(prop_dictionary_t env, prop_dictionary_t oenv) 936{ 937 puts("Note: trailers are no longer sent, but always received"); 938 return 0; 939} 940 941/*ARGSUSED*/ 942static int 943setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv) 944{ 945 const char *key; 946 const struct paddr_prefix *pfx; 947 prop_data_t d; 948 unsigned short flags; 949 950 if (getifflags(env, oenv, &flags) == -1) 951 err(EXIT_FAILURE, "%s: getifflags", __func__); 952 953 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 954 assert(d != NULL); 955 pfx = prop_data_data_nocopy(d); 956 957 if ((flags & IFF_BROADCAST) == 0) { 958 key = "dst"; 959 } else { 960 key = "netmask"; 961 } 962 963 if (!prop_dictionary_set(oenv, key, (prop_object_t)d)) 964 return -1; 965 966 return 0; 967} 968 969static int 970setifflags(prop_dictionary_t env, prop_dictionary_t oenv) 971{ 972 struct ifreq ifr; 973 int64_t ifflag; 974 bool rc; 975 976 rc = prop_dictionary_get_int64(env, "ifflag", &ifflag); 977 assert(rc); 978 979 if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) 980 return -1; 981 982 if (ifflag < 0) { 983 ifflag = -ifflag; 984 ifr.ifr_flags &= ~ifflag; 985 } else 986 ifr.ifr_flags |= ifflag; 987 988 if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1) 989 return -1; 990 991 return 0; 992} 993 994static int 995getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr) 996{ 997 bool rc; 998 struct ifcapreq ifcr; 999 const struct ifcapreq *tmpifcr; 1000 prop_data_t capdata; 1001 1002 capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps"); 1003 1004 if (capdata != NULL) { 1005 tmpifcr = prop_data_data_nocopy(capdata); 1006 *oifcr = *tmpifcr; 1007 return 0; 1008 } 1009 1010 (void)direct_ioctl(env, SIOCGIFCAP, &ifcr); 1011 *oifcr = ifcr; 1012 1013 capdata = prop_data_create_data(&ifcr, sizeof(ifcr)); 1014 1015 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1016 1017 prop_object_release((prop_object_t)capdata); 1018 1019 return rc ? 0 : -1; 1020} 1021 1022static int 1023setifcaps(prop_dictionary_t env, prop_dictionary_t oenv) 1024{ 1025 int64_t ifcap; 1026 int s; 1027 bool rc; 1028 prop_data_t capdata; 1029 struct ifcapreq ifcr; 1030 1031 s = getsock(AF_INET); 1032 1033 rc = prop_dictionary_get_int64(env, "ifcap", &ifcap); 1034 assert(rc); 1035 1036 if (getifcaps(env, oenv, &ifcr) == -1) 1037 return -1; 1038 1039 if (ifcap < 0) { 1040 ifcap = -ifcap; 1041 ifcr.ifcr_capenable &= ~ifcap; 1042 } else 1043 ifcr.ifcr_capenable |= ifcap; 1044 1045 if ((capdata = prop_data_create_data(&ifcr, sizeof(ifcr))) == NULL) 1046 return -1; 1047 1048 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1049 prop_object_release((prop_object_t)capdata); 1050 1051 return rc ? 0 : -1; 1052} 1053 1054static int 1055setifmetric(prop_dictionary_t env, prop_dictionary_t oenv) 1056{ 1057 struct ifreq ifr; 1058 bool rc; 1059 int64_t metric; 1060 1061 rc = prop_dictionary_get_int64(env, "metric", &metric); 1062 assert(rc); 1063 1064 ifr.ifr_metric = metric; 1065 if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1) 1066 warn("SIOCSIFMETRIC"); 1067 return 0; 1068} 1069 1070static void 1071do_setifpreference(prop_dictionary_t env) 1072{ 1073 struct if_addrprefreq ifap; 1074 prop_data_t d; 1075 const struct paddr_prefix *pfx; 1076 1077 memset(&ifap, 0, sizeof(ifap)); 1078 1079 if (!prop_dictionary_get_int16(env, "preference", 1080 &ifap.ifap_preference)) 1081 return; 1082 1083 d = (prop_data_t)prop_dictionary_get(env, "address"); 1084 assert(d != NULL); 1085 1086 pfx = prop_data_data_nocopy(d); 1087 1088 memcpy(&ifap.ifap_addr, &pfx->pfx_addr, 1089 MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len)); 1090 if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1) 1091 warn("SIOCSIFADDRPREF"); 1092} 1093 1094static int 1095setifmtu(prop_dictionary_t env, prop_dictionary_t oenv) 1096{ 1097 int64_t mtu; 1098 bool rc; 1099 struct ifreq ifr; 1100 1101 rc = prop_dictionary_get_int64(env, "mtu", &mtu); 1102 assert(rc); 1103 1104 ifr.ifr_mtu = mtu; 1105 if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1) 1106 warn("SIOCSIFMTU"); 1107 1108 return 0; 1109} 1110 1111static int 1112carrier(prop_dictionary_t env) 1113{ 1114 struct ifmediareq ifmr; 1115 1116 memset(&ifmr, 0, sizeof(ifmr)); 1117 1118 if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) { 1119 /* 1120 * Interface doesn't support SIOC{G,S}IFMEDIA; 1121 * assume ok. 1122 */ 1123 return EXIT_SUCCESS; 1124 } 1125 if ((ifmr.ifm_status & IFM_AVALID) == 0) { 1126 /* 1127 * Interface doesn't report media-valid status. 1128 * assume ok. 1129 */ 1130 return EXIT_SUCCESS; 1131 } 1132 /* otherwise, return ok for active, not-ok if not active. */ 1133 if (ifmr.ifm_status & IFM_ACTIVE) 1134 return EXIT_SUCCESS; 1135 else 1136 return EXIT_FAILURE; 1137} 1138 1139static void 1140print_plural(const char *prefix, uint64_t n, const char *unit) 1141{ 1142 printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s"); 1143} 1144 1145static void 1146print_human_bytes(bool humanize, uint64_t n) 1147{ 1148 char buf[5]; 1149 1150 if (humanize) { 1151 (void)humanize_number(buf, sizeof(buf), 1152 (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); 1153 printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s"); 1154 } else 1155 print_plural(", ", n, "byte"); 1156} 1157 1158/* 1159 * Print the status of the interface. If an address family was 1160 * specified, show it and it only; otherwise, show them all. 1161 */ 1162void 1163status(const struct sockaddr *sdl, prop_dictionary_t env, 1164 prop_dictionary_t oenv) 1165{ 1166 const struct if_data *ifi; 1167 status_func_t *status_f; 1168 statistics_func_t *statistics_f; 1169 struct ifdatareq ifdr; 1170 struct ifreq ifr; 1171 struct ifdrv ifdrv; 1172 char fbuf[BUFSIZ]; 1173 int af, s; 1174 const char *ifname; 1175 struct ifcapreq ifcr; 1176 unsigned short flags; 1177 const struct afswtch *afp; 1178 1179 if ((af = getaf(env)) == -1) { 1180 afp = NULL; 1181 af = AF_UNSPEC; 1182 } else 1183 afp = lookup_af_bynum(af); 1184 1185 /* get out early if the family is unsupported by the kernel */ 1186 if ((s = getsock(af)) == -1) 1187 err(EXIT_FAILURE, "%s: getsock", __func__); 1188 1189 if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 1190 err(EXIT_FAILURE, "%s: getifinfo", __func__); 1191 1192 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags); 1193 printf("%s: flags=%s", ifname, &fbuf[2]); 1194 1195 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1196 if (prog_ioctl(s, SIOCGIFMETRIC, &ifr) == -1) 1197 warn("SIOCGIFMETRIC %s", ifr.ifr_name); 1198 else if (ifr.ifr_metric != 0) 1199 printf(" metric %d", ifr.ifr_metric); 1200 1201 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1202 if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0) 1203 printf(" mtu %d", ifr.ifr_mtu); 1204 printf("\n"); 1205 1206 if (getifcaps(env, oenv, &ifcr) == -1) 1207 err(EXIT_FAILURE, "%s: getifcaps", __func__); 1208 1209 if (ifcr.ifcr_capabilities != 0) { 1210 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 1211 ifcr.ifcr_capabilities); 1212 printf("\tcapabilities=%s\n", &fbuf[2]); 1213 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 1214 ifcr.ifcr_capenable); 1215 printf("\tenabled=%s\n", &fbuf[2]); 1216 } 1217 1218 SIMPLEQ_FOREACH(status_f, &status_funcs, f_next) 1219 (*status_f->f_func)(env, oenv); 1220 1221 print_link_addresses(env, true); 1222 1223 estrlcpy(ifdrv.ifd_name, ifname, sizeof(ifdrv.ifd_name)); 1224 ifdrv.ifd_cmd = IFLINKSTR_QUERYLEN; 1225 ifdrv.ifd_len = 0; 1226 ifdrv.ifd_data = NULL; 1227 /* interface supports linkstr? */ 1228 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) != -1) { 1229 char *p; 1230 1231 p = malloc(ifdrv.ifd_len); 1232 if (p == NULL) 1233 err(EXIT_FAILURE, "malloc linkstr buf failed"); 1234 ifdrv.ifd_data = p; 1235 ifdrv.ifd_cmd = 0; 1236 if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) == -1) 1237 err(EXIT_FAILURE, "failed to query linkstr"); 1238 printf("\tlinkstr: %s\n", (char *)ifdrv.ifd_data); 1239 free(p); 1240 } 1241 1242 media_status(env, oenv); 1243 1244 if (!vflag && !zflag) 1245 goto proto_status; 1246 1247 estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 1248 1249 if (prog_ioctl(s, zflag ? SIOCZIFDATA : SIOCGIFDATA, &ifdr) == -1) 1250 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA"); 1251 1252 ifi = &ifdr.ifdr_data; 1253 1254 print_plural("\tinput: ", ifi->ifi_ipackets, "packet"); 1255 print_human_bytes(hflag, ifi->ifi_ibytes); 1256 if (ifi->ifi_imcasts) 1257 print_plural(", ", ifi->ifi_imcasts, "multicast"); 1258 if (ifi->ifi_ierrors) 1259 print_plural(", ", ifi->ifi_ierrors, "error"); 1260 if (ifi->ifi_iqdrops) 1261 print_plural(", ", ifi->ifi_iqdrops, "queue drop"); 1262 if (ifi->ifi_noproto) 1263 printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto); 1264 print_plural("\n\toutput: ", ifi->ifi_opackets, "packet"); 1265 print_human_bytes(hflag, ifi->ifi_obytes); 1266 if (ifi->ifi_omcasts) 1267 print_plural(", ", ifi->ifi_omcasts, "multicast"); 1268 if (ifi->ifi_oerrors) 1269 print_plural(", ", ifi->ifi_oerrors, "error"); 1270 if (ifi->ifi_collisions) 1271 print_plural(", ", ifi->ifi_collisions, "collision"); 1272 printf("\n"); 1273 1274 SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next) 1275 (*statistics_f->f_func)(env); 1276 1277 proto_status: 1278 1279 if (afp != NULL) 1280 (*afp->af_status)(env, oenv, true); 1281 else SIMPLEQ_FOREACH(afp, &aflist, af_next) 1282 (*afp->af_status)(env, oenv, false); 1283} 1284 1285static int 1286setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv) 1287{ 1288 bool rc; 1289 int64_t plen; 1290 int af; 1291 struct paddr_prefix *pfx; 1292 prop_data_t d; 1293 1294 if ((af = getaf(env)) == -1) 1295 af = AF_INET; 1296 1297 rc = prop_dictionary_get_int64(env, "prefixlen", &plen); 1298 assert(rc); 1299 1300 pfx = prefixlen_to_mask(af, plen); 1301 if (pfx == NULL) 1302 err(EXIT_FAILURE, "prefixlen_to_mask"); 1303 1304 d = prop_data_create_data(pfx, paddr_prefix_size(pfx)); 1305 if (d == NULL) 1306 err(EXIT_FAILURE, "%s: prop_data_create_data", __func__); 1307 1308 if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d)) 1309 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 1310 1311 free(pfx); 1312 return 0; 1313} 1314 1315static int 1316setlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1317{ 1318 struct ifdrv ifdrv; 1319 size_t linkstrlen; 1320 prop_data_t data; 1321 char *linkstr; 1322 1323 data = (prop_data_t)prop_dictionary_get(env, "linkstr"); 1324 if (data == NULL) { 1325 errno = ENOENT; 1326 return -1; 1327 } 1328 linkstrlen = prop_data_size(data)+1; 1329 1330 linkstr = malloc(linkstrlen); 1331 if (linkstr == NULL) 1332 err(EXIT_FAILURE, "malloc linkstr space"); 1333 if (getargstr(env, "linkstr", linkstr, linkstrlen) == -1) 1334 errx(EXIT_FAILURE, "getargstr linkstr failed"); 1335 1336 ifdrv.ifd_cmd = 0; 1337 ifdrv.ifd_len = linkstrlen; 1338 ifdrv.ifd_data = __UNCONST(linkstr); 1339 1340 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1341 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1342 free(linkstr); 1343 1344 return 0; 1345} 1346 1347static int 1348unsetlinkstr(prop_dictionary_t env, prop_dictionary_t oenv) 1349{ 1350 struct ifdrv ifdrv; 1351 1352 memset(&ifdrv, 0, sizeof(ifdrv)); 1353 ifdrv.ifd_cmd = IFLINKSTR_UNSET; 1354 1355 if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1) 1356 err(EXIT_FAILURE, "SIOCSLINKSTR"); 1357 1358 return 0; 1359} 1360 1361static void 1362usage(void) 1363{ 1364 const char *progname = getprogname(); 1365 usage_func_t *usage_f; 1366 prop_dictionary_t env; 1367 1368 if ((env = prop_dictionary_create()) == NULL) 1369 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 1370 1371 fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n" 1372 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n" 1373 "\t\t[ alias | -alias ] ]\n" 1374 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname, 1375 flag_is_registered(gflags, 'm') ? "[-m] " : "", 1376 flag_is_registered(gflags, 'L') ? "[-L] " : ""); 1377 1378 SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next) 1379 (*usage_f->f_func)(env); 1380 1381 fprintf(stderr, 1382 "\t[ arp | -arp ]\n" 1383 "\t[ preference n ]\n" 1384 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n" 1385 " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n" 1386 " %s -l [-b] [-d] [-s] [-u]\n" 1387 " %s -C\n" 1388 " %s interface create\n" 1389 " %s interface destroy\n", 1390 progname, flag_is_registered(gflags, 'm') ? "[-m] " : "", 1391 progname, progname, progname, progname); 1392 1393 prop_object_release((prop_object_t)env); 1394 exit(EXIT_FAILURE); 1395} 1396