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