Home | History | Annotate | Line # | Download | only in ifconfig
ifconfig.c revision 1.208
      1 /*	$NetBSD: ifconfig.c,v 1.208 2008/07/02 07:44:14 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 __RCSID("$NetBSD: ifconfig.c,v 1.208 2008/07/02 07:44:14 dyoung Exp $");
     67 #endif /* not lint */
     68 
     69 #include <sys/param.h>
     70 #include <sys/queue.h>
     71 #include <sys/socket.h>
     72 #include <sys/ioctl.h>
     73 
     74 #include <net/if.h>
     75 #include <net/if_dl.h>
     76 #include <net/if_media.h>
     77 #include <net/if_ether.h>
     78 #include <netinet/in.h>		/* XXX */
     79 #include <netinet/in_var.h>	/* XXX */
     80 
     81 #include <netdb.h>
     82 
     83 #include <sys/protosw.h>
     84 
     85 #include <assert.h>
     86 #include <ctype.h>
     87 #include <err.h>
     88 #include <errno.h>
     89 #include <stdbool.h>
     90 #include <stddef.h>
     91 #include <stdio.h>
     92 #include <stdlib.h>
     93 #include <string.h>
     94 #include <unistd.h>
     95 #include <ifaddrs.h>
     96 #include <util.h>
     97 
     98 #include "extern.h"
     99 
    100 #include "media.h"
    101 #include "parse.h"
    102 #include "env.h"
    103 
    104 static bool bflag, dflag, hflag, sflag, uflag;
    105 bool lflag, vflag, zflag;
    106 
    107 static char gflags[10 + 26 * 2 + 1] = "AabCdhlsuvz";
    108 bool gflagset[10 + 26 * 2];
    109 
    110 static int carrier(prop_dictionary_t);
    111 static int clone_command(prop_dictionary_t, prop_dictionary_t);
    112 static void do_setifpreference(prop_dictionary_t);
    113 static int flag_index(int);
    114 static void init_afs(void);
    115 static int list_cloners(prop_dictionary_t, prop_dictionary_t);
    116 static int media_status_exec(prop_dictionary_t, prop_dictionary_t);
    117 static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t);
    118 static int notrailers(prop_dictionary_t, prop_dictionary_t);
    119 static void printall(const char *, prop_dictionary_t);
    120 static int setifaddr(prop_dictionary_t, prop_dictionary_t);
    121 static int setifbroadaddr(prop_dictionary_t, prop_dictionary_t);
    122 static int setifcaps(prop_dictionary_t, prop_dictionary_t);
    123 static int setifdstormask(prop_dictionary_t, prop_dictionary_t);
    124 static int setifflags(prop_dictionary_t, prop_dictionary_t);
    125 static int setifmetric(prop_dictionary_t, prop_dictionary_t);
    126 static int setifmtu(prop_dictionary_t, prop_dictionary_t);
    127 static int setifnetmask(prop_dictionary_t, prop_dictionary_t);
    128 static int setifprefixlen(prop_dictionary_t, prop_dictionary_t);
    129 static void status(const struct sockaddr_dl *, prop_dictionary_t,
    130     prop_dictionary_t);
    131 static void usage(void);
    132 
    133 static const struct kwinst ifflagskw[] = {
    134 	  IFKW("arp", IFF_NOARP)
    135 	, IFKW("debug", IFF_DEBUG)
    136 	, IFKW("link0", IFF_LINK0)
    137 	, IFKW("link1", IFF_LINK1)
    138 	, IFKW("link2", IFF_LINK2)
    139 	, {.k_word = "down", .k_type = KW_T_INT, .k_int = -IFF_UP}
    140 	, {.k_word = "up", .k_type = KW_T_INT, .k_int = IFF_UP}
    141 };
    142 
    143 static const struct kwinst ifcapskw[] = {
    144 	  IFKW("ip4csum-tx",	IFCAP_CSUM_IPv4_Tx)
    145 	, IFKW("ip4csum-rx",	IFCAP_CSUM_IPv4_Rx)
    146 	, IFKW("tcp4csum-tx",	IFCAP_CSUM_TCPv4_Tx)
    147 	, IFKW("tcp4csum-rx",	IFCAP_CSUM_TCPv4_Rx)
    148 	, IFKW("udp4csum-tx",	IFCAP_CSUM_UDPv4_Tx)
    149 	, IFKW("udp4csum-rx",	IFCAP_CSUM_UDPv4_Rx)
    150 	, IFKW("tcp6csum-tx",	IFCAP_CSUM_TCPv6_Tx)
    151 	, IFKW("tcp6csum-rx",	IFCAP_CSUM_TCPv6_Rx)
    152 	, IFKW("udp6csum-tx",	IFCAP_CSUM_UDPv6_Tx)
    153 	, IFKW("udp6csum-rx",	IFCAP_CSUM_UDPv6_Rx)
    154 	, IFKW("ip4csum",	IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx)
    155 	, IFKW("tcp4csum",	IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx)
    156 	, IFKW("udp4csum",	IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx)
    157 	, IFKW("tcp6csum",	IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx)
    158 	, IFKW("udp6csum",	IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx)
    159 	, IFKW("tso4",		IFCAP_TSOv4)
    160 	, IFKW("tso6",		IFCAP_TSOv6)
    161 };
    162 
    163 extern struct pbranch command_root;
    164 extern struct pbranch opt_command;
    165 extern struct pbranch opt_family, opt_silent_family;
    166 extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc;
    167 
    168 struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10,
    169     setifmetric, "metric", &command_root.pb_parser);
    170 
    171 struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10,
    172     setifmtu, "mtu", &command_root.pb_parser);
    173 
    174 struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen,
    175     "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser);
    176 
    177 struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference,
    178     "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference",
    179     &command_root.pb_parser);
    180 
    181 struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask",
    182     setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser);
    183 
    184 struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast,
    185     "broadcast address",
    186     setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser);
    187 
    188 static const struct kwinst misckw[] = {
    189 	  {.k_word = "alias", .k_key = "alias", .k_deact = "alias",
    190 	   .k_type = KW_T_BOOL, .k_neg = true,
    191 	   .k_bool = true, .k_negbool = false,
    192 	   .k_nextparser = &command_root.pb_parser}
    193 	, {.k_word = "broadcast", .k_nextparser = &parse_broadcast.pa_parser}
    194 	, {.k_word = "delete", .k_key = "alias", .k_deact = "alias",
    195 	   .k_type = KW_T_BOOL, .k_bool = false,
    196 	   .k_nextparser = &command_root.pb_parser}
    197 	, {.k_word = "metric", .k_nextparser = &parse_metric.pi_parser}
    198 	, {.k_word = "mtu", .k_nextparser = &parse_mtu.pi_parser}
    199 	, {.k_word = "netmask", .k_nextparser = &parse_netmask.pa_parser}
    200 	, {.k_word = "preference", .k_act = "address",
    201 	   .k_nextparser = &parse_preference.pi_parser}
    202 	, {.k_word = "prefixlen", .k_nextparser = &parse_prefixlen.pi_parser}
    203 	, {.k_word = "trailers", .k_neg = true,
    204 	   .k_exec = notrailers, .k_nextparser = &command_root.pb_parser}
    205 };
    206 
    207 /* key: clonecmd */
    208 static const struct kwinst clonekw[] = {
    209 	{.k_word = "create", .k_type = KW_T_INT, .k_int = SIOCIFCREATE,
    210 	 .k_nextparser = &opt_silent_family.pb_parser},
    211 	{.k_word = "destroy", .k_type = KW_T_INT, .k_int = SIOCIFDESTROY}
    212 };
    213 
    214 static struct kwinst familykw[24];
    215 
    216 struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners",
    217     list_cloners, "none");
    218 
    219 struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec,
    220     "none");
    221 
    222 struct pkw family_only =
    223     PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw,
    224 	__arraycount(familykw), &no_cmds.pt_parser);
    225 
    226 struct paddr address = PADDR_INITIALIZER(&address,
    227     "local address (address 1)",
    228     setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser);
    229 
    230 struct paddr dstormask = PADDR_INITIALIZER(&dstormask,
    231     "destination/netmask (address 2)",
    232     setifdstormask, "dstormask", NULL, "address", "dstormask",
    233     &command_root.pb_parser);
    234 
    235 struct paddr broadcast = PADDR_INITIALIZER(&broadcast,
    236     "broadcast address (address 3)",
    237     setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast",
    238     &command_root.pb_parser);
    239 
    240 static SIMPLEQ_HEAD(, afswtch) aflist = SIMPLEQ_HEAD_INITIALIZER(aflist);
    241 
    242 static SIMPLEQ_HEAD(, status_func) status_funcs =
    243     SIMPLEQ_HEAD_INITIALIZER(status_funcs);
    244 static SIMPLEQ_HEAD(, statistics_func) statistics_funcs =
    245     SIMPLEQ_HEAD_INITIALIZER(statistics_funcs);
    246 static SIMPLEQ_HEAD(, cmdloop_branch) cmdloop_branches =
    247     SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches);
    248 
    249 struct branch opt_clone_brs[] = {
    250 	  {.b_nextparser = &cloning.pk_parser}
    251 	, {.b_nextparser = &opt_family.pb_parser}
    252 }, opt_silent_family_brs[] = {
    253 	  {.b_nextparser = &silent_family.pk_parser}
    254 	, {.b_nextparser = &command_root.pb_parser}
    255 }, opt_family_brs[] = {
    256 	  {.b_nextparser = &family.pk_parser}
    257 	, {.b_nextparser = &opt_command.pb_parser}
    258 }, command_root_brs[] = {
    259 	  {.b_nextparser = &ifflags.pk_parser}
    260 	, {.b_nextparser = &ifcaps.pk_parser}
    261 	, {.b_nextparser = &kwmedia.pk_parser}
    262 	, {.b_nextparser = &misc.pk_parser}
    263 	, {.b_nextparser = &address.pa_parser}
    264 	, {.b_nextparser = &dstormask.pa_parser}
    265 	, {.b_nextparser = &broadcast.pa_parser}
    266 	, {.b_nextparser = NULL}
    267 }, opt_command_brs[] = {
    268 	  {.b_nextparser = &no_cmds.pt_parser}
    269 	, {.b_nextparser = &command_root.pb_parser}
    270 };
    271 
    272 struct branch opt_family_only_brs[] = {
    273 	  {.b_nextparser = &no_cmds.pt_parser}
    274 	, {.b_nextparser = &family_only.pk_parser}
    275 };
    276 struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only,
    277     "opt-family-only", opt_family_only_brs,
    278     __arraycount(opt_family_only_brs), true);
    279 struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command,
    280     "optional command",
    281     opt_command_brs, __arraycount(opt_command_brs), true);
    282 
    283 struct pbranch command_root = PBRANCH_INITIALIZER(&command_root,
    284     "command-root", command_root_brs, __arraycount(command_root_brs), true);
    285 
    286 struct piface iface_opt_family_only =
    287     PIFACE_INITIALIZER(&iface_opt_family_only, "iface-opt-family-only",
    288     NULL, "if", &opt_family_only.pb_parser);
    289 
    290 struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af",
    291     familykw, __arraycount(familykw), &opt_command.pb_parser);
    292 
    293 struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family",
    294     NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser);
    295 
    296 struct pkw *family_users[] = {&family_only, &family, &silent_family};
    297 
    298 struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps,
    299     "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser);
    300 
    301 struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags,
    302     "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser);
    303 
    304 struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command,
    305     "clonecmd", clonekw, __arraycount(clonekw), NULL);
    306 
    307 struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL,
    308     misckw, __arraycount(misckw), NULL);
    309 
    310 struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone,
    311     "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true);
    312 
    313 struct pbranch opt_silent_family = PBRANCH_INITIALIZER(&opt_silent_family,
    314     "optional silent family", opt_silent_family_brs,
    315     __arraycount(opt_silent_family_brs), true);
    316 
    317 struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family,
    318     "opt-family", opt_family_brs, __arraycount(opt_family_brs), true);
    319 
    320 struct piface iface_start = PIFACE_INITIALIZER(&iface_start,
    321     "iface-opt-family", NULL, "if", &opt_clone.pb_parser);
    322 
    323 struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface",
    324     media_status_exec, "if", NULL);
    325 
    326 static int
    327 check_flag(char *flags, int flag)
    328 {
    329 	if (flags != NULL && strchr(flags, flag) != NULL) {
    330 		errno = EEXIST;
    331 		return -1;
    332 	}
    333 
    334 	if (flag >= '0' && flag <= '9')
    335 		return 0;
    336 	if (flag >= 'a' && flag <= 'z')
    337 		return 0;
    338 	if (flag >= 'A' && flag <= 'Z')
    339 		return 0;
    340 
    341 	errno = EINVAL;
    342 	return -1;
    343 }
    344 
    345 void
    346 cmdloop_branch_init(cmdloop_branch_t *b, struct parser *p)
    347 {
    348 	b->b_parser = p;
    349 }
    350 
    351 void
    352 statistics_func_init(statistics_func_t *f, statistics_cb_t func)
    353 {
    354 	f->f_func = func;
    355 }
    356 
    357 void
    358 status_func_init(status_func_t *f, status_cb_t func)
    359 {
    360 	f->f_func = func;
    361 }
    362 
    363 int
    364 register_cmdloop_branch(cmdloop_branch_t *b)
    365 {
    366 	SIMPLEQ_INSERT_TAIL(&cmdloop_branches, b, b_next);
    367 	return 0;
    368 }
    369 
    370 int
    371 register_statistics(statistics_func_t *f)
    372 {
    373 	SIMPLEQ_INSERT_TAIL(&statistics_funcs, f, f_next);
    374 	return 0;
    375 }
    376 
    377 int
    378 register_status(status_func_t *f)
    379 {
    380 	SIMPLEQ_INSERT_TAIL(&status_funcs, f, f_next);
    381 	return 0;
    382 }
    383 
    384 int
    385 register_family(struct afswtch *af)
    386 {
    387 	SIMPLEQ_INSERT_TAIL(&aflist, af, af_next);
    388 	return 0;
    389 }
    390 
    391 int
    392 register_flag(int flag)
    393 {
    394 	if (check_flag(gflags, flag) == -1)
    395 		return -1;
    396 
    397 	if (strlen(gflags) + 1 >= sizeof(gflags)) {
    398 		errno = ENOMEM;
    399 		return -1;
    400 	}
    401 
    402 	gflags[strlen(gflags)] = flag;
    403 
    404 	return 0;
    405 }
    406 
    407 static int
    408 flag_index(int flag)
    409 {
    410 	if (flag >= '0' && flag <= '9')
    411 		return flag - '0';
    412 	if (flag >= 'a' && flag <= 'z')
    413 		return 10 + flag - 'a';
    414 	if (flag >= 'A' && flag <= 'Z')
    415 		return 10 + 26 + flag - 'a';
    416 
    417 	errno = EINVAL;
    418 	return -1;
    419 }
    420 
    421 static bool
    422 set_flag(int flag)
    423 {
    424 	int idx;
    425 
    426 	if ((idx = flag_index(flag)) == -1)
    427 		return false;
    428 
    429 	return gflagset[idx] = true;
    430 }
    431 
    432 bool
    433 get_flag(int flag)
    434 {
    435 	int idx;
    436 
    437 	if ((idx = flag_index(flag)) == -1)
    438 		return false;
    439 
    440 	return gflagset[idx];
    441 }
    442 
    443 static struct parser *
    444 init_parser(void)
    445 {
    446 	cmdloop_branch_t *b;
    447 
    448 	if (parser_init(&iface_opt_family_only.pif_parser) == -1)
    449 		err(EXIT_FAILURE, "parser_init(iface_opt_family_only)");
    450 	if (parser_init(&iface_only.pif_parser) == -1)
    451 		err(EXIT_FAILURE, "parser_init(iface_only)");
    452 	if (parser_init(&iface_start.pif_parser) == -1)
    453 		err(EXIT_FAILURE, "parser_init(iface_start)");
    454 
    455 	SIMPLEQ_FOREACH(b, &cmdloop_branches, b_next)
    456 		pbranch_addbranch(&command_root, b->b_parser);
    457 
    458 	return &iface_start.pif_parser;
    459 }
    460 
    461 static int
    462 no_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 
    477 static int
    478 media_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 
    492 static void
    493 do_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 
    509 int
    510 main(int argc, char **argv)
    511 {
    512 	const struct afswtch *afp;
    513 	int af, s;
    514 	bool aflag = false, Cflag = false;
    515 	struct match match[32];
    516 	size_t nmatch;
    517 	struct parser *start;
    518 	int ch, narg = 0, rc;
    519 	prop_dictionary_t env, xenv;
    520 	const char *ifname;
    521 
    522 	memset(match, 0, sizeof(match));
    523 
    524 	init_afs();
    525 
    526 	start = init_parser();
    527 
    528 	/* Parse command-line options */
    529 	aflag = vflag = zflag = false;
    530 	while ((ch = getopt(argc, argv, gflags)) != -1) {
    531 		switch (ch) {
    532 		case 'A':
    533 			warnx("-A is deprecated");
    534 			break;
    535 
    536 		case 'a':
    537 			aflag = true;
    538 			break;
    539 
    540 		case 'b':
    541 			bflag = true;
    542 			break;
    543 
    544 		case 'C':
    545 			Cflag = true;
    546 			break;
    547 
    548 		case 'd':
    549 			dflag = true;
    550 			break;
    551 		case 'h':
    552 			hflag = true;
    553 			break;
    554 		case 'l':
    555 			lflag = true;
    556 			break;
    557 
    558 		case 's':
    559 			sflag = true;
    560 			break;
    561 
    562 		case 'u':
    563 			uflag = true;
    564 			break;
    565 
    566 		case 'v':
    567 			vflag = true;
    568 			break;
    569 
    570 		case 'z':
    571 			zflag = true;
    572 			break;
    573 
    574 		default:
    575 			if (!set_flag(ch))
    576 				usage();
    577 			break;
    578 		}
    579 		switch (ch) {
    580 		case 'a':
    581 			start = &opt_family_only.pb_parser;
    582 			break;
    583 
    584 #ifdef INET6
    585 		case 'L':
    586 #endif
    587 		case 'm':
    588 		case 'v':
    589 		case 'z':
    590 			if (start != &opt_family_only.pb_parser)
    591 				start = &iface_opt_family_only.pif_parser;
    592 			break;
    593 		case 'C':
    594 			start = &cloneterm.pt_parser;
    595 			break;
    596 		case 'l':
    597 			start = &no_cmds.pt_parser;
    598 			break;
    599 		case 's':
    600 			if (start != &no_cmds.pt_parser &&
    601 			    start != &opt_family_only.pb_parser)
    602 				start = &iface_only.pif_parser;
    603 			break;
    604 		default:
    605 			break;
    606 		}
    607 	}
    608 	argc -= optind;
    609 	argv += optind;
    610 
    611 	/*
    612 	 * -l means "list all interfaces", and is mutally exclusive with
    613 	 * all other flags/commands.
    614 	 *
    615 	 * -C means "list all names of cloners", and it mutually exclusive
    616 	 * with all other flags/commands.
    617 	 *
    618 	 * -a means "print status of all interfaces".
    619 	 */
    620 	if ((lflag || Cflag) && (aflag || get_flag('m') || vflag || zflag))
    621 		usage();
    622 #ifdef INET6
    623 	if ((lflag || Cflag) && get_flag('L'))
    624 		usage();
    625 #endif
    626 	if (lflag && Cflag)
    627 		usage();
    628 
    629 	nmatch = __arraycount(match);
    630 
    631 	rc = parse(argc, argv, start, match, &nmatch, &narg);
    632 	if (rc != 0)
    633 		usage();
    634 
    635 	if ((xenv = prop_dictionary_create()) == NULL)
    636 		err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
    637 
    638 	if (matches_exec(match, xenv, nmatch) == -1)
    639 		err(EXIT_FAILURE, "exec_matches");
    640 
    641 	argc -= narg;
    642 	argv += narg;
    643 
    644 	env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL;
    645 	if (env == NULL)
    646 		env = xenv;
    647 	else
    648 		env = prop_dictionary_augment(env, xenv);
    649 
    650 	/* Process any media commands that may have been issued. */
    651 	process_media_commands(env);
    652 
    653 	if ((af = getaf(env)) == -1)
    654 		af = AF_INET;
    655 
    656 	if ((s = getsock(af)) == -1)
    657 		err(EXIT_FAILURE, "%s: getsock", __func__);
    658 
    659 	if ((ifname = getifname(env)) == NULL)
    660 		err(EXIT_FAILURE, "%s: getifname", __func__);
    661 
    662 	if ((afp = lookup_af_bynum(af)) == NULL)
    663 		errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__);
    664 
    665 	assert(afp->af_addr_commit != NULL);
    666 	(*afp->af_addr_commit)(env, xenv);
    667 
    668 	do_setifpreference(env);
    669 	do_setifcaps(env);
    670 
    671 	exit(EXIT_SUCCESS);
    672 }
    673 
    674 static void
    675 init_afs(void)
    676 {
    677 	int i;
    678 	const struct afswtch *afp;
    679 	struct kwinst kw = {.k_type = KW_T_INT};
    680 
    681 	SIMPLEQ_FOREACH(afp, &aflist, af_next) {
    682 		kw.k_word = afp->af_name;
    683 		kw.k_int = afp->af_af;
    684 		for (i = 0; i < __arraycount(familykw); i++) {
    685 			if (familykw[i].k_word == NULL) {
    686 				familykw[i] = kw;
    687 				break;
    688 			}
    689 		}
    690 	}
    691 }
    692 
    693 const struct afswtch *
    694 lookup_af_bynum(int afnum)
    695 {
    696 	const struct afswtch *afp;
    697 
    698 	SIMPLEQ_FOREACH(afp, &aflist, af_next) {
    699 		if (afp->af_af == afnum)
    700 			break;
    701 	}
    702 	return afp;
    703 }
    704 
    705 void
    706 printall(const char *ifname, prop_dictionary_t env0)
    707 {
    708 	struct ifaddrs *ifap, *ifa;
    709 	struct ifreq ifr;
    710 	const struct sockaddr_dl *sdl = NULL;
    711 	prop_dictionary_t env, oenv;
    712 	int idx;
    713 	char *p;
    714 
    715 	if (env0 == NULL)
    716 		env = prop_dictionary_create();
    717 	else
    718 		env = prop_dictionary_copy_mutable(env0);
    719 
    720 	oenv = prop_dictionary_create();
    721 
    722 	if (env == NULL || oenv == NULL)
    723 		errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__);
    724 
    725 	if (getifaddrs(&ifap) != 0)
    726 		err(EXIT_FAILURE, "getifaddrs");
    727 	p = NULL;
    728 	idx = 0;
    729 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    730 		memset(&ifr, 0, sizeof(ifr));
    731 		estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
    732 		if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
    733 			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
    734 			    ifa->ifa_addr->sa_len);
    735 		}
    736 
    737 		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
    738 			continue;
    739 		if (ifa->ifa_addr->sa_family == AF_LINK)
    740 			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
    741 		if (p && strcmp(p, ifa->ifa_name) == 0)
    742 			continue;
    743 		if (!prop_dictionary_set_cstring(env, "if", ifa->ifa_name))
    744 			continue;
    745 		p = ifa->ifa_name;
    746 
    747 		if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
    748 			continue;
    749 		if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
    750 			continue;
    751 		if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
    752 			continue;
    753 
    754 		if (sflag && carrier(env))
    755 			continue;
    756 		idx++;
    757 		/*
    758 		 * Are we just listing the interfaces?
    759 		 */
    760 		if (lflag) {
    761 			if (idx > 1)
    762 				printf(" ");
    763 			fputs(ifa->ifa_name, stdout);
    764 			continue;
    765 		}
    766 
    767 		status(sdl, env, oenv);
    768 		sdl = NULL;
    769 	}
    770 	if (lflag)
    771 		printf("\n");
    772 	prop_object_release((prop_object_t)env);
    773 	prop_object_release((prop_object_t)oenv);
    774 	freeifaddrs(ifap);
    775 }
    776 
    777 static int
    778 list_cloners(prop_dictionary_t env, prop_dictionary_t oenv)
    779 {
    780 	struct if_clonereq ifcr;
    781 	char *cp, *buf;
    782 	int idx, s;
    783 
    784 	memset(&ifcr, 0, sizeof(ifcr));
    785 
    786 	s = getsock(AF_INET);
    787 
    788 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
    789 		err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
    790 
    791 	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
    792 	if (buf == NULL)
    793 		err(EXIT_FAILURE, "unable to allocate cloner name buffer");
    794 
    795 	ifcr.ifcr_count = ifcr.ifcr_total;
    796 	ifcr.ifcr_buffer = buf;
    797 
    798 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
    799 		err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
    800 
    801 	/*
    802 	 * In case some disappeared in the mean time, clamp it down.
    803 	 */
    804 	if (ifcr.ifcr_count > ifcr.ifcr_total)
    805 		ifcr.ifcr_count = ifcr.ifcr_total;
    806 
    807 	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
    808 		if (idx > 0)
    809 			printf(" ");
    810 		printf("%s", cp);
    811 	}
    812 
    813 	printf("\n");
    814 	free(buf);
    815 	exit(EXIT_SUCCESS);
    816 }
    817 
    818 static int
    819 clone_command(prop_dictionary_t env, prop_dictionary_t xenv)
    820 {
    821 	int64_t cmd;
    822 
    823 	if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) {
    824 		errno = ENOENT;
    825 		return -1;
    826 	}
    827 
    828 	if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) {
    829 		warn("%s", __func__);
    830 		return -1;
    831 	}
    832 	return 0;
    833 }
    834 
    835 /*ARGSUSED*/
    836 static int
    837 setifaddr(prop_dictionary_t env, prop_dictionary_t xenv)
    838 {
    839 	const struct paddr_prefix *pfx0;
    840 	struct paddr_prefix *pfx;
    841 	prop_data_t d;
    842 	int af;
    843 
    844 	if ((af = getaf(env)) == -1)
    845 		af = AF_INET;
    846 
    847 	d = (prop_data_t)prop_dictionary_get(env, "address");
    848 	assert(d != NULL);
    849 	pfx0 = prop_data_data_nocopy(d);
    850 
    851 	if (pfx0->pfx_len >= 0) {
    852 		pfx = prefixlen_to_mask(af, pfx0->pfx_len);
    853 		if (pfx == NULL)
    854 			err(EXIT_FAILURE, "prefixlen_to_mask");
    855 		free(pfx);
    856 	}
    857 
    858 	return 0;
    859 }
    860 
    861 static int
    862 setifnetmask(prop_dictionary_t env, prop_dictionary_t xenv)
    863 {
    864 	const struct paddr_prefix *pfx;
    865 	prop_data_t d;
    866 
    867 	d = (prop_data_t)prop_dictionary_get(env, "dstormask");
    868 	assert(d != NULL);
    869 	pfx = prop_data_data_nocopy(d);
    870 
    871 	if (!prop_dictionary_set(xenv, "netmask", (prop_object_t)d))
    872 		return -1;
    873 
    874 	return 0;
    875 }
    876 
    877 static int
    878 setifbroadaddr(prop_dictionary_t env, prop_dictionary_t xenv)
    879 {
    880 	const struct paddr_prefix *pfx;
    881 	prop_data_t d;
    882 	unsigned short flags;
    883 
    884 	if (getifflags(env, xenv, &flags) == -1)
    885 		err(EXIT_FAILURE, "%s: getifflags", __func__);
    886 
    887 	if ((flags & IFF_BROADCAST) == 0)
    888 		errx(EXIT_FAILURE, "not a broadcast interface");
    889 
    890 	d = (prop_data_t)prop_dictionary_get(env, "broadcast");
    891 	assert(d != NULL);
    892 	pfx = prop_data_data_nocopy(d);
    893 
    894 	if (!prop_dictionary_set(xenv, "broadcast", (prop_object_t)d))
    895 		return -1;
    896 
    897 	return 0;
    898 }
    899 
    900 /*ARGSUSED*/
    901 static int
    902 notrailers(prop_dictionary_t env, prop_dictionary_t xenv)
    903 {
    904 	puts("Note: trailers are no longer sent, but always received");
    905 	return 0;
    906 }
    907 
    908 /*ARGSUSED*/
    909 static int
    910 setifdstormask(prop_dictionary_t env, prop_dictionary_t xenv)
    911 {
    912 	const char *key;
    913 	const struct paddr_prefix *pfx;
    914 	prop_data_t d;
    915 	unsigned short flags;
    916 
    917 	if (getifflags(env, xenv, &flags) == -1)
    918 		err(EXIT_FAILURE, "%s: getifflags", __func__);
    919 
    920 	d = (prop_data_t)prop_dictionary_get(env, "dstormask");
    921 	assert(d != NULL);
    922 	pfx = prop_data_data_nocopy(d);
    923 
    924 	if ((flags & IFF_BROADCAST) == 0) {
    925 		key = "dst";
    926 	} else {
    927 		key = "netmask";
    928 	}
    929 
    930 	if (!prop_dictionary_set(xenv, key, (prop_object_t)d))
    931 		return -1;
    932 
    933 	return 0;
    934 }
    935 
    936 static int
    937 setifflags(prop_dictionary_t env, prop_dictionary_t xenv)
    938 {
    939 	struct ifreq ifr;
    940 	int64_t ifflag;
    941 	bool rc;
    942 
    943 	rc = prop_dictionary_get_int64(env, "ifflag", &ifflag);
    944 	assert(rc);
    945 
    946  	if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1)
    947 		return -1;
    948 
    949 	if (ifflag < 0) {
    950 		ifflag = -ifflag;
    951 		ifr.ifr_flags &= ~ifflag;
    952 	} else
    953 		ifr.ifr_flags |= ifflag;
    954 
    955 	if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1)
    956 		return -1;
    957 
    958 	return 0;
    959 }
    960 
    961 static int
    962 getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr)
    963 {
    964 	bool rc;
    965 	struct ifcapreq ifcr;
    966 	const struct ifcapreq *tmpifcr;
    967 	prop_data_t capdata;
    968 
    969 	capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps");
    970 
    971 	if (capdata != NULL) {
    972 		tmpifcr = prop_data_data_nocopy(capdata);
    973 		*oifcr = *tmpifcr;
    974 		return 0;
    975 	}
    976 
    977 	(void)direct_ioctl(env, SIOCGIFCAP, &ifcr);
    978 	*oifcr = ifcr;
    979 
    980 	capdata = prop_data_create_data(&ifcr, sizeof(ifcr));
    981 
    982 	rc = prop_dictionary_set(oenv, "ifcaps", capdata);
    983 
    984 	prop_object_release((prop_object_t)capdata);
    985 
    986 	return rc ? 0 : -1;
    987 }
    988 
    989 static int
    990 setifcaps(prop_dictionary_t env, prop_dictionary_t oenv)
    991 {
    992 	int64_t ifcap;
    993 	int s;
    994 	bool rc;
    995 	prop_data_t capdata;
    996 	struct ifcapreq ifcr;
    997 
    998 	s = getsock(AF_INET);
    999 
   1000 	rc = prop_dictionary_get_int64(env, "ifcap", &ifcap);
   1001 	assert(rc);
   1002 
   1003 	if (getifcaps(env, oenv, &ifcr) == -1)
   1004 		return -1;
   1005 
   1006 	if (ifcap < 0) {
   1007 		ifcap = -ifcap;
   1008 		ifcr.ifcr_capenable &= ~ifcap;
   1009 	} else
   1010 		ifcr.ifcr_capenable |= ifcap;
   1011 
   1012 	if ((capdata = prop_data_create_data(&ifcr, sizeof(ifcr))) == NULL)
   1013 		return -1;
   1014 
   1015 	rc = prop_dictionary_set(oenv, "ifcaps", capdata);
   1016 	prop_object_release((prop_object_t)capdata);
   1017 
   1018 	return rc ? 0 : -1;
   1019 }
   1020 
   1021 static int
   1022 setifmetric(prop_dictionary_t env, prop_dictionary_t xenv)
   1023 {
   1024 	struct ifreq ifr;
   1025 	bool rc;
   1026 	int64_t metric;
   1027 
   1028 	rc = prop_dictionary_get_int64(env, "metric", &metric);
   1029 	assert(rc);
   1030 
   1031 	ifr.ifr_metric = metric;
   1032 	if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1)
   1033 		warn("SIOCSIFMETRIC");
   1034 	return 0;
   1035 }
   1036 
   1037 static void
   1038 do_setifpreference(prop_dictionary_t env)
   1039 {
   1040 	struct if_addrprefreq ifap;
   1041 	prop_data_t d;
   1042 	const struct paddr_prefix *pfx;
   1043 
   1044 	memset(&ifap, 0, sizeof(ifap));
   1045 
   1046 	if (!prop_dictionary_get_int16(env, "preference",
   1047 	    &ifap.ifap_preference))
   1048 		return;
   1049 
   1050 	d = (prop_data_t)prop_dictionary_get(env, "address");
   1051 	assert(d != NULL);
   1052 
   1053 	pfx = prop_data_data_nocopy(d);
   1054 
   1055 	memcpy(&ifap.ifap_addr, &pfx->pfx_addr,
   1056 	    MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len));
   1057 	if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1)
   1058 		warn("SIOCSIFADDRPREF");
   1059 }
   1060 
   1061 static int
   1062 setifmtu(prop_dictionary_t env, prop_dictionary_t xenv)
   1063 {
   1064 	int64_t mtu;
   1065 	bool rc;
   1066 	struct ifreq ifr;
   1067 
   1068 	rc = prop_dictionary_get_int64(env, "mtu", &mtu);
   1069 	assert(rc);
   1070 
   1071 	ifr.ifr_mtu = mtu;
   1072 	if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1)
   1073 		warn("SIOCSIFMTU");
   1074 
   1075 	return 0;
   1076 }
   1077 
   1078 static int
   1079 carrier(prop_dictionary_t env)
   1080 {
   1081 	struct ifmediareq ifmr;
   1082 
   1083 	memset(&ifmr, 0, sizeof(ifmr));
   1084 
   1085 	if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) {
   1086 		/*
   1087 		 * Interface doesn't support SIOC{G,S}IFMEDIA;
   1088 		 * assume ok.
   1089 		 */
   1090 		return EXIT_SUCCESS;
   1091 	}
   1092 	if ((ifmr.ifm_status & IFM_AVALID) == 0) {
   1093 		/*
   1094 		 * Interface doesn't report media-valid status.
   1095 		 * assume ok.
   1096 		 */
   1097 		return EXIT_SUCCESS;
   1098 	}
   1099 	/* otherwise, return ok for active, not-ok if not active. */
   1100 	if (ifmr.ifm_status & IFM_ACTIVE)
   1101 		return EXIT_SUCCESS;
   1102 	else
   1103 		return EXIT_FAILURE;
   1104 }
   1105 
   1106 static void
   1107 print_plural(const char *prefix, uint64_t n, const char *unit)
   1108 {
   1109 	printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s");
   1110 }
   1111 
   1112 static void
   1113 print_human_bytes(bool humanize, uint64_t n)
   1114 {
   1115 	char buf[5];
   1116 
   1117 	if (humanize) {
   1118 		(void)humanize_number(buf, sizeof(buf),
   1119 		    (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
   1120 		printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s");
   1121 	} else
   1122 		print_plural(", ", n, "byte");
   1123 }
   1124 
   1125 /*
   1126  * Print the status of the interface.  If an address family was
   1127  * specified, show it and it only; otherwise, show them all.
   1128  */
   1129 void
   1130 status(const struct sockaddr_dl *sdl, prop_dictionary_t env,
   1131     prop_dictionary_t oenv)
   1132 {
   1133 	const struct if_data *ifi;
   1134 	status_func_t *status_f;
   1135 	statistics_func_t *statistics_f;
   1136 	struct ifdatareq ifdr;
   1137 	struct ifreq ifr;
   1138 	char hbuf[NI_MAXHOST];
   1139 	char fbuf[BUFSIZ];
   1140 	int af, s;
   1141 	const char *ifname;
   1142 	struct ifcapreq ifcr;
   1143 	unsigned short flags;
   1144 	const struct afswtch *afp;
   1145 
   1146 	if ((af = getaf(env)) == -1) {
   1147 		afp = NULL;
   1148 		af = AF_UNSPEC;
   1149 	} else
   1150 		afp = lookup_af_bynum(af);
   1151 
   1152 	/* get out early if the family is unsupported by the kernel */
   1153 	if ((s = getsock(af)) == -1)
   1154 		err(EXIT_FAILURE, "%s: getsock", __func__);
   1155 
   1156 	if ((ifname = getifinfo(env, oenv, &flags)) == NULL)
   1157 		err(EXIT_FAILURE, "%s: getifinfo", __func__);
   1158 
   1159 	(void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
   1160 	printf("%s: flags=%s", ifname, &fbuf[2]);
   1161 
   1162 	estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
   1163 	if (ioctl(s, SIOCGIFMETRIC, &ifr) == -1)
   1164 		warn("SIOCGIFMETRIC %s", ifr.ifr_name);
   1165 	else if (ifr.ifr_metric != 0)
   1166 		printf(" metric %d", ifr.ifr_metric);
   1167 
   1168 	estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
   1169 	if (ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0)
   1170 		printf(" mtu %d", ifr.ifr_mtu);
   1171 	printf("\n");
   1172 
   1173 	if (getifcaps(env, oenv, &ifcr) == -1)
   1174 		err(EXIT_FAILURE, "%s: getifcaps", __func__);
   1175 
   1176 	if (ifcr.ifcr_capabilities != 0) {
   1177 		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
   1178 		    ifcr.ifcr_capabilities);
   1179 		printf("\tcapabilities=%s\n", &fbuf[2]);
   1180 		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
   1181 		    ifcr.ifcr_capenable);
   1182 		printf("\tenabled=%s\n", &fbuf[2]);
   1183 	}
   1184 
   1185 	SIMPLEQ_FOREACH(status_f, &status_funcs, f_next)
   1186 		(*status_f->f_func)(env, oenv);
   1187 
   1188 	if (sdl != NULL &&
   1189 	    getnameinfo((const struct sockaddr *)sdl, sdl->sdl_len,
   1190 		hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
   1191 	    hbuf[0] != '\0')
   1192 		printf("\taddress: %s\n", hbuf);
   1193 
   1194 	media_status(env, oenv);
   1195 
   1196 	if (!vflag && !zflag)
   1197 		goto proto_status;
   1198 
   1199 	estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name));
   1200 
   1201 	if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1)
   1202 		err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
   1203 
   1204 	ifi = &ifdr.ifdr_data;
   1205 
   1206 	print_plural("\tinput: ", ifi->ifi_ipackets, "packet");
   1207 	print_human_bytes(hflag, ifi->ifi_ibytes);
   1208 	if (ifi->ifi_imcasts)
   1209 		print_plural(", ", ifi->ifi_imcasts, "multicast");
   1210 	if (ifi->ifi_ierrors)
   1211 		print_plural(", ", ifi->ifi_ierrors, "error");
   1212 	if (ifi->ifi_iqdrops)
   1213 		print_plural(", ", ifi->ifi_iqdrops, "queue drop");
   1214 	if (ifi->ifi_noproto)
   1215 		printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto);
   1216 	print_plural("\n\toutput: ", ifi->ifi_opackets, "packet");
   1217 	print_human_bytes(hflag, ifi->ifi_obytes);
   1218 	if (ifi->ifi_omcasts)
   1219 		print_plural(", ", ifi->ifi_omcasts, "multicast");
   1220 	if (ifi->ifi_oerrors)
   1221 		print_plural(", ", ifi->ifi_oerrors, "error");
   1222 	if (ifi->ifi_collisions)
   1223 		print_plural(", ", ifi->ifi_collisions, "collision");
   1224 	printf("\n");
   1225 
   1226 	SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next)
   1227 		(*statistics_f->f_func)(env);
   1228 
   1229  proto_status:
   1230 
   1231 	if (afp != NULL)
   1232 		(*afp->af_status)(env, oenv, true);
   1233 	else SIMPLEQ_FOREACH(afp, &aflist, af_next)
   1234 		(*afp->af_status)(env, oenv, false);
   1235 }
   1236 
   1237 static int
   1238 setifprefixlen(prop_dictionary_t env, prop_dictionary_t xenv)
   1239 {
   1240 	bool rc;
   1241 	int64_t plen;
   1242 	int af;
   1243 	struct paddr_prefix *pfx;
   1244 	prop_data_t d;
   1245 
   1246 	if ((af = getaf(env)) == -1)
   1247 		af = AF_INET;
   1248 
   1249 	rc = prop_dictionary_get_int64(env, "prefixlen", &plen);
   1250 	assert(rc);
   1251 
   1252 	pfx = prefixlen_to_mask(af, plen);
   1253 	if (pfx == NULL)
   1254 		err(EXIT_FAILURE, "prefixlen_to_mask");
   1255 
   1256 	d = prop_data_create_data(pfx,
   1257 	    offsetof(struct paddr_prefix, pfx_addr) + pfx->pfx_addr.sa_len);
   1258 	if (d == NULL)
   1259 		err(EXIT_FAILURE, "%s: prop_data_create_data", __func__);
   1260 
   1261 	if (!prop_dictionary_set(xenv, "netmask", (prop_object_t)d))
   1262 		err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
   1263 
   1264 	free(pfx);
   1265 	return 0;
   1266 }
   1267 
   1268 void
   1269 usage(void)
   1270 {
   1271 	const char *progname = getprogname();
   1272 
   1273 	fprintf(stderr,
   1274 	    "usage: %s [-h] [-m] [-v] [-z] "
   1275 #ifdef INET6
   1276 		"[-L] "
   1277 #endif
   1278 		"interface\n"
   1279 		"\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
   1280 		"\t\t[ alias | -alias ] ]\n"
   1281 		"\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
   1282 		"\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
   1283 		"\t[ list scan ]\n"
   1284 		"\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
   1285 		"\t[ hidessid | -hidessid ] [ apbridge | -apbridge ]\n"
   1286 		"\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"
   1287 		"\t[ arp | -arp ]\n"
   1288 		"\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
   1289 		"[ instance minst ]\n"
   1290 		"\t[ preference n ]\n"
   1291 		"\t[ vlan n vlanif i ]\n"
   1292 		"\t[ agrport i ] [ -agrport i ]\n"
   1293 		"\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
   1294 		"\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n"
   1295 		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
   1296 		"       %s -a [-b] [-h] [-m] [-d] [-u] [-v] [-z] [ af ]\n"
   1297 		"       %s -l [-b] [-d] [-u] [-s]\n"
   1298 		"       %s -C\n"
   1299 		"       %s interface create\n"
   1300 		"       %s interface destroy\n",
   1301 		progname, progname, progname, progname, progname, progname);
   1302 	exit(EXIT_FAILURE);
   1303 }
   1304