ifconfig.c revision 1.206
1/* $NetBSD: ifconfig.c,v 1.206 2008/06/03 21:02:49 dyoung 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\n\ 65 The Regents of the University of California. All rights reserved.\n"); 66#endif /* not lint */ 67 68#ifndef lint 69#if 0 70static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; 71#else 72__RCSID("$NetBSD: ifconfig.c,v 1.206 2008/06/03 21:02:49 dyoung Exp $"); 73#endif 74#endif /* not lint */ 75 76#include <sys/param.h> 77#include <sys/socket.h> 78#include <sys/ioctl.h> 79 80#include <net/if.h> 81#include <net/if_dl.h> 82#include <net/if_media.h> 83#include <net/if_ether.h> 84#include <netinet/in.h> /* XXX */ 85#include <netinet/in_var.h> /* XXX */ 86 87#include <netdb.h> 88 89#include <sys/protosw.h> 90 91#include <assert.h> 92#include <ctype.h> 93#include <err.h> 94#include <errno.h> 95#include <stdbool.h> 96#include <stddef.h> 97#include <stdio.h> 98#include <stdlib.h> 99#include <string.h> 100#include <unistd.h> 101#include <ifaddrs.h> 102#include <util.h> 103 104#include "extern.h" 105 106#ifndef INET_ONLY 107#include "af_atalk.h" 108#include "af_iso.h" 109#endif /* ! INET_ONLY */ 110#include "af_inet.h" 111#ifdef INET6 112#include "af_inet6.h" 113#endif /* INET6 */ 114#include "af_link.h" 115 116#include "agr.h" 117#include "carp.h" 118#include "ieee80211.h" 119#include "tunnel.h" 120#include "vlan.h" 121#include "parse.h" 122#include "env.h" 123 124int setaddr, doalias; 125int clearaddr; 126int newaddr = -1; 127int check_up_state = -1; 128int bflag, dflag, hflag, lflag, mflag, sflag, uflag, vflag, zflag; 129#ifdef INET6 130int Lflag; 131#endif 132 133/* 134 * Media stuff. Whenever a media command is first performed, the 135 * currently select media is grabbed for this interface. If `media' 136 * is given, the current media word is modifed. `mediaopt' commands 137 * only modify the set and clear words. They then operate on the 138 * current media word later. 139 */ 140int media_current; 141int mediaopt_set; 142int mediaopt_clear; 143 144void check_ifflags_up(prop_dictionary_t); 145 146int notealias(prop_dictionary_t, prop_dictionary_t); 147int notrailers(prop_dictionary_t, prop_dictionary_t); 148int setifaddr(prop_dictionary_t, prop_dictionary_t); 149int setifdstormask(prop_dictionary_t, prop_dictionary_t); 150int setifflags(prop_dictionary_t, prop_dictionary_t); 151static int setifcaps(prop_dictionary_t, prop_dictionary_t); 152int setifbroadaddr(prop_dictionary_t, prop_dictionary_t); 153static int setifmetric(prop_dictionary_t, prop_dictionary_t); 154static int setifmtu(prop_dictionary_t, prop_dictionary_t); 155int setifnetmask(prop_dictionary_t, prop_dictionary_t); 156int setifprefixlen(prop_dictionary_t, prop_dictionary_t); 157int setmedia(prop_dictionary_t, prop_dictionary_t); 158int setmediamode(prop_dictionary_t, prop_dictionary_t); 159int setmediaopt(prop_dictionary_t, prop_dictionary_t); 160int unsetmediaopt(prop_dictionary_t, prop_dictionary_t); 161int setmediainst(prop_dictionary_t, prop_dictionary_t); 162static int clone_command(prop_dictionary_t, prop_dictionary_t); 163static void do_setifpreference(prop_dictionary_t); 164 165static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t); 166static int media_status_exec(prop_dictionary_t, prop_dictionary_t); 167 168int carrier(prop_dictionary_t); 169void printall(const char *, prop_dictionary_t); 170int list_cloners(prop_dictionary_t, prop_dictionary_t); 171void status(const struct sockaddr_dl *, prop_dictionary_t, 172 prop_dictionary_t); 173void usage(void); 174 175void print_media_word(int, const char *); 176void process_media_commands(prop_dictionary_t); 177void init_current_media(prop_dictionary_t, prop_dictionary_t); 178 179/* Known address families */ 180static const struct afswtch afs[] = { 181 {.af_name = "inet", .af_af = AF_INET, .af_status = in_status, 182 .af_addr_commit = in_commit_address} 183 184 , {.af_name = "link", .af_af = AF_LINK, .af_status = link_status, 185 .af_addr_commit = link_commit_address} 186#ifdef INET6 187 , {.af_name = "inet6", .af_af = AF_INET6, .af_status = in6_status, 188 .af_addr_commit = in6_commit_address} 189#endif 190 191#ifndef INET_ONLY /* small version, for boot media */ 192 , {.af_name = "atalk", .af_af = AF_APPLETALK, .af_status = at_status, 193 .af_getaddr = at_getaddr, NULL, .af_difaddr = SIOCDIFADDR, 194 .af_aifaddr = SIOCAIFADDR, .af_gifaddr = SIOCGIFADDR, 195 .af_ridreq = &at_addreq, .af_addreq = &at_addreq} 196 , {.af_name = "iso", .af_af = AF_ISO, .af_status = iso_status, 197 .af_getaddr = iso_getaddr, .af_difaddr = SIOCDIFADDR_ISO, 198 .af_aifaddr = SIOCAIFADDR_ISO, .af_gifaddr = SIOCGIFADDR_ISO, 199 .af_ridreq = &iso_ridreq, .af_addreq = &iso_addreq} 200#endif /* INET_ONLY */ 201 202 , {.af_name = NULL} /* sentinel */ 203}; 204 205static const struct kwinst ifflagskw[] = { 206 IFKW("arp", IFF_NOARP) 207 , IFKW("debug", IFF_DEBUG) 208 , IFKW("link0", IFF_LINK0) 209 , IFKW("link1", IFF_LINK1) 210 , IFKW("link2", IFF_LINK2) 211 , {.k_word = "down", .k_type = KW_T_INT, .k_int = -IFF_UP} 212 , {.k_word = "up", .k_type = KW_T_INT, .k_int = IFF_UP} 213}; 214 215static const struct kwinst ifcapskw[] = { 216 IFKW("ip4csum-tx", IFCAP_CSUM_IPv4_Tx) 217 , IFKW("ip4csum-rx", IFCAP_CSUM_IPv4_Rx) 218 , IFKW("tcp4csum-tx", IFCAP_CSUM_TCPv4_Tx) 219 , IFKW("tcp4csum-rx", IFCAP_CSUM_TCPv4_Rx) 220 , IFKW("udp4csum-tx", IFCAP_CSUM_UDPv4_Tx) 221 , IFKW("udp4csum-rx", IFCAP_CSUM_UDPv4_Rx) 222 , IFKW("tcp6csum-tx", IFCAP_CSUM_TCPv6_Tx) 223 , IFKW("tcp6csum-rx", IFCAP_CSUM_TCPv6_Rx) 224 , IFKW("udp6csum-tx", IFCAP_CSUM_UDPv6_Tx) 225 , IFKW("udp6csum-rx", IFCAP_CSUM_UDPv6_Rx) 226 , IFKW("ip4csum", IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx) 227 , IFKW("tcp4csum", IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx) 228 , IFKW("udp4csum", IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx) 229 , IFKW("tcp6csum", IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx) 230 , IFKW("udp6csum", IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx) 231 , IFKW("tso4", IFCAP_TSOv4) 232 , IFKW("tso6", IFCAP_TSOv6) 233}; 234 235extern struct pbranch command_root; 236extern struct pbranch opt_command; 237extern struct pbranch opt_family, opt_silent_family; 238extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc; 239 240struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10, 241 setifmetric, "metric", &command_root.pb_parser); 242 243struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10, 244 setifmtu, "mtu", &command_root.pb_parser); 245 246struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen, 247 "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser); 248 249struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference, 250 "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference", 251 &command_root.pb_parser); 252 253struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask", 254 setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser); 255 256struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast, 257 "broadcast address", 258 setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser); 259 260struct pstr mediamode = PSTR_INITIALIZER(&mediamode, "mediamode", 261 setmediamode, "mediamode", &command_root.pb_parser); 262 263struct pinteger mediainst = PINTEGER_INITIALIZER1(&mediainst, "mediainst", 264 0, IFM_INST_MAX, 10, setmediainst, "mediainst", &command_root.pb_parser); 265 266struct pstr unmediaopt = PSTR_INITIALIZER(&unmediaopt, "-mediaopt", 267 unsetmediaopt, "unmediaopt", &command_root.pb_parser); 268 269struct pstr mediaopt = PSTR_INITIALIZER(&mediaopt, "mediaopt", 270 setmediaopt, "mediaopt", &command_root.pb_parser); 271 272struct pstr media = PSTR_INITIALIZER(&media, "media", 273 setmedia, "media", &command_root.pb_parser); 274 275static const struct kwinst misckw[] = { 276 {.k_word = "active", .k_key = "active", .k_type = KW_T_BOOL, 277 .k_bool = true, .k_nextparser = &command_root.pb_parser} 278 , {.k_word = "alias", .k_key = "alias", .k_deact = "alias", 279 .k_type = KW_T_BOOL, .k_neg = true, 280 .k_bool = true, .k_negbool = false, 281 .k_exec = notealias, .k_nextparser = &command_root.pb_parser} 282 , {.k_word = "broadcast", .k_nextparser = &parse_broadcast.pa_parser} 283 , {.k_word = "delete", .k_key = "alias", .k_deact = "alias", 284 .k_type = KW_T_BOOL, .k_bool = false, .k_exec = notealias, 285 .k_nextparser = &command_root.pb_parser} 286 , {.k_word = "instance", .k_key = "anymedia", .k_type = KW_T_BOOL, 287 .k_bool = true, .k_act = "media", .k_deact = "mediainst", 288 .k_nextparser = &mediainst.pi_parser} 289 , {.k_word = "inst", .k_key = "anymedia", .k_type = KW_T_BOOL, 290 .k_bool = true, .k_act = "media", .k_deact = "mediainst", 291 .k_nextparser = &mediainst.pi_parser} 292 , {.k_word = "media", .k_key = "anymedia", .k_type = KW_T_BOOL, 293 .k_bool = true, .k_deact = "media", .k_altdeact = "anymedia", 294 .k_nextparser = &media.ps_parser} 295 , {.k_word = "mediaopt", .k_key = "anymedia", .k_type = KW_T_BOOL, 296 .k_bool = true, .k_deact = "mediaopt", .k_altdeact = "instance", 297 .k_nextparser = &mediaopt.ps_parser} 298 , {.k_word = "-mediaopt", .k_key = "anymedia", .k_type = KW_T_BOOL, 299 .k_bool = true, .k_deact = "unmediaopt", .k_altdeact = "media", 300 .k_nextparser = &unmediaopt.ps_parser} 301 , {.k_word = "mode", .k_key = "anymedia", .k_type = KW_T_BOOL, 302 .k_bool = true, .k_deact = "mode", 303 .k_nextparser = &mediamode.ps_parser} 304 , {.k_word = "metric", .k_nextparser = &parse_metric.pi_parser} 305 , {.k_word = "mtu", .k_nextparser = &parse_mtu.pi_parser} 306 , {.k_word = "netmask", .k_nextparser = &parse_netmask.pa_parser} 307 , {.k_word = "preference", .k_act = "address", 308 .k_nextparser = &parse_preference.pi_parser} 309 , {.k_word = "prefixlen", .k_nextparser = &parse_prefixlen.pi_parser} 310 , {.k_word = "trailers", .k_neg = true, 311 .k_exec = notrailers, .k_nextparser = &command_root.pb_parser} 312}; 313 314/* key: clonecmd */ 315static const struct kwinst clonekw[] = { 316 {.k_word = "create", .k_type = KW_T_INT, .k_int = SIOCIFCREATE, 317 .k_nextparser = &opt_silent_family.pb_parser}, 318 {.k_word = "destroy", .k_type = KW_T_INT, .k_int = SIOCIFDESTROY} 319}; 320 321static const struct kwinst familykw[] = { 322 {.k_word = "inet", .k_type = KW_T_INT, .k_int = AF_INET, 323 .k_nextparser = NULL} 324 , {.k_word = "link", .k_type = KW_T_INT, .k_int = AF_LINK, 325 .k_nextparser = NULL} 326#ifdef INET6 327 , {.k_word = "inet6", .k_type = KW_T_INT, .k_int = AF_INET6, 328 .k_nextparser = NULL} 329#endif 330#ifndef INET_ONLY /* small version, for boot media */ 331 , {.k_word = "atalk", .k_type = KW_T_INT, .k_int = AF_APPLETALK, 332 .k_nextparser = NULL} 333 , {.k_word = "iso", .k_type = KW_T_INT, .k_int = AF_ISO, 334 .k_nextparser = NULL} 335#endif /* INET_ONLY */ 336}; 337 338struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners", 339 list_cloners, "none"); 340 341struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec, 342 "none"); 343 344struct pkw family_only = 345 PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw, 346 __arraycount(familykw), &no_cmds.pt_parser); 347 348struct paddr address = PADDR_INITIALIZER(&address, 349 "local address (address 1)", 350 setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser); 351 352struct paddr dstormask = PADDR_INITIALIZER(&dstormask, 353 "destination/netmask (address 2)", 354 setifdstormask, "dstormask", NULL, "address", "dstormask", 355 &command_root.pb_parser); 356 357struct paddr broadcast = PADDR_INITIALIZER(&broadcast, 358 "broadcast address (address 3)", 359 setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast", 360 &command_root.pb_parser); 361 362struct branch opt_clone_brs[] = { 363 {.b_nextparser = &cloning.pk_parser} 364 , {.b_nextparser = &opt_family.pb_parser} 365}, opt_silent_family_brs[] = { 366 {.b_nextparser = &silent_family.pk_parser} 367 , {.b_nextparser = &command_root.pb_parser} 368}, opt_family_brs[] = { 369 {.b_nextparser = &family.pk_parser} 370 , {.b_nextparser = &opt_command.pb_parser} 371}, command_root_brs[] = { 372 {.b_nextparser = &ieee80211bool.pk_parser} 373 , {.b_nextparser = &ifflags.pk_parser} 374 , {.b_nextparser = &ifcaps.pk_parser} 375#ifdef INET6 376 , {.b_nextparser = &ia6flags.pk_parser} 377 , {.b_nextparser = &inet6.pk_parser} 378#endif /*INET6*/ 379 , {.b_nextparser = &misc.pk_parser} 380 , {.b_nextparser = &tunnel.pk_parser} 381 , {.b_nextparser = &vlan.pk_parser} 382 , {.b_nextparser = &agr.pk_parser} 383#ifndef INET_ONLY 384 , {.b_nextparser = &carp.pk_parser} 385 , {.b_nextparser = &atalk.pk_parser} 386 , {.b_nextparser = &iso.pk_parser} 387#endif 388 , {.b_nextparser = &kw80211.pk_parser} 389 , {.b_nextparser = &address.pa_parser} 390 , {.b_nextparser = &dstormask.pa_parser} 391 , {.b_nextparser = &broadcast.pa_parser} 392 , {.b_nextparser = NULL} 393}, opt_command_brs[] = { 394 {.b_nextparser = &no_cmds.pt_parser} 395 , {.b_nextparser = &command_root.pb_parser} 396}; 397 398struct branch opt_family_only_brs[] = { 399 {.b_nextparser = &no_cmds.pt_parser} 400 , {.b_nextparser = &family_only.pk_parser} 401}; 402struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only, 403 "opt-family-only", opt_family_only_brs, 404 __arraycount(opt_family_only_brs), true); 405struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command, 406 "optional command", 407 opt_command_brs, __arraycount(opt_command_brs), true); 408 409struct pbranch command_root = PBRANCH_INITIALIZER(&command_root, 410 "command-root", command_root_brs, __arraycount(command_root_brs), true); 411 412struct piface iface_opt_family_only = 413 PIFACE_INITIALIZER(&iface_opt_family_only, "iface-opt-family-only", 414 NULL, "if", &opt_family_only.pb_parser); 415 416struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af", 417 familykw, __arraycount(familykw), &opt_command.pb_parser); 418 419struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family", 420 NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser); 421 422struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps, 423 "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser); 424 425struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags, 426 "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser); 427 428struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command, 429 "clonecmd", clonekw, __arraycount(clonekw), NULL); 430 431struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL, 432 misckw, __arraycount(misckw), NULL); 433 434struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone, 435 "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true); 436 437struct pbranch opt_silent_family = PBRANCH_INITIALIZER(&opt_silent_family, 438 "optional silent family", opt_silent_family_brs, 439 __arraycount(opt_silent_family_brs), true); 440 441struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family, 442 "opt-family", opt_family_brs, __arraycount(opt_family_brs), true); 443 444struct piface iface_start = PIFACE_INITIALIZER(&iface_start, 445 "iface-opt-family", NULL, "if", &opt_clone.pb_parser); 446 447struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface", 448 media_status_exec, "if", NULL); 449 450static struct parser * 451init_parser(void) 452{ 453 if (parser_init(&iface_opt_family_only.pif_parser) == -1) 454 err(EXIT_FAILURE, "parser_init(iface_opt_family_only)"); 455 if (parser_init(&iface_only.pif_parser) == -1) 456 err(EXIT_FAILURE, "parser_init(iface_only)"); 457 if (parser_init(&iface_start.pif_parser) == -1) 458 err(EXIT_FAILURE, "parser_init(iface_start)"); 459 460 return &iface_start.pif_parser; 461} 462 463static int 464no_cmds_exec(prop_dictionary_t env, prop_dictionary_t xenv) 465{ 466 const char *ifname; 467 unsigned short ignore; 468 469 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */ 470 if ((ifname = getifname(env)) == NULL) 471 ; 472 else if (getifflags(env, xenv, &ignore) == -1) 473 err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname); 474 475 printall(ifname, env); 476 exit(EXIT_SUCCESS); 477} 478 479static int 480media_status_exec(prop_dictionary_t env, prop_dictionary_t xenv) 481{ 482 const char *ifname; 483 unsigned short ignore; 484 485 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */ 486 if ((ifname = getifname(env)) == NULL) 487 ; 488 else if (getifflags(env, xenv, &ignore) == -1) 489 err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname); 490 491 exit(carrier(env)); 492} 493 494static void 495do_setifcaps(prop_dictionary_t env) 496{ 497 struct ifcapreq ifcr; 498 prop_data_t d; 499 500 d = (prop_data_t )prop_dictionary_get(env, "ifcaps"); 501 if (d == NULL) 502 return; 503 504 assert(sizeof(ifcr) == prop_data_size(d)); 505 506 memcpy(&ifcr, prop_data_data_nocopy(d), sizeof(ifcr)); 507 if (direct_ioctl(env, SIOCSIFCAP, &ifcr) == -1) 508 err(EXIT_FAILURE, "SIOCSIFCAP"); 509} 510 511int 512main(int argc, char **argv) 513{ 514 const struct afswtch *afp; 515 int af, aflag = 0, Cflag = 0, s; 516 struct match match[32]; 517 size_t nmatch; 518 struct parser *start; 519 int ch, narg = 0, rc; 520 prop_dictionary_t env, xenv; 521 const char *ifname; 522 523 memset(match, 0, sizeof(match)); 524 525 start = init_parser(); 526 527 /* Parse command-line options */ 528 aflag = mflag = vflag = zflag = 0; 529 while ((ch = getopt(argc, argv, "AabCdhlmsuvz" 530#ifdef INET6 531 "L" 532#endif 533 )) != -1) { 534 switch (ch) { 535 case 'A': 536 warnx("-A is deprecated"); 537 break; 538 539 case 'a': 540 aflag = 1; 541 break; 542 543 case 'b': 544 bflag = 1; 545 break; 546 547 case 'C': 548 Cflag = 1; 549 break; 550 551 case 'd': 552 dflag = 1; 553 break; 554 case 'h': 555 hflag = 1; 556 break; 557#ifdef INET6 558 case 'L': 559 Lflag = 1; 560 break; 561#endif 562 563 case 'l': 564 lflag = 1; 565 break; 566 567 case 'm': 568 mflag = 1; 569 break; 570 571 case 's': 572 sflag = 1; 573 break; 574 575 case 'u': 576 uflag = 1; 577 break; 578 579 case 'v': 580 vflag = 1; 581 break; 582 583 case 'z': 584 zflag = 1; 585 break; 586 587 588 default: 589 usage(); 590 /* NOTREACHED */ 591 } 592 switch (ch) { 593 case 'a': 594 start = &opt_family_only.pb_parser; 595 break; 596 597#ifdef INET6 598 case 'L': 599#endif 600 case 'm': 601 case 'v': 602 case 'z': 603 if (start != &opt_family_only.pb_parser) 604 start = &iface_opt_family_only.pif_parser; 605 break; 606 case 'C': 607 start = &cloneterm.pt_parser; 608 break; 609 case 'l': 610 start = &no_cmds.pt_parser; 611 break; 612 case 's': 613 if (start != &no_cmds.pt_parser && 614 start != &opt_family_only.pb_parser) 615 start = &iface_only.pif_parser; 616 break; 617 default: 618 break; 619 } 620 } 621 argc -= optind; 622 argv += optind; 623 624 /* 625 * -l means "list all interfaces", and is mutally exclusive with 626 * all other flags/commands. 627 * 628 * -C means "list all names of cloners", and it mutually exclusive 629 * with all other flags/commands. 630 * 631 * -a means "print status of all interfaces". 632 */ 633 if ((lflag || Cflag) && (aflag || mflag || vflag || zflag)) 634 usage(); 635#ifdef INET6 636 if ((lflag || Cflag) && Lflag) 637 usage(); 638#endif 639 if (lflag && Cflag) 640 usage(); 641 642 nmatch = __arraycount(match); 643 644 rc = parse(argc, argv, start, match, &nmatch, &narg); 645 if (rc != 0) 646 usage(); 647 648 if ((xenv = prop_dictionary_create()) == NULL) 649 err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__); 650 651 if (matches_exec(match, xenv, nmatch) == -1) 652 err(EXIT_FAILURE, "exec_matches"); 653 654 argc -= narg; 655 argv += narg; 656 657 env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL; 658 if (env == NULL) 659 env = xenv; 660 else 661 env = prop_dictionary_augment(env, xenv); 662 663 /* Process any media commands that may have been issued. */ 664 process_media_commands(env); 665 666 af = getaf(env); 667 switch (af) { 668#ifndef INET_ONLY 669 case AF_APPLETALK: 670 checkatrange(&at_addreq.ifra_addr); 671 break; 672#endif /* INET_ONLY */ 673 default: 674 break; 675 case -1: 676 af = AF_INET; 677 break; 678 } 679 680 if ((s = getsock(af)) == -1) 681 err(EXIT_FAILURE, "%s: getsock", __func__); 682 683 if ((ifname = getifname(env)) == NULL) 684 err(EXIT_FAILURE, "%s: getifname", __func__); 685 686 if ((afp = lookup_af_bynum(af)) == NULL) 687 errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__); 688 689 if (afp->af_addr_commit != NULL) { 690 (*afp->af_addr_commit)(env, xenv); 691 } else { 692 if (clearaddr) { 693 estrlcpy(afp->af_ridreq, ifname, IFNAMSIZ); 694 if (ioctl(s, afp->af_difaddr, afp->af_ridreq) == -1) 695 err(EXIT_FAILURE, "SIOCDIFADDR"); 696 } 697 if (newaddr > 0) { 698 estrlcpy(afp->af_addreq, ifname, IFNAMSIZ); 699 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) == -1) 700 warn("SIOCAIFADDR"); 701 else if (check_up_state < 0) 702 check_up_state = 1; 703 } 704 } 705 706 do_setifpreference(env); 707 do_setifcaps(env); 708 709 if (check_up_state == 1) 710 check_ifflags_up(env); 711 712 exit(EXIT_SUCCESS); 713} 714 715const struct afswtch * 716lookup_af_bynum(int afnum) 717{ 718 const struct afswtch *a; 719 720 for (a = afs; a->af_name != NULL; a++) 721 if (a->af_af == afnum) 722 return (a); 723 return (NULL); 724} 725 726void 727printall(const char *ifname, prop_dictionary_t env0) 728{ 729 struct ifaddrs *ifap, *ifa; 730 struct ifreq ifr; 731 const struct sockaddr_dl *sdl = NULL; 732 prop_dictionary_t env, oenv; 733 int idx; 734 char *p; 735 736 if (env0 == NULL) 737 env = prop_dictionary_create(); 738 else 739 env = prop_dictionary_copy_mutable(env0); 740 741 oenv = prop_dictionary_create(); 742 743 if (env == NULL || oenv == NULL) 744 errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__); 745 746 if (getifaddrs(&ifap) != 0) 747 err(EXIT_FAILURE, "getifaddrs"); 748 p = NULL; 749 idx = 0; 750 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 751 memset(&ifr, 0, sizeof(ifr)); 752 estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); 753 if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 754 memcpy(&ifr.ifr_addr, ifa->ifa_addr, 755 ifa->ifa_addr->sa_len); 756 } 757 758 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) 759 continue; 760 if (ifa->ifa_addr->sa_family == AF_LINK) 761 sdl = (const struct sockaddr_dl *) ifa->ifa_addr; 762 if (p && strcmp(p, ifa->ifa_name) == 0) 763 continue; 764 if (!prop_dictionary_set_cstring(env, "if", ifa->ifa_name)) 765 continue; 766 p = ifa->ifa_name; 767 768 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0) 769 continue; 770 if (dflag && (ifa->ifa_flags & IFF_UP) != 0) 771 continue; 772 if (uflag && (ifa->ifa_flags & IFF_UP) == 0) 773 continue; 774 775 if (sflag && carrier(env)) 776 continue; 777 idx++; 778 /* 779 * Are we just listing the interfaces? 780 */ 781 if (lflag) { 782 if (idx > 1) 783 printf(" "); 784 fputs(ifa->ifa_name, stdout); 785 continue; 786 } 787 788 status(sdl, env, oenv); 789 sdl = NULL; 790 } 791 if (lflag) 792 printf("\n"); 793 prop_object_release((prop_object_t)env); 794 prop_object_release((prop_object_t)oenv); 795 freeifaddrs(ifap); 796} 797 798int 799list_cloners(prop_dictionary_t env, prop_dictionary_t oenv) 800{ 801 struct if_clonereq ifcr; 802 char *cp, *buf; 803 int idx, s; 804 805 memset(&ifcr, 0, sizeof(ifcr)); 806 807 s = getsock(AF_INET); 808 809 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 810 err(EXIT_FAILURE, "SIOCIFGCLONERS for count"); 811 812 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 813 if (buf == NULL) 814 err(EXIT_FAILURE, "unable to allocate cloner name buffer"); 815 816 ifcr.ifcr_count = ifcr.ifcr_total; 817 ifcr.ifcr_buffer = buf; 818 819 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 820 err(EXIT_FAILURE, "SIOCIFGCLONERS for names"); 821 822 /* 823 * In case some disappeared in the mean time, clamp it down. 824 */ 825 if (ifcr.ifcr_count > ifcr.ifcr_total) 826 ifcr.ifcr_count = ifcr.ifcr_total; 827 828 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 829 if (idx > 0) 830 printf(" "); 831 printf("%s", cp); 832 } 833 834 printf("\n"); 835 free(buf); 836 exit(EXIT_SUCCESS); 837} 838 839static int 840clone_command(prop_dictionary_t env, prop_dictionary_t xenv) 841{ 842 int64_t cmd; 843 844 if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) { 845 errno = ENOENT; 846 return -1; 847 } 848 849 if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) { 850 warn("%s", __func__); 851 return -1; 852 } 853 return 0; 854} 855 856/*ARGSUSED*/ 857int 858setifaddr(prop_dictionary_t env, prop_dictionary_t xenv) 859{ 860 struct ifreq *ifr; /* XXX */ 861 const struct paddr_prefix *pfx0; 862 struct paddr_prefix *pfx; 863 prop_data_t d; 864 const char *ifname; 865 int af, s; 866 const struct afswtch *afp; 867 868 if ((af = getaf(env)) == -1) 869 af = AF_INET; 870 871 if ((afp = lookup_af_bynum(af)) == NULL) 872 return -1; 873 874 d = (prop_data_t)prop_dictionary_get(env, "address"); 875 assert(d != NULL); 876 pfx0 = prop_data_data_nocopy(d); 877 878 if (pfx0->pfx_len >= 0) { 879 pfx = prefixlen_to_mask(af, pfx0->pfx_len); 880 if (pfx == NULL) 881 err(EXIT_FAILURE, "prefixlen_to_mask"); 882 883 if (afp->af_getaddr != NULL) 884 (*afp->af_getaddr)(pfx, MASK); 885 free(pfx); 886 } 887 888 if (afp->af_addr_commit != NULL) 889 return 0; 890 891 if ((ifname = getifname(env)) == NULL) 892 return -1; 893 894 /* 895 * Delay the ioctl to set the interface addr until flags are all set. 896 * The address interpretation may depend on the flags, 897 * and the flags may change when the address is set. 898 */ 899 setaddr++; 900 if (newaddr == -1) 901 newaddr = 1; 902 if (doalias == 0 && afp->af_gifaddr != 0) { 903 ifr = (struct ifreq *)afp->af_ridreq; 904 estrlcpy(ifr->ifr_name, ifname, sizeof(ifr->ifr_name)); 905 ifr->ifr_addr.sa_family = af; 906 907 if ((s = getsock(af)) == -1) 908 err(EXIT_FAILURE, "getsock"); 909 910 if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0) 911 clearaddr = 1; 912 else if (errno == EADDRNOTAVAIL) 913 /* No address was assigned yet. */ 914 ; 915 else 916 err(EXIT_FAILURE, "SIOCGIFADDR"); 917 } 918 919#if 0 920 int i; 921 for (i = 0; i < pfx0->pfx_addr.sa_len; i++) 922 printf(" %02x", ((const uint8_t *)&pfx->pfx_addr)[i]); 923 printf("\n"); 924#endif 925 if (afp->af_getaddr != NULL) 926 (*afp->af_getaddr)(pfx0, (doalias >= 0 ? ADDR : RIDADDR)); 927 return 0; 928} 929 930int 931setifnetmask(prop_dictionary_t env, prop_dictionary_t xenv) 932{ 933 const struct paddr_prefix *pfx; 934 prop_data_t d; 935 int af; 936 const struct afswtch *afp; 937 938 if ((af = getaf(env)) == -1) 939 af = AF_INET; 940 941 if ((afp = lookup_af_bynum(af)) == NULL) 942 return -1; 943 944 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 945 assert(d != NULL); 946 pfx = prop_data_data_nocopy(d); 947 948 if (!prop_dictionary_set(xenv, "netmask", (prop_object_t)d)) 949 return -1; 950 951 if (afp->af_getaddr != NULL) 952 (*afp->af_getaddr)(pfx, MASK); 953 return 0; 954} 955 956int 957setifbroadaddr(prop_dictionary_t env, prop_dictionary_t xenv) 958{ 959 const struct paddr_prefix *pfx; 960 prop_data_t d; 961 int af; 962 const struct afswtch *afp; 963 unsigned short flags; 964 965 if ((af = getaf(env)) == -1) 966 af = AF_INET; 967 968 if ((afp = lookup_af_bynum(af)) == NULL) 969 return -1; 970 971 if (getifflags(env, xenv, &flags) == -1) 972 err(EXIT_FAILURE, "%s: getifflags", __func__); 973 974 if ((flags & IFF_BROADCAST) == 0) 975 errx(EXIT_FAILURE, "not a broadcast interface"); 976 977 d = (prop_data_t)prop_dictionary_get(env, "broadcast"); 978 assert(d != NULL); 979 pfx = prop_data_data_nocopy(d); 980 981 if (!prop_dictionary_set(xenv, "broadcast", (prop_object_t)d)) 982 return -1; 983 984 if (afp->af_getaddr != NULL) 985 (*afp->af_getaddr)(pfx, DSTADDR); 986 987 return 0; 988} 989 990#define rqtosa(__afp, __x) (&(((struct ifreq *)(__afp->__x))->ifr_addr)) 991 992int 993notealias(prop_dictionary_t env, prop_dictionary_t xenv) 994{ 995 bool alias, delete; 996 int af; 997 const struct afswtch *afp; 998 999 if ((af = getaf(env)) == -1) 1000 af = AF_INET; 1001 1002 if ((afp = lookup_af_bynum(af)) == NULL) 1003 return -1; 1004 1005 if (afp->af_addr_commit != NULL) 1006 return 0; 1007 1008 if (!prop_dictionary_get_bool(env, "alias", &alias)) { 1009 errno = ENOENT; 1010 return -1; 1011 } 1012 delete = !alias; 1013 if (setaddr && doalias == 0 && delete) 1014 memcpy(rqtosa(afp, af_ridreq), rqtosa(afp, af_addreq), 1015 rqtosa(afp, af_addreq)->sa_len); 1016 doalias = delete ? -1 : 1; 1017 if (delete) { 1018 clearaddr = 1; 1019 newaddr = 0; 1020 } else { 1021 clearaddr = 0; 1022 } 1023 return 0; 1024} 1025 1026/*ARGSUSED*/ 1027int 1028notrailers(prop_dictionary_t env, prop_dictionary_t xenv) 1029{ 1030 puts("Note: trailers are no longer sent, but always received"); 1031 return 0; 1032} 1033 1034/*ARGSUSED*/ 1035int 1036setifdstormask(prop_dictionary_t env, prop_dictionary_t xenv) 1037{ 1038 const char *key; 1039 const struct paddr_prefix *pfx; 1040 prop_data_t d; 1041 int af, which; 1042 const struct afswtch *afp; 1043 unsigned short flags; 1044 1045 if ((af = getaf(env)) == -1) 1046 af = AF_INET; 1047 1048 if ((afp = lookup_af_bynum(af)) == NULL) 1049 return -1; 1050 1051 if (getifflags(env, xenv, &flags) == -1) 1052 err(EXIT_FAILURE, "%s: getifflags", __func__); 1053 1054 d = (prop_data_t)prop_dictionary_get(env, "dstormask"); 1055 assert(d != NULL); 1056 pfx = prop_data_data_nocopy(d); 1057 1058 if ((flags & IFF_BROADCAST) == 0) { 1059 key = "dst"; 1060 which = DSTADDR; 1061 } else { 1062 key = "netmask"; 1063 which = MASK; 1064 } 1065 1066 if (!prop_dictionary_set(xenv, key, (prop_object_t)d)) 1067 return -1; 1068 1069 if (afp->af_getaddr != NULL) 1070 (*afp->af_getaddr)(pfx, which); 1071 return 0; 1072} 1073 1074void 1075check_ifflags_up(prop_dictionary_t env) 1076{ 1077 struct ifreq ifr; 1078 1079 if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) 1080 err(EXIT_FAILURE, "SIOCGIFFLAGS"); 1081 if (ifr.ifr_flags & IFF_UP) 1082 return; 1083 ifr.ifr_flags |= IFF_UP; 1084 if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1) 1085 err(EXIT_FAILURE, "SIOCSIFFLAGS"); 1086} 1087 1088int 1089setifflags(prop_dictionary_t env, prop_dictionary_t xenv) 1090{ 1091 struct ifreq ifr; 1092 int64_t ifflag; 1093 bool rc; 1094 1095 rc = prop_dictionary_get_int64(env, "ifflag", &ifflag); 1096 assert(rc); 1097 1098 if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1) 1099 return -1; 1100 1101 if (ifflag < 0) { 1102 ifflag = -ifflag; 1103 if (ifflag == IFF_UP) 1104 check_up_state = 0; 1105 ifr.ifr_flags &= ~ifflag; 1106 } else 1107 ifr.ifr_flags |= ifflag; 1108 1109 if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1) 1110 return -1; 1111 1112 return 0; 1113} 1114 1115static int 1116getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr) 1117{ 1118 bool rc; 1119 struct ifcapreq ifcr; 1120 const struct ifcapreq *tmpifcr; 1121 prop_data_t capdata; 1122 1123 capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps"); 1124 1125 if (capdata != NULL) { 1126 tmpifcr = prop_data_data_nocopy(capdata); 1127 *oifcr = *tmpifcr; 1128 return 0; 1129 } 1130 1131 (void)direct_ioctl(env, SIOCGIFCAP, &ifcr); 1132 *oifcr = ifcr; 1133 1134 capdata = prop_data_create_data(&ifcr, sizeof(ifcr)); 1135 1136 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1137 1138 prop_object_release((prop_object_t)capdata); 1139 1140 return rc ? 0 : -1; 1141} 1142 1143static int 1144setifcaps(prop_dictionary_t env, prop_dictionary_t oenv) 1145{ 1146 int64_t ifcap; 1147 int s; 1148 bool rc; 1149 prop_data_t capdata; 1150 const char *ifname; 1151 struct ifcapreq ifcr; 1152 1153 s = getsock(AF_INET); 1154 1155 rc = prop_dictionary_get_int64(env, "ifcap", &ifcap); 1156 assert(rc); 1157 1158 if ((ifname = getifname(env)) == NULL) 1159 return -1; 1160 1161 if (getifcaps(env, oenv, &ifcr) == -1) 1162 return -1; 1163 1164 if (ifcap < 0) { 1165 ifcap = -ifcap; 1166 ifcr.ifcr_capenable &= ~ifcap; 1167 } else 1168 ifcr.ifcr_capenable |= ifcap; 1169 1170 if ((capdata = prop_data_create_data(&ifcr, sizeof(ifcr))) == NULL) 1171 return -1; 1172 1173 rc = prop_dictionary_set(oenv, "ifcaps", capdata); 1174 prop_object_release((prop_object_t)capdata); 1175 1176 return rc ? 0 : -1; 1177} 1178 1179static int 1180setifmetric(prop_dictionary_t env, prop_dictionary_t xenv) 1181{ 1182 struct ifreq ifr; 1183 bool rc; 1184 int64_t metric; 1185 1186 rc = prop_dictionary_get_int64(env, "metric", &metric); 1187 assert(rc); 1188 1189 ifr.ifr_metric = metric; 1190 if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1) 1191 warn("SIOCSIFMETRIC"); 1192 return 0; 1193} 1194 1195static void 1196do_setifpreference(prop_dictionary_t env) 1197{ 1198 struct if_addrprefreq ifap; 1199 int af; 1200 const struct afswtch *afp; 1201 prop_data_t d; 1202 const struct paddr_prefix *pfx; 1203 1204 if ((af = getaf(env)) == -1) 1205 af = AF_INET; 1206 1207 if ((afp = lookup_af_bynum(af)) == NULL) 1208 errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__); 1209 1210 memset(&ifap, 0, sizeof(ifap)); 1211 1212 if (!prop_dictionary_get_int16(env, "preference", 1213 &ifap.ifap_preference)) 1214 return; 1215 1216 d = (prop_data_t)prop_dictionary_get(env, "address"); 1217 assert(d != NULL); 1218 1219 pfx = prop_data_data_nocopy(d); 1220 1221 memcpy(&ifap.ifap_addr, &pfx->pfx_addr, 1222 MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len)); 1223 if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1) 1224 warn("SIOCSIFADDRPREF"); 1225} 1226 1227static int 1228setifmtu(prop_dictionary_t env, prop_dictionary_t xenv) 1229{ 1230 int64_t mtu; 1231 bool rc; 1232 struct ifreq ifr; 1233 1234 rc = prop_dictionary_get_int64(env, "mtu", &mtu); 1235 assert(rc); 1236 1237 ifr.ifr_mtu = mtu; 1238 if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1) 1239 warn("SIOCSIFMTU"); 1240 1241 return 0; 1242} 1243 1244static void 1245media_error(int type, const char *val, const char *opt) 1246{ 1247 errx(EXIT_FAILURE, "unknown %s media %s: %s", 1248 get_media_type_string(type), opt, val); 1249} 1250 1251void 1252init_current_media(prop_dictionary_t env, prop_dictionary_t oenv) 1253{ 1254 const char *ifname; 1255 struct ifmediareq ifmr; 1256 1257 if ((ifname = getifname(env)) == NULL) 1258 err(EXIT_FAILURE, "getifname"); 1259 1260 /* 1261 * If we have not yet done so, grab the currently-selected 1262 * media. 1263 */ 1264 1265 if (prop_dictionary_get(env, "initmedia") == NULL) { 1266 memset(&ifmr, 0, sizeof(ifmr)); 1267 1268 if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) { 1269 /* 1270 * If we get E2BIG, the kernel is telling us 1271 * that there are more, so we can ignore it. 1272 */ 1273 if (errno != E2BIG) 1274 err(EXIT_FAILURE, "SIOCGIFMEDIA"); 1275 } 1276 1277 if (!prop_dictionary_set_bool(oenv, "initmedia", true)) { 1278 err(EXIT_FAILURE, "%s: prop_dictionary_set_bool", 1279 __func__); 1280 } 1281 media_current = ifmr.ifm_current; 1282 } 1283 1284 /* Sanity. */ 1285 if (IFM_TYPE(media_current) == 0) 1286 errx(EXIT_FAILURE, "%s: no link type?", ifname); 1287} 1288 1289void 1290process_media_commands(prop_dictionary_t env) 1291{ 1292 struct ifreq ifr; 1293 1294 if (prop_dictionary_get(env, "media") == NULL && 1295 prop_dictionary_get(env, "mediaopt") == NULL && 1296 prop_dictionary_get(env, "unmediaopt") == NULL && 1297 prop_dictionary_get(env, "mediamode") == NULL) { 1298 /* Nothing to do. */ 1299 return; 1300 } 1301 1302 /* 1303 * Media already set up, and commands sanity-checked. Set/clear 1304 * any options, and we're ready to go. 1305 */ 1306 media_current |= mediaopt_set; 1307 media_current &= ~mediaopt_clear; 1308 1309 memset(&ifr, 0, sizeof(ifr)); 1310 ifr.ifr_media = media_current; 1311 1312 if (direct_ioctl(env, SIOCSIFMEDIA, &ifr) == -1) 1313 err(EXIT_FAILURE, "SIOCSIFMEDIA"); 1314} 1315 1316int 1317setmedia(prop_dictionary_t env, prop_dictionary_t xenv) 1318{ 1319 int type, subtype, inst; 1320 prop_data_t data; 1321 char *val; 1322 1323 init_current_media(env, xenv); 1324 1325 data = (prop_data_t)prop_dictionary_get(env, "media"); 1326 assert(data != NULL); 1327 1328 /* Only one media command may be given. */ 1329 /* Must not come after mode commands */ 1330 /* Must not come after mediaopt commands */ 1331 1332 /* 1333 * No need to check if `instance' has been issued; setmediainst() 1334 * craps out if `media' has not been specified. 1335 */ 1336 1337 type = IFM_TYPE(media_current); 1338 inst = IFM_INST(media_current); 1339 1340 val = strndup(prop_data_data_nocopy(data), prop_data_size(data)); 1341 if (val == NULL) 1342 return -1; 1343 1344 /* Look up the subtype. */ 1345 subtype = get_media_subtype(type, val); 1346 if (subtype == -1) 1347 media_error(type, val, "subtype"); 1348 1349 /* Build the new current media word. */ 1350 media_current = IFM_MAKEWORD(type, subtype, 0, inst); 1351 1352 /* Media will be set after other processing is complete. */ 1353 return 0; 1354} 1355 1356int 1357setmediaopt(prop_dictionary_t env, prop_dictionary_t xenv) 1358{ 1359 char *invalid; 1360 prop_data_t data; 1361 char *val; 1362 1363 init_current_media(env, xenv); 1364 1365 data = (prop_data_t)prop_dictionary_get(env, "mediaopt"); 1366 assert(data != NULL); 1367 1368 /* Can only issue `mediaopt' once. */ 1369 /* Can't issue `mediaopt' if `instance' has already been issued. */ 1370 1371 val = strndup(prop_data_data_nocopy(data), prop_data_size(data)); 1372 if (val == NULL) 1373 return -1; 1374 1375 mediaopt_set = get_media_options(media_current, val, &invalid); 1376 free(val); 1377 if (mediaopt_set == -1) 1378 media_error(media_current, invalid, "option"); 1379 1380 /* Media will be set after other processing is complete. */ 1381 return 0; 1382} 1383 1384int 1385unsetmediaopt(prop_dictionary_t env, prop_dictionary_t xenv) 1386{ 1387 char *invalid, *val; 1388 prop_data_t data; 1389 1390 init_current_media(env, xenv); 1391 1392 data = (prop_data_t)prop_dictionary_get(env, "unmediaopt"); 1393 if (data == NULL) { 1394 errno = ENOENT; 1395 return -1; 1396 } 1397 1398 val = strndup(prop_data_data_nocopy(data), prop_data_size(data)); 1399 if (val == NULL) 1400 return -1; 1401 1402 /* 1403 * No need to check for A_MEDIAINST, since the test for A_MEDIA 1404 * implicitly checks for A_MEDIAINST. 1405 */ 1406 1407 mediaopt_clear = get_media_options(media_current, val, &invalid); 1408 free(val); 1409 if (mediaopt_clear == -1) 1410 media_error(media_current, invalid, "option"); 1411 1412 /* Media will be set after other processing is complete. */ 1413 return 0; 1414} 1415 1416int 1417setmediainst(prop_dictionary_t env, prop_dictionary_t xenv) 1418{ 1419 int type, subtype, options; 1420 int64_t inst; 1421 bool rc; 1422 1423 init_current_media(env, xenv); 1424 1425 rc = prop_dictionary_get_int64(env, "mediainst", &inst); 1426 assert(rc); 1427 1428 /* Can only issue `instance' once. */ 1429 /* Must have already specified `media' */ 1430 1431 type = IFM_TYPE(media_current); 1432 subtype = IFM_SUBTYPE(media_current); 1433 options = IFM_OPTIONS(media_current); 1434 1435 media_current = IFM_MAKEWORD(type, subtype, options, inst); 1436 1437 /* Media will be set after other processing is complete. */ 1438 return 0; 1439} 1440 1441int 1442setmediamode(prop_dictionary_t env, prop_dictionary_t xenv) 1443{ 1444 int type, subtype, options, inst, mode; 1445 prop_data_t data; 1446 char *val; 1447 1448 init_current_media(env, xenv); 1449 1450 data = (prop_data_t)prop_dictionary_get(env, "mediamode"); 1451 assert(data != NULL); 1452 1453 type = IFM_TYPE(media_current); 1454 subtype = IFM_SUBTYPE(media_current); 1455 options = IFM_OPTIONS(media_current); 1456 inst = IFM_INST(media_current); 1457 1458 val = strndup(prop_data_data_nocopy(data), prop_data_size(data)); 1459 if (val == NULL) 1460 return -1; 1461 1462 mode = get_media_mode(type, val); 1463 if (mode == -1) 1464 media_error(type, val, "mode"); 1465 1466 free(val); 1467 1468 media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode; 1469 1470 /* Media will be set after other processing is complete. */ 1471 return 0; 1472} 1473 1474void 1475print_media_word(int ifmw, const char *opt_sep) 1476{ 1477 const char *str; 1478 1479 printf("%s", get_media_subtype_string(ifmw)); 1480 1481 /* Find mode. */ 1482 if (IFM_MODE(ifmw) != 0) { 1483 str = get_media_mode_string(ifmw); 1484 if (str != NULL) 1485 printf(" mode %s", str); 1486 } 1487 1488 /* Find options. */ 1489 for (; (str = get_media_option_string(&ifmw)) != NULL; opt_sep = ",") 1490 printf("%s%s", opt_sep, str); 1491 1492 if (IFM_INST(ifmw) != 0) 1493 printf(" instance %d", IFM_INST(ifmw)); 1494} 1495 1496int 1497carrier(prop_dictionary_t env) 1498{ 1499 struct ifmediareq ifmr; 1500 1501 memset(&ifmr, 0, sizeof(ifmr)); 1502 1503 if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) { 1504 /* 1505 * Interface doesn't support SIOC{G,S}IFMEDIA; 1506 * assume ok. 1507 */ 1508 return EXIT_SUCCESS; 1509 } 1510 if ((ifmr.ifm_status & IFM_AVALID) == 0) { 1511 /* 1512 * Interface doesn't report media-valid status. 1513 * assume ok. 1514 */ 1515 return EXIT_SUCCESS; 1516 } 1517 /* otherwise, return ok for active, not-ok if not active. */ 1518 if (ifmr.ifm_status & IFM_ACTIVE) 1519 return EXIT_SUCCESS; 1520 else 1521 return EXIT_FAILURE; 1522} 1523 1524const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST; 1525 1526const struct ifmedia_status_description ifm_status_descriptions[] = 1527 IFM_STATUS_DESCRIPTIONS; 1528 1529/* 1530 * Print the status of the interface. If an address family was 1531 * specified, show it and it only; otherwise, show them all. 1532 */ 1533void 1534status(const struct sockaddr_dl *sdl, prop_dictionary_t env, 1535 prop_dictionary_t oenv) 1536{ 1537 struct ifmediareq ifmr; 1538 struct ifdatareq ifdr; 1539 struct ifreq ifr; 1540 int *media_list, i; 1541 char hbuf[NI_MAXHOST]; 1542 char fbuf[BUFSIZ]; 1543 int af, s; 1544 const char *ifname; 1545 struct ifcapreq ifcr; 1546 unsigned short flags; 1547 const struct afswtch *afp; 1548 1549 if ((af = getaf(env)) == -1) { 1550 afp = NULL; 1551 af = AF_UNSPEC; 1552 } else 1553 afp = lookup_af_bynum(af); 1554 1555 /* get out early if the family is unsupported by the kernel */ 1556 if ((s = getsock(af)) == -1) 1557 err(EXIT_FAILURE, "%s: getsock", __func__); 1558 1559 if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 1560 err(EXIT_FAILURE, "%s: getifinfo", __func__); 1561 1562 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags); 1563 printf("%s: flags=%s", ifname, &fbuf[2]); 1564 1565 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1566 if (ioctl(s, SIOCGIFMETRIC, &ifr) == -1) 1567 warn("SIOCGIFMETRIC %s", ifr.ifr_name); 1568 else if (ifr.ifr_metric != 0) 1569 printf(" metric %d", ifr.ifr_metric); 1570 1571 estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1572 if (ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0) 1573 printf(" mtu %d", ifr.ifr_mtu); 1574 printf("\n"); 1575 1576 if (getifcaps(env, oenv, &ifcr) == -1) 1577 err(EXIT_FAILURE, "%s: getifcaps", __func__); 1578 1579 if (ifcr.ifcr_capabilities != 0) { 1580 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 1581 ifcr.ifcr_capabilities); 1582 printf("\tcapabilities=%s\n", &fbuf[2]); 1583 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 1584 ifcr.ifcr_capenable); 1585 printf("\tenabled=%s\n", &fbuf[2]); 1586 } 1587 1588 ieee80211_status(env, oenv); 1589 vlan_status(env, oenv); 1590#ifndef INET_ONLY 1591 carp_status(env, oenv); 1592#endif 1593 tunnel_status(env, oenv); 1594 agr_status(env, oenv); 1595 1596 if (sdl != NULL && 1597 getnameinfo((const struct sockaddr *)sdl, sdl->sdl_len, 1598 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 && 1599 hbuf[0] != '\0') 1600 printf("\taddress: %s\n", hbuf); 1601 1602 (void) memset(&ifmr, 0, sizeof(ifmr)); 1603 estrlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 1604 1605 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) { 1606 /* 1607 * Interface doesn't support SIOC{G,S}IFMEDIA. 1608 */ 1609 goto iface_stats; 1610 } 1611 1612 if (ifmr.ifm_count == 0) { 1613 warnx("%s: no media types?", ifname); 1614 goto iface_stats; 1615 } 1616 1617 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 1618 if (media_list == NULL) 1619 err(EXIT_FAILURE, "malloc"); 1620 ifmr.ifm_ulist = media_list; 1621 1622 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) 1623 err(EXIT_FAILURE, "SIOCGIFMEDIA"); 1624 1625 printf("\tmedia: %s ", get_media_type_string(ifmr.ifm_current)); 1626 print_media_word(ifmr.ifm_current, " "); 1627 if (ifmr.ifm_active != ifmr.ifm_current) { 1628 printf(" ("); 1629 print_media_word(ifmr.ifm_active, " "); 1630 printf(")"); 1631 } 1632 printf("\n"); 1633 1634 if (ifmr.ifm_status & IFM_STATUS_VALID) { 1635 const struct ifmedia_status_description *ifms; 1636 int bitno, found = 0; 1637 1638 printf("\tstatus: "); 1639 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) { 1640 for (ifms = ifm_status_descriptions; 1641 ifms->ifms_valid != 0; ifms++) { 1642 if (ifms->ifms_type != 1643 IFM_TYPE(ifmr.ifm_current) || 1644 ifms->ifms_valid != 1645 ifm_status_valid_list[bitno]) 1646 continue; 1647 printf("%s%s", found ? ", " : "", 1648 IFM_STATUS_DESC(ifms, ifmr.ifm_status)); 1649 found = 1; 1650 1651 /* 1652 * For each valid indicator bit, there's 1653 * only one entry for each media type, so 1654 * terminate the inner loop now. 1655 */ 1656 break; 1657 } 1658 } 1659 1660 if (found == 0) 1661 printf("unknown"); 1662 printf("\n"); 1663 } 1664 1665 if (mflag) { 1666 int type, printed_type; 1667 1668 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) { 1669 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) { 1670 if (IFM_TYPE(media_list[i]) != type) 1671 continue; 1672 if (printed_type == 0) { 1673 printf("\tsupported %s media:\n", 1674 get_media_type_string(type)); 1675 printed_type = 1; 1676 } 1677 printf("\t\tmedia "); 1678 print_media_word(media_list[i], " mediaopt "); 1679 printf("\n"); 1680 } 1681 } 1682 } 1683 1684 free(media_list); 1685 1686 iface_stats: 1687 if (!vflag && !zflag) 1688 goto proto_status; 1689 1690 estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 1691 1692 if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1) { 1693 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA"); 1694 } else { 1695 struct if_data * const ifi = &ifdr.ifdr_data; 1696 char buf[5]; 1697 1698#define PLURAL(n) ((n) == 1 ? "" : "s") 1699#define PLURALSTR(s) ((atof(s)) == 1.0 ? "" : "s") 1700 printf("\tinput: %llu packet%s, ", 1701 (unsigned long long) ifi->ifi_ipackets, 1702 PLURAL(ifi->ifi_ipackets)); 1703 if (hflag) { 1704 (void) humanize_number(buf, sizeof(buf), 1705 (int64_t) ifi->ifi_ibytes, "", HN_AUTOSCALE, 1706 HN_NOSPACE | HN_DECIMAL); 1707 printf("%s byte%s", buf, 1708 PLURALSTR(buf)); 1709 } else 1710 printf("%llu byte%s", 1711 (unsigned long long) ifi->ifi_ibytes, 1712 PLURAL(ifi->ifi_ibytes)); 1713 if (ifi->ifi_imcasts) 1714 printf(", %llu multicast%s", 1715 (unsigned long long) ifi->ifi_imcasts, 1716 PLURAL(ifi->ifi_imcasts)); 1717 if (ifi->ifi_ierrors) 1718 printf(", %llu error%s", 1719 (unsigned long long) ifi->ifi_ierrors, 1720 PLURAL(ifi->ifi_ierrors)); 1721 if (ifi->ifi_iqdrops) 1722 printf(", %llu queue drop%s", 1723 (unsigned long long) ifi->ifi_iqdrops, 1724 PLURAL(ifi->ifi_iqdrops)); 1725 if (ifi->ifi_noproto) 1726 printf(", %llu unknown protocol", 1727 (unsigned long long) ifi->ifi_noproto); 1728 printf("\n\toutput: %llu packet%s, ", 1729 (unsigned long long) ifi->ifi_opackets, 1730 PLURAL(ifi->ifi_opackets)); 1731 if (hflag) { 1732 (void) humanize_number(buf, sizeof(buf), 1733 (int64_t) ifi->ifi_obytes, "", HN_AUTOSCALE, 1734 HN_NOSPACE | HN_DECIMAL); 1735 printf("%s byte%s", buf, 1736 PLURALSTR(buf)); 1737 } else 1738 printf("%llu byte%s", 1739 (unsigned long long) ifi->ifi_obytes, 1740 PLURAL(ifi->ifi_obytes)); 1741 if (ifi->ifi_omcasts) 1742 printf(", %llu multicast%s", 1743 (unsigned long long) ifi->ifi_omcasts, 1744 PLURAL(ifi->ifi_omcasts)); 1745 if (ifi->ifi_oerrors) 1746 printf(", %llu error%s", 1747 (unsigned long long) ifi->ifi_oerrors, 1748 PLURAL(ifi->ifi_oerrors)); 1749 if (ifi->ifi_collisions) 1750 printf(", %llu collision%s", 1751 (unsigned long long) ifi->ifi_collisions, 1752 PLURAL(ifi->ifi_collisions)); 1753 printf("\n"); 1754#undef PLURAL 1755#undef PLURALSTR 1756 } 1757 1758 ieee80211_statistics(env); 1759 1760 proto_status: 1761 1762 if (afp != NULL) 1763 (*afp->af_status)(env, oenv, true); 1764 else for (afp = afs; afp->af_name != NULL; afp++) 1765 (*afp->af_status)(env, oenv, false); 1766} 1767 1768int 1769setifprefixlen(prop_dictionary_t env, prop_dictionary_t xenv) 1770{ 1771 const char *ifname; 1772 bool rc; 1773 int64_t plen; 1774 int af; 1775 const struct afswtch *afp; 1776 unsigned short flags; 1777 struct paddr_prefix *pfx; 1778 prop_data_t d; 1779 1780 if ((af = getaf(env)) == -1) 1781 af = AF_INET; 1782 1783 if ((afp = lookup_af_bynum(af)) == NULL) 1784 return -1; 1785 1786 if ((ifname = getifinfo(env, xenv, &flags)) == NULL) 1787 err(EXIT_FAILURE, "getifinfo"); 1788 1789 rc = prop_dictionary_get_int64(env, "prefixlen", &plen); 1790 assert(rc); 1791 1792 pfx = prefixlen_to_mask(af, plen); 1793 if (pfx == NULL) 1794 err(EXIT_FAILURE, "prefixlen_to_mask"); 1795 1796 d = prop_data_create_data(pfx, 1797 offsetof(struct paddr_prefix, pfx_addr) + pfx->pfx_addr.sa_len); 1798 if (d == NULL) 1799 err(EXIT_FAILURE, "%s: prop_data_create_data", __func__); 1800 1801 if (!prop_dictionary_set(xenv, "netmask", (prop_object_t)d)) 1802 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 1803 1804 if (afp->af_getaddr != NULL) 1805 (*afp->af_getaddr)(pfx, MASK); 1806 1807 free(pfx); 1808 return 0; 1809} 1810 1811void 1812usage(void) 1813{ 1814 const char *progname = getprogname(); 1815 1816 fprintf(stderr, 1817 "usage: %s [-h] [-m] [-v] [-z] " 1818#ifdef INET6 1819 "[-L] " 1820#endif 1821 "interface\n" 1822 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n" 1823 "\t\t[ alias | -alias ] ]\n" 1824 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n" 1825 "\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n" 1826 "\t[ list scan ]\n" 1827 "\t[ powersave | -powersave ] [ powersavesleep duration ]\n" 1828 "\t[ hidessid | -hidessid ] [ apbridge | -apbridge ]\n" 1829 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n" 1830 "\t[ arp | -arp ]\n" 1831 "\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] " 1832 "[ instance minst ]\n" 1833 "\t[ preference n ]\n" 1834 "\t[ vlan n vlanif i ]\n" 1835 "\t[ agrport i ] [ -agrport i ]\n" 1836 "\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n" 1837 "\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n" 1838 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n" 1839 " %s -a [-b] [-h] [-m] [-d] [-u] [-v] [-z] [ af ]\n" 1840 " %s -l [-b] [-d] [-u] [-s]\n" 1841 " %s -C\n" 1842 " %s interface create\n" 1843 " %s interface destroy\n", 1844 progname, progname, progname, progname, progname, progname); 1845 exit(EXIT_FAILURE); 1846} 1847