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