ifconfig.c revision 1.215
1/*	$NetBSD: ifconfig.c,v 1.215 2009/04/04 17:10:19 plunky Exp $	*/
2
3/*-
4 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1983, 1993
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 *    may be used to endorse or promote products derived from this software
47 *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62#include <sys/cdefs.h>
63#ifndef lint
64__COPYRIGHT("@(#) Copyright (c) 1983, 1993\
65 The Regents of the University of California.  All rights reserved.");
66__RCSID("$NetBSD: ifconfig.c,v 1.215 2009/04/04 17:10:19 plunky 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
104static bool bflag, dflag, hflag, sflag, uflag;
105bool lflag, vflag, zflag;
106
107static char gflags[10 + 26 * 2 + 1] = "AabCdhlsuvz";
108bool gflagset[10 + 26 * 2];
109
110static int carrier(prop_dictionary_t);
111static int clone_command(prop_dictionary_t, prop_dictionary_t);
112static void do_setifpreference(prop_dictionary_t);
113static int flag_index(int);
114static void init_afs(void);
115static int list_cloners(prop_dictionary_t, prop_dictionary_t);
116static int media_status_exec(prop_dictionary_t, prop_dictionary_t);
117static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t);
118static int notrailers(prop_dictionary_t, prop_dictionary_t);
119static void printall(const char *, prop_dictionary_t);
120static int setifaddr(prop_dictionary_t, prop_dictionary_t);
121static int setifbroadaddr(prop_dictionary_t, prop_dictionary_t);
122static int setifcaps(prop_dictionary_t, prop_dictionary_t);
123static int setifdstormask(prop_dictionary_t, prop_dictionary_t);
124static int setifflags(prop_dictionary_t, prop_dictionary_t);
125static int setifmetric(prop_dictionary_t, prop_dictionary_t);
126static int setifmtu(prop_dictionary_t, prop_dictionary_t);
127static int setifnetmask(prop_dictionary_t, prop_dictionary_t);
128static int setifprefixlen(prop_dictionary_t, prop_dictionary_t);
129static void status(const struct sockaddr_dl *, prop_dictionary_t,
130    prop_dictionary_t);
131static void usage(void);
132
133static 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
143static 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
163extern struct pbranch command_root;
164extern struct pbranch opt_command;
165extern struct pbranch opt_family, opt_silent_family;
166extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc;
167
168struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10,
169    setifmetric, "metric", &command_root.pb_parser);
170
171struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10,
172    setifmtu, "mtu", &command_root.pb_parser);
173
174struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen,
175    "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser);
176
177struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference,
178    "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference",
179    &command_root.pb_parser);
180
181struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask",
182    setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser);
183
184struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast,
185    "broadcast address",
186    setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser);
187
188static 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 */
208static 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
214static struct kwinst familykw[24];
215
216struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners",
217    list_cloners, "none");
218
219struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec,
220    "none");
221
222struct pkw family_only =
223    PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw,
224	__arraycount(familykw), &no_cmds.pt_parser);
225
226struct paddr address = PADDR_INITIALIZER(&address,
227    "local address (address 1)",
228    setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser);
229
230struct paddr dstormask = PADDR_INITIALIZER(&dstormask,
231    "destination/netmask (address 2)",
232    setifdstormask, "dstormask", NULL, "address", "dstormask",
233    &command_root.pb_parser);
234
235struct paddr broadcast = PADDR_INITIALIZER(&broadcast,
236    "broadcast address (address 3)",
237    setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast",
238    &command_root.pb_parser);
239
240static SIMPLEQ_HEAD(, afswtch) aflist = SIMPLEQ_HEAD_INITIALIZER(aflist);
241
242static SIMPLEQ_HEAD(, usage_func) usage_funcs =
243    SIMPLEQ_HEAD_INITIALIZER(usage_funcs);
244static SIMPLEQ_HEAD(, status_func) status_funcs =
245    SIMPLEQ_HEAD_INITIALIZER(status_funcs);
246static SIMPLEQ_HEAD(, statistics_func) statistics_funcs =
247    SIMPLEQ_HEAD_INITIALIZER(statistics_funcs);
248static SIMPLEQ_HEAD(, cmdloop_branch) cmdloop_branches =
249    SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches);
250
251struct branch opt_clone_brs[] = {
252	  {.b_nextparser = &cloning.pk_parser}
253	, {.b_nextparser = &opt_family.pb_parser}
254}, opt_silent_family_brs[] = {
255	  {.b_nextparser = &silent_family.pk_parser}
256	, {.b_nextparser = &command_root.pb_parser}
257}, opt_family_brs[] = {
258	  {.b_nextparser = &family.pk_parser}
259	, {.b_nextparser = &opt_command.pb_parser}
260}, command_root_brs[] = {
261	  {.b_nextparser = &ifflags.pk_parser}
262	, {.b_nextparser = &ifcaps.pk_parser}
263	, {.b_nextparser = &kwmedia.pk_parser}
264	, {.b_nextparser = &misc.pk_parser}
265	, {.b_nextparser = &address.pa_parser}
266	, {.b_nextparser = &dstormask.pa_parser}
267	, {.b_nextparser = &broadcast.pa_parser}
268	, {.b_nextparser = NULL}
269}, opt_command_brs[] = {
270	  {.b_nextparser = &no_cmds.pt_parser}
271	, {.b_nextparser = &command_root.pb_parser}
272};
273
274struct branch opt_family_only_brs[] = {
275	  {.b_nextparser = &no_cmds.pt_parser}
276	, {.b_nextparser = &family_only.pk_parser}
277};
278struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only,
279    "opt-family-only", opt_family_only_brs,
280    __arraycount(opt_family_only_brs), true);
281struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command,
282    "optional command",
283    opt_command_brs, __arraycount(opt_command_brs), true);
284
285struct pbranch command_root = PBRANCH_INITIALIZER(&command_root,
286    "command-root", command_root_brs, __arraycount(command_root_brs), true);
287
288struct piface iface_opt_family_only =
289    PIFACE_INITIALIZER(&iface_opt_family_only, "iface-opt-family-only",
290    NULL, "if", &opt_family_only.pb_parser);
291
292struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af",
293    familykw, __arraycount(familykw), &opt_command.pb_parser);
294
295struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family",
296    NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser);
297
298struct pkw *family_users[] = {&family_only, &family, &silent_family};
299
300struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps,
301    "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser);
302
303struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags,
304    "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser);
305
306struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command,
307    "clonecmd", clonekw, __arraycount(clonekw), NULL);
308
309struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL,
310    misckw, __arraycount(misckw), NULL);
311
312struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone,
313    "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true);
314
315struct pbranch opt_silent_family = PBRANCH_INITIALIZER(&opt_silent_family,
316    "optional silent family", opt_silent_family_brs,
317    __arraycount(opt_silent_family_brs), true);
318
319struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family,
320    "opt-family", opt_family_brs, __arraycount(opt_family_brs), true);
321
322struct piface iface_start = PIFACE_INITIALIZER(&iface_start,
323    "iface-opt-family", NULL, "if", &opt_clone.pb_parser);
324
325struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface",
326    media_status_exec, "if", NULL);
327
328static bool
329flag_is_registered(const char *flags, int flag)
330{
331	return flags != NULL && strchr(flags, flag) != NULL;
332}
333
334static int
335check_flag(const char *flags, int flag)
336{
337	if (flag_is_registered(flags, flag)) {
338		errno = EEXIST;
339		return -1;
340	}
341
342	if (flag >= '0' && flag <= '9')
343		return 0;
344	if (flag >= 'a' && flag <= 'z')
345		return 0;
346	if (flag >= 'A' && flag <= 'Z')
347		return 0;
348
349	errno = EINVAL;
350	return -1;
351}
352
353void
354cmdloop_branch_init(cmdloop_branch_t *b, struct parser *p)
355{
356	b->b_parser = p;
357}
358
359void
360statistics_func_init(statistics_func_t *f, statistics_cb_t func)
361{
362	f->f_func = func;
363}
364
365void
366status_func_init(status_func_t *f, status_cb_t func)
367{
368	f->f_func = func;
369}
370
371void
372usage_func_init(usage_func_t *f, usage_cb_t func)
373{
374	f->f_func = func;
375}
376
377int
378register_cmdloop_branch(cmdloop_branch_t *b)
379{
380	SIMPLEQ_INSERT_TAIL(&cmdloop_branches, b, b_next);
381	return 0;
382}
383
384int
385register_statistics(statistics_func_t *f)
386{
387	SIMPLEQ_INSERT_TAIL(&statistics_funcs, f, f_next);
388	return 0;
389}
390
391int
392register_status(status_func_t *f)
393{
394	SIMPLEQ_INSERT_TAIL(&status_funcs, f, f_next);
395	return 0;
396}
397
398int
399register_usage(usage_func_t *f)
400{
401	SIMPLEQ_INSERT_TAIL(&usage_funcs, f, f_next);
402	return 0;
403}
404
405int
406register_family(struct afswtch *af)
407{
408	SIMPLEQ_INSERT_TAIL(&aflist, af, af_next);
409	return 0;
410}
411
412int
413register_flag(int flag)
414{
415	if (check_flag(gflags, flag) == -1)
416		return -1;
417
418	if (strlen(gflags) + 1 >= sizeof(gflags)) {
419		errno = ENOMEM;
420		return -1;
421	}
422
423	gflags[strlen(gflags)] = flag;
424
425	return 0;
426}
427
428static int
429flag_index(int flag)
430{
431	if (flag >= '0' && flag <= '9')
432		return flag - '0';
433	if (flag >= 'a' && flag <= 'z')
434		return 10 + flag - 'a';
435	if (flag >= 'A' && flag <= 'Z')
436		return 10 + 26 + flag - 'a';
437
438	errno = EINVAL;
439	return -1;
440}
441
442static bool
443set_flag(int flag)
444{
445	int idx;
446
447	if ((idx = flag_index(flag)) == -1)
448		return false;
449
450	return gflagset[idx] = true;
451}
452
453bool
454get_flag(int flag)
455{
456	int idx;
457
458	if ((idx = flag_index(flag)) == -1)
459		return false;
460
461	return gflagset[idx];
462}
463
464static struct parser *
465init_parser(void)
466{
467	cmdloop_branch_t *b;
468
469	if (parser_init(&iface_opt_family_only.pif_parser) == -1)
470		err(EXIT_FAILURE, "parser_init(iface_opt_family_only)");
471	if (parser_init(&iface_only.pif_parser) == -1)
472		err(EXIT_FAILURE, "parser_init(iface_only)");
473	if (parser_init(&iface_start.pif_parser) == -1)
474		err(EXIT_FAILURE, "parser_init(iface_start)");
475
476	SIMPLEQ_FOREACH(b, &cmdloop_branches, b_next)
477		pbranch_addbranch(&command_root, b->b_parser);
478
479	return &iface_start.pif_parser;
480}
481
482static int
483no_cmds_exec(prop_dictionary_t env, prop_dictionary_t oenv)
484{
485	const char *ifname;
486	unsigned short ignore;
487
488	/* ifname == NULL is ok.  It indicates 'ifconfig -a'. */
489	if ((ifname = getifname(env)) == NULL)
490		;
491	else if (getifflags(env, oenv, &ignore) == -1)
492		err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname);
493
494	printall(ifname, env);
495	exit(EXIT_SUCCESS);
496}
497
498static int
499media_status_exec(prop_dictionary_t env, prop_dictionary_t oenv)
500{
501	const char *ifname;
502	unsigned short ignore;
503
504	/* ifname == NULL is ok.  It indicates 'ifconfig -a'. */
505	if ((ifname = getifname(env)) == NULL)
506		;
507	else if (getifflags(env, oenv, &ignore) == -1)
508		err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname);
509
510	exit(carrier(env));
511}
512
513static void
514do_setifcaps(prop_dictionary_t env)
515{
516	struct ifcapreq ifcr;
517	prop_data_t d;
518
519	d = (prop_data_t )prop_dictionary_get(env, "ifcaps");
520	if (d == NULL)
521		return;
522
523	assert(sizeof(ifcr) == prop_data_size(d));
524
525	memcpy(&ifcr, prop_data_data_nocopy(d), sizeof(ifcr));
526	if (direct_ioctl(env, SIOCSIFCAP, &ifcr) == -1)
527		err(EXIT_FAILURE, "SIOCSIFCAP");
528}
529
530int
531main(int argc, char **argv)
532{
533	const struct afswtch *afp;
534	int af, s;
535	bool aflag = false, Cflag = false;
536	struct match match[32];
537	size_t nmatch;
538	struct parser *start;
539	int ch, narg = 0, rc;
540	prop_dictionary_t env, oenv;
541	const char *ifname;
542
543	memset(match, 0, sizeof(match));
544
545	init_afs();
546
547	start = init_parser();
548
549	/* Parse command-line options */
550	aflag = vflag = zflag = false;
551	while ((ch = getopt(argc, argv, gflags)) != -1) {
552		switch (ch) {
553		case 'A':
554			warnx("-A is deprecated");
555			break;
556
557		case 'a':
558			aflag = true;
559			break;
560
561		case 'b':
562			bflag = true;
563			break;
564
565		case 'C':
566			Cflag = true;
567			break;
568
569		case 'd':
570			dflag = true;
571			break;
572		case 'h':
573			hflag = true;
574			break;
575		case 'l':
576			lflag = true;
577			break;
578
579		case 's':
580			sflag = true;
581			break;
582
583		case 'u':
584			uflag = true;
585			break;
586
587		case 'v':
588			vflag = true;
589			break;
590
591		case 'z':
592			zflag = true;
593			break;
594
595		default:
596			if (!set_flag(ch))
597				usage();
598			break;
599		}
600		switch (ch) {
601		case 'a':
602			start = &opt_family_only.pb_parser;
603			break;
604
605		case 'L':
606		case 'm':
607		case 'v':
608		case 'z':
609			if (start != &opt_family_only.pb_parser)
610				start = &iface_opt_family_only.pif_parser;
611			break;
612		case 'C':
613			start = &cloneterm.pt_parser;
614			break;
615		case 'l':
616			start = &no_cmds.pt_parser;
617			break;
618		case 's':
619			if (start != &no_cmds.pt_parser &&
620			    start != &opt_family_only.pb_parser)
621				start = &iface_only.pif_parser;
622			break;
623		default:
624			break;
625		}
626	}
627	argc -= optind;
628	argv += optind;
629
630	/*
631	 * -l means "list all interfaces", and is mutally exclusive with
632	 * all other flags/commands.
633	 *
634	 * -C means "list all names of cloners", and it mutually exclusive
635	 * with all other flags/commands.
636	 *
637	 * -a means "print status of all interfaces".
638	 */
639	if ((lflag || Cflag) && (aflag || get_flag('m') || vflag || zflag))
640		usage();
641	if ((lflag || Cflag) && get_flag('L'))
642		usage();
643	if (lflag && Cflag)
644		usage();
645
646	nmatch = __arraycount(match);
647
648	rc = parse(argc, argv, start, match, &nmatch, &narg);
649	if (rc != 0)
650		usage();
651
652	if ((oenv = prop_dictionary_create()) == NULL)
653		err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
654
655	if (matches_exec(match, oenv, nmatch) == -1)
656		err(EXIT_FAILURE, "exec_matches");
657
658	argc -= narg;
659	argv += narg;
660
661	env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL;
662	if (env == NULL)
663		env = oenv;
664	else
665		env = prop_dictionary_augment(env, oenv);
666
667	/* Process any media commands that may have been issued. */
668	process_media_commands(env);
669
670	if ((af = getaf(env)) == -1)
671		af = AF_INET;
672
673	if ((s = getsock(af)) == -1)
674		err(EXIT_FAILURE, "%s: getsock", __func__);
675
676	if ((ifname = getifname(env)) == NULL)
677		err(EXIT_FAILURE, "%s: getifname", __func__);
678
679	if ((afp = lookup_af_bynum(af)) == NULL)
680		errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__);
681
682	assert(afp->af_addr_commit != NULL);
683	(*afp->af_addr_commit)(env, oenv);
684
685	do_setifpreference(env);
686	do_setifcaps(env);
687
688	exit(EXIT_SUCCESS);
689}
690
691static void
692init_afs(void)
693{
694	size_t i;
695	const struct afswtch *afp;
696	struct kwinst kw = {.k_type = KW_T_INT};
697
698	SIMPLEQ_FOREACH(afp, &aflist, af_next) {
699		kw.k_word = afp->af_name;
700		kw.k_int = afp->af_af;
701		for (i = 0; i < __arraycount(familykw); i++) {
702			if (familykw[i].k_word == NULL) {
703				familykw[i] = kw;
704				break;
705			}
706		}
707	}
708}
709
710const struct afswtch *
711lookup_af_bynum(int afnum)
712{
713	const struct afswtch *afp;
714
715	SIMPLEQ_FOREACH(afp, &aflist, af_next) {
716		if (afp->af_af == afnum)
717			break;
718	}
719	return afp;
720}
721
722void
723printall(const char *ifname, prop_dictionary_t env0)
724{
725	struct ifaddrs *ifap, *ifa;
726	struct ifreq ifr;
727	const struct sockaddr_dl *sdl = NULL;
728	prop_dictionary_t env, oenv;
729	int idx;
730	char *p;
731
732	if (env0 == NULL)
733		env = prop_dictionary_create();
734	else
735		env = prop_dictionary_copy_mutable(env0);
736
737	oenv = prop_dictionary_create();
738
739	if (env == NULL || oenv == NULL)
740		errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__);
741
742	if (getifaddrs(&ifap) != 0)
743		err(EXIT_FAILURE, "getifaddrs");
744	p = NULL;
745	idx = 0;
746	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
747		memset(&ifr, 0, sizeof(ifr));
748		estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
749		if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
750			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
751			    ifa->ifa_addr->sa_len);
752		}
753
754		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
755			continue;
756		if (ifa->ifa_addr->sa_family == AF_LINK)
757			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
758		if (p && strcmp(p, ifa->ifa_name) == 0)
759			continue;
760		if (!prop_dictionary_set_cstring(env, "if", ifa->ifa_name))
761			continue;
762		p = ifa->ifa_name;
763
764		if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
765			continue;
766		if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
767			continue;
768		if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
769			continue;
770
771		if (sflag && carrier(env))
772			continue;
773		idx++;
774		/*
775		 * Are we just listing the interfaces?
776		 */
777		if (lflag) {
778			if (idx > 1)
779				printf(" ");
780			fputs(ifa->ifa_name, stdout);
781			continue;
782		}
783
784		status(sdl, env, oenv);
785		sdl = NULL;
786	}
787	if (lflag)
788		printf("\n");
789	prop_object_release((prop_object_t)env);
790	prop_object_release((prop_object_t)oenv);
791	freeifaddrs(ifap);
792}
793
794static int
795list_cloners(prop_dictionary_t env, prop_dictionary_t oenv)
796{
797	struct if_clonereq ifcr;
798	char *cp, *buf;
799	int idx, s;
800
801	memset(&ifcr, 0, sizeof(ifcr));
802
803	s = getsock(AF_INET);
804
805	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
806		err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
807
808	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
809	if (buf == NULL)
810		err(EXIT_FAILURE, "unable to allocate cloner name buffer");
811
812	ifcr.ifcr_count = ifcr.ifcr_total;
813	ifcr.ifcr_buffer = buf;
814
815	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
816		err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
817
818	/*
819	 * In case some disappeared in the mean time, clamp it down.
820	 */
821	if (ifcr.ifcr_count > ifcr.ifcr_total)
822		ifcr.ifcr_count = ifcr.ifcr_total;
823
824	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
825		if (idx > 0)
826			printf(" ");
827		printf("%s", cp);
828	}
829
830	printf("\n");
831	free(buf);
832	exit(EXIT_SUCCESS);
833}
834
835static int
836clone_command(prop_dictionary_t env, prop_dictionary_t oenv)
837{
838	int64_t cmd;
839
840	if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) {
841		errno = ENOENT;
842		return -1;
843	}
844
845	if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) {
846		warn("%s", __func__);
847		return -1;
848	}
849	return 0;
850}
851
852/*ARGSUSED*/
853static int
854setifaddr(prop_dictionary_t env, prop_dictionary_t oenv)
855{
856	const struct paddr_prefix *pfx0;
857	struct paddr_prefix *pfx;
858	prop_data_t d;
859	int af;
860
861	if ((af = getaf(env)) == -1)
862		af = AF_INET;
863
864	d = (prop_data_t)prop_dictionary_get(env, "address");
865	assert(d != NULL);
866	pfx0 = prop_data_data_nocopy(d);
867
868	if (pfx0->pfx_len >= 0) {
869		pfx = prefixlen_to_mask(af, pfx0->pfx_len);
870		if (pfx == NULL)
871			err(EXIT_FAILURE, "prefixlen_to_mask");
872		free(pfx);
873	}
874
875	return 0;
876}
877
878static int
879setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv)
880{
881	const struct paddr_prefix *pfx;
882	prop_data_t d;
883
884	d = (prop_data_t)prop_dictionary_get(env, "dstormask");
885	assert(d != NULL);
886	pfx = prop_data_data_nocopy(d);
887
888	if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d))
889		return -1;
890
891	return 0;
892}
893
894static int
895setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv)
896{
897	const struct paddr_prefix *pfx;
898	prop_data_t d;
899	unsigned short flags;
900
901	if (getifflags(env, oenv, &flags) == -1)
902		err(EXIT_FAILURE, "%s: getifflags", __func__);
903
904	if ((flags & IFF_BROADCAST) == 0)
905		errx(EXIT_FAILURE, "not a broadcast interface");
906
907	d = (prop_data_t)prop_dictionary_get(env, "broadcast");
908	assert(d != NULL);
909	pfx = prop_data_data_nocopy(d);
910
911	if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d))
912		return -1;
913
914	return 0;
915}
916
917/*ARGSUSED*/
918static int
919notrailers(prop_dictionary_t env, prop_dictionary_t oenv)
920{
921	puts("Note: trailers are no longer sent, but always received");
922	return 0;
923}
924
925/*ARGSUSED*/
926static int
927setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv)
928{
929	const char *key;
930	const struct paddr_prefix *pfx;
931	prop_data_t d;
932	unsigned short flags;
933
934	if (getifflags(env, oenv, &flags) == -1)
935		err(EXIT_FAILURE, "%s: getifflags", __func__);
936
937	d = (prop_data_t)prop_dictionary_get(env, "dstormask");
938	assert(d != NULL);
939	pfx = prop_data_data_nocopy(d);
940
941	if ((flags & IFF_BROADCAST) == 0) {
942		key = "dst";
943	} else {
944		key = "netmask";
945	}
946
947	if (!prop_dictionary_set(oenv, key, (prop_object_t)d))
948		return -1;
949
950	return 0;
951}
952
953static int
954setifflags(prop_dictionary_t env, prop_dictionary_t oenv)
955{
956	struct ifreq ifr;
957	int64_t ifflag;
958	bool rc;
959
960	rc = prop_dictionary_get_int64(env, "ifflag", &ifflag);
961	assert(rc);
962
963 	if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1)
964		return -1;
965
966	if (ifflag < 0) {
967		ifflag = -ifflag;
968		ifr.ifr_flags &= ~ifflag;
969	} else
970		ifr.ifr_flags |= ifflag;
971
972	if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1)
973		return -1;
974
975	return 0;
976}
977
978static int
979getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr)
980{
981	bool rc;
982	struct ifcapreq ifcr;
983	const struct ifcapreq *tmpifcr;
984	prop_data_t capdata;
985
986	capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps");
987
988	if (capdata != NULL) {
989		tmpifcr = prop_data_data_nocopy(capdata);
990		*oifcr = *tmpifcr;
991		return 0;
992	}
993
994	(void)direct_ioctl(env, SIOCGIFCAP, &ifcr);
995	*oifcr = ifcr;
996
997	capdata = prop_data_create_data(&ifcr, sizeof(ifcr));
998
999	rc = prop_dictionary_set(oenv, "ifcaps", capdata);
1000
1001	prop_object_release((prop_object_t)capdata);
1002
1003	return rc ? 0 : -1;
1004}
1005
1006static int
1007setifcaps(prop_dictionary_t env, prop_dictionary_t oenv)
1008{
1009	int64_t ifcap;
1010	int s;
1011	bool rc;
1012	prop_data_t capdata;
1013	struct ifcapreq ifcr;
1014
1015	s = getsock(AF_INET);
1016
1017	rc = prop_dictionary_get_int64(env, "ifcap", &ifcap);
1018	assert(rc);
1019
1020	if (getifcaps(env, oenv, &ifcr) == -1)
1021		return -1;
1022
1023	if (ifcap < 0) {
1024		ifcap = -ifcap;
1025		ifcr.ifcr_capenable &= ~ifcap;
1026	} else
1027		ifcr.ifcr_capenable |= ifcap;
1028
1029	if ((capdata = prop_data_create_data(&ifcr, sizeof(ifcr))) == NULL)
1030		return -1;
1031
1032	rc = prop_dictionary_set(oenv, "ifcaps", capdata);
1033	prop_object_release((prop_object_t)capdata);
1034
1035	return rc ? 0 : -1;
1036}
1037
1038static int
1039setifmetric(prop_dictionary_t env, prop_dictionary_t oenv)
1040{
1041	struct ifreq ifr;
1042	bool rc;
1043	int64_t metric;
1044
1045	rc = prop_dictionary_get_int64(env, "metric", &metric);
1046	assert(rc);
1047
1048	ifr.ifr_metric = metric;
1049	if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1)
1050		warn("SIOCSIFMETRIC");
1051	return 0;
1052}
1053
1054static void
1055do_setifpreference(prop_dictionary_t env)
1056{
1057	struct if_addrprefreq ifap;
1058	prop_data_t d;
1059	const struct paddr_prefix *pfx;
1060
1061	memset(&ifap, 0, sizeof(ifap));
1062
1063	if (!prop_dictionary_get_int16(env, "preference",
1064	    &ifap.ifap_preference))
1065		return;
1066
1067	d = (prop_data_t)prop_dictionary_get(env, "address");
1068	assert(d != NULL);
1069
1070	pfx = prop_data_data_nocopy(d);
1071
1072	memcpy(&ifap.ifap_addr, &pfx->pfx_addr,
1073	    MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len));
1074	if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1)
1075		warn("SIOCSIFADDRPREF");
1076}
1077
1078static int
1079setifmtu(prop_dictionary_t env, prop_dictionary_t oenv)
1080{
1081	int64_t mtu;
1082	bool rc;
1083	struct ifreq ifr;
1084
1085	rc = prop_dictionary_get_int64(env, "mtu", &mtu);
1086	assert(rc);
1087
1088	ifr.ifr_mtu = mtu;
1089	if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1)
1090		warn("SIOCSIFMTU");
1091
1092	return 0;
1093}
1094
1095static int
1096carrier(prop_dictionary_t env)
1097{
1098	struct ifmediareq ifmr;
1099
1100	memset(&ifmr, 0, sizeof(ifmr));
1101
1102	if (direct_ioctl(env, SIOCGIFMEDIA, &ifmr) == -1) {
1103		/*
1104		 * Interface doesn't support SIOC{G,S}IFMEDIA;
1105		 * assume ok.
1106		 */
1107		return EXIT_SUCCESS;
1108	}
1109	if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1110		/*
1111		 * Interface doesn't report media-valid status.
1112		 * assume ok.
1113		 */
1114		return EXIT_SUCCESS;
1115	}
1116	/* otherwise, return ok for active, not-ok if not active. */
1117	if (ifmr.ifm_status & IFM_ACTIVE)
1118		return EXIT_SUCCESS;
1119	else
1120		return EXIT_FAILURE;
1121}
1122
1123static void
1124print_plural(const char *prefix, uint64_t n, const char *unit)
1125{
1126	printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s");
1127}
1128
1129static void
1130print_human_bytes(bool humanize, uint64_t n)
1131{
1132	char buf[5];
1133
1134	if (humanize) {
1135		(void)humanize_number(buf, sizeof(buf),
1136		    (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
1137		printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s");
1138	} else
1139		print_plural(", ", n, "byte");
1140}
1141
1142/*
1143 * Print the status of the interface.  If an address family was
1144 * specified, show it and it only; otherwise, show them all.
1145 */
1146void
1147status(const struct sockaddr_dl *sdl, prop_dictionary_t env,
1148    prop_dictionary_t oenv)
1149{
1150	const struct if_data *ifi;
1151	status_func_t *status_f;
1152	statistics_func_t *statistics_f;
1153	struct ifdatareq ifdr;
1154	struct ifreq ifr;
1155	char hbuf[NI_MAXHOST];
1156	char fbuf[BUFSIZ];
1157	int af, s;
1158	const char *ifname;
1159	struct ifcapreq ifcr;
1160	unsigned short flags;
1161	const struct afswtch *afp;
1162
1163	if ((af = getaf(env)) == -1) {
1164		afp = NULL;
1165		af = AF_UNSPEC;
1166	} else
1167		afp = lookup_af_bynum(af);
1168
1169	/* get out early if the family is unsupported by the kernel */
1170	if ((s = getsock(af)) == -1)
1171		err(EXIT_FAILURE, "%s: getsock", __func__);
1172
1173	if ((ifname = getifinfo(env, oenv, &flags)) == NULL)
1174		err(EXIT_FAILURE, "%s: getifinfo", __func__);
1175
1176	(void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
1177	printf("%s: flags=%s", ifname, &fbuf[2]);
1178
1179	estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1180	if (ioctl(s, SIOCGIFMETRIC, &ifr) == -1)
1181		warn("SIOCGIFMETRIC %s", ifr.ifr_name);
1182	else if (ifr.ifr_metric != 0)
1183		printf(" metric %d", ifr.ifr_metric);
1184
1185	estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1186	if (ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0)
1187		printf(" mtu %d", ifr.ifr_mtu);
1188	printf("\n");
1189
1190	if (getifcaps(env, oenv, &ifcr) == -1)
1191		err(EXIT_FAILURE, "%s: getifcaps", __func__);
1192
1193	if (ifcr.ifcr_capabilities != 0) {
1194		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1195		    ifcr.ifcr_capabilities);
1196		printf("\tcapabilities=%s\n", &fbuf[2]);
1197		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1198		    ifcr.ifcr_capenable);
1199		printf("\tenabled=%s\n", &fbuf[2]);
1200	}
1201
1202	SIMPLEQ_FOREACH(status_f, &status_funcs, f_next)
1203		(*status_f->f_func)(env, oenv);
1204
1205	if (sdl != NULL &&
1206	    getnameinfo((const struct sockaddr *)sdl, sdl->sdl_len,
1207		hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
1208	    hbuf[0] != '\0')
1209		printf("\taddress: %s\n", hbuf);
1210
1211	media_status(env, oenv);
1212
1213	if (!vflag && !zflag)
1214		goto proto_status;
1215
1216	estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name));
1217
1218	if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1)
1219		err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
1220
1221	ifi = &ifdr.ifdr_data;
1222
1223	print_plural("\tinput: ", ifi->ifi_ipackets, "packet");
1224	print_human_bytes(hflag, ifi->ifi_ibytes);
1225	if (ifi->ifi_imcasts)
1226		print_plural(", ", ifi->ifi_imcasts, "multicast");
1227	if (ifi->ifi_ierrors)
1228		print_plural(", ", ifi->ifi_ierrors, "error");
1229	if (ifi->ifi_iqdrops)
1230		print_plural(", ", ifi->ifi_iqdrops, "queue drop");
1231	if (ifi->ifi_noproto)
1232		printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto);
1233	print_plural("\n\toutput: ", ifi->ifi_opackets, "packet");
1234	print_human_bytes(hflag, ifi->ifi_obytes);
1235	if (ifi->ifi_omcasts)
1236		print_plural(", ", ifi->ifi_omcasts, "multicast");
1237	if (ifi->ifi_oerrors)
1238		print_plural(", ", ifi->ifi_oerrors, "error");
1239	if (ifi->ifi_collisions)
1240		print_plural(", ", ifi->ifi_collisions, "collision");
1241	printf("\n");
1242
1243	SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next)
1244		(*statistics_f->f_func)(env);
1245
1246 proto_status:
1247
1248	if (afp != NULL)
1249		(*afp->af_status)(env, oenv, true);
1250	else SIMPLEQ_FOREACH(afp, &aflist, af_next)
1251		(*afp->af_status)(env, oenv, false);
1252}
1253
1254static int
1255setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv)
1256{
1257	bool rc;
1258	int64_t plen;
1259	int af;
1260	struct paddr_prefix *pfx;
1261	prop_data_t d;
1262
1263	if ((af = getaf(env)) == -1)
1264		af = AF_INET;
1265
1266	rc = prop_dictionary_get_int64(env, "prefixlen", &plen);
1267	assert(rc);
1268
1269	pfx = prefixlen_to_mask(af, plen);
1270	if (pfx == NULL)
1271		err(EXIT_FAILURE, "prefixlen_to_mask");
1272
1273	d = prop_data_create_data(pfx, paddr_prefix_size(pfx));
1274	if (d == NULL)
1275		err(EXIT_FAILURE, "%s: prop_data_create_data", __func__);
1276
1277	if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d))
1278		err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
1279
1280	free(pfx);
1281	return 0;
1282}
1283
1284static void
1285usage(void)
1286{
1287	const char *progname = getprogname();
1288	usage_func_t *usage_f;
1289	prop_dictionary_t env;
1290
1291	if ((env = prop_dictionary_create()) == NULL)
1292		err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
1293
1294	fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n"
1295		"\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
1296		"\t\t[ alias | -alias ] ]\n"
1297		"\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname,
1298		flag_is_registered(gflags, 'm') ? "[-m] " : "",
1299		flag_is_registered(gflags, 'L') ? "[-L] " : "");
1300
1301	SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next)
1302		(*usage_f->f_func)(env);
1303
1304	fprintf(stderr,
1305		"\t[ arp | -arp ]\n"
1306		"\t[ preference n ]\n"
1307		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
1308		"       %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n"
1309		"       %s -l [-b] [-d] [-s] [-u]\n"
1310		"       %s -C\n"
1311		"       %s interface create\n"
1312		"       %s interface destroy\n",
1313		progname, flag_is_registered(gflags, 'm') ? "[-m] " : "",
1314		progname, progname, progname, progname);
1315
1316	prop_object_release((prop_object_t)env);
1317	exit(EXIT_FAILURE);
1318}
1319