1872b698pfg/*-
2872b698pfg * SPDX-License-Identifier: BSD-3-Clause
3872b698pfg *
4d038e02rgrimes * Copyright (c) 1983, 1993
5d038e02rgrimes *	The Regents of the University of California.  All rights reserved.
6d038e02rgrimes *
7d038e02rgrimes * Redistribution and use in source and binary forms, with or without
8d038e02rgrimes * modification, are permitted provided that the following conditions
9d038e02rgrimes * are met:
10d038e02rgrimes * 1. Redistributions of source code must retain the above copyright
11d038e02rgrimes *    notice, this list of conditions and the following disclaimer.
12d038e02rgrimes * 2. Redistributions in binary form must reproduce the above copyright
13d038e02rgrimes *    notice, this list of conditions and the following disclaimer in the
14d038e02rgrimes *    documentation and/or other materials provided with the distribution.
157e6cabdimp * 3. Neither the name of the University nor the names of its contributors
16d038e02rgrimes *    may be used to endorse or promote products derived from this software
17d038e02rgrimes *    without specific prior written permission.
18d038e02rgrimes *
19d038e02rgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20d038e02rgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21d038e02rgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22d038e02rgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23d038e02rgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24d038e02rgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25d038e02rgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26d038e02rgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27d038e02rgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28d038e02rgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29d038e02rgrimes * SUCH DAMAGE.
30d038e02rgrimes */
31d038e02rgrimes
32d038e02rgrimes#ifndef lint
331ee570ewollmanstatic const char copyright[] =
34d038e02rgrimes"@(#) Copyright (c) 1983, 1993\n\
35d038e02rgrimes	The Regents of the University of California.  All rights reserved.\n";
36d038e02rgrimes#endif /* not lint */
37d038e02rgrimes
38d038e02rgrimes#ifndef lint
39dde477fcharnier#if 0
40d038e02rgrimesstatic char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
41dde477fcharnier#endif
421ee570ewollmanstatic const char rcsid[] =
4376f0c92peter  "$FreeBSD$";
44d038e02rgrimes#endif /* not lint */
45d038e02rgrimes
46d038e02rgrimes#include <sys/param.h>
47d038e02rgrimes#include <sys/ioctl.h>
484d16916msmith#include <sys/module.h>
494d16916msmith#include <sys/linker.h>
506a39979vsevolod#include <sys/queue.h>
51224e90angie#include <sys/socket.h>
52224e90angie#include <sys/time.h>
53d038e02rgrimes
5482e4a37wpaul#include <net/ethernet.h>
55d038e02rgrimes#include <net/if.h>
5619e605ajkh#include <net/if_dl.h>
5776ccec8peter#include <net/if_types.h>
5876ccec8peter#include <net/route.h>
591ee570ewollman
601ee570ewollman/* IP */
61d038e02rgrimes#include <netinet/in.h>
6219e605ajkh#include <netinet/in_var.h>
63d038e02rgrimes#include <arpa/inet.h>
6490ae06djulian#include <netdb.h>
6590ae06djulian
66dd5a75deugen#include <fnmatch.h>
67cd822ecsam#include <ifaddrs.h>
68d038e02rgrimes#include <ctype.h>
69d038e02rgrimes#include <err.h>
70d038e02rgrimes#include <errno.h>
711ee570ewollman#include <fcntl.h>
720cc840ermh#ifdef JAIL
731773242jamie#include <jail.h>
740cc840ermh#endif
75408cf30kevans#include <stdbool.h>
76d038e02rgrimes#include <stdio.h>
77d038e02rgrimes#include <stdlib.h>
78d038e02rgrimes#include <string.h>
79d038e02rgrimes#include <unistd.h>
80d038e02rgrimes
8154b5e92peter#include "ifconfig.h"
8254b5e92peter
832b707fbyongari/*
842b707fbyongari * Since "struct ifreq" is composed of various union members, callers
853a0070cgjb * should pay special attention to interpret the value.
862b707fbyongari * (.e.g. little/big endian difference in the structure.)
872b707fbyongari */
8868cd876samstruct	ifreq ifr;
89d038e02rgrimes
90280fcfebrookschar	name[IFNAMSIZ];
91d9a0cd0delphijchar	*descr = NULL;
92d9a0cd0delphijsize_t	descrlen = 64;
93d038e02rgrimesint	setaddr;
94ad2a925umeint	setmask;
95d038e02rgrimesint	doalias;
96d038e02rgrimesint	clearaddr;
97d038e02rgrimesint	newaddr = 1;
9868cd876samint	verbose;
99fca2195thompsaint	noload;
10033ef68fkpint	printifname = 0;
101d038e02rgrimes
10268cd876samint	supmedia = 0;
1032df666arwatsonint	printkeys = 0;		/* Print keying material for interfaces. */
104dde41c9gallatinint	exit_code = 0;
1051ee570ewollman
106700d268allanjude/* Formatter Strings */
1078e48e06allanjudechar	*f_inet, *f_inet6, *f_ether, *f_addr;
108700d268allanjude
109dd5a75deugenstatic	bool group_member(const char *ifname, const char *match,
110dd5a75deugen		const char *nomatch);
1111cec369samstatic	int ifconfig(int argc, char *const *argv, int iscreate,
1121cec369sam		const struct afswtch *afp);
113cd822ecsamstatic	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
114cd822ecsam		struct ifaddrs *ifa);
11568cd876samstatic	void tunnel_status(int s);
116c38387bmarkjstatic _Noreturn void usage(void);
11770f0bdfshin
118247f8f7pkelseystatic int getifflags(const char *ifname, int us);
119247f8f7pkelsey
12068cd876samstatic struct afswtch *af_getbyname(const char *name);
12168cd876samstatic struct afswtch *af_getbyfamily(int af);
12265cf57fsamstatic void af_other_status(int);
123d038e02rgrimes
12433ef68fkpvoid printifnamemaybe(void);
12533ef68fkp
12668cd876samstatic struct option *opts = NULL;
12776ccec8peter
1286a39979vsevolodstruct ifa_order_elt {
1296a39979vsevolod	int if_order;
1306a39979vsevolod	int af_orders[255];
1316a39979vsevolod	struct ifaddrs *ifa;
1326a39979vsevolod	TAILQ_ENTRY(ifa_order_elt) link;
1336a39979vsevolod};
1346a39979vsevolod
1356a39979vsevolodTAILQ_HEAD(ifa_queue, ifa_order_elt);
1366a39979vsevolod
1370f415eekevansstatic struct module_map_entry {
1380f415eekevans	const char *ifname;
1390f415eekevans	const char *kldname;
1400f415eekevans} module_map[] = {
1410f415eekevans	{
1420f415eekevans		.ifname = "tun",
1430f415eekevans		.kldname = "if_tuntap",
1440f415eekevans	},
1450f415eekevans	{
1460f415eekevans		.ifname = "tap",
1470f415eekevans		.kldname = "if_tuntap",
1480f415eekevans	},
1490f415eekevans	{
1500f415eekevans		.ifname = "vmnet",
1510f415eekevans		.kldname = "if_tuntap",
1520f415eekevans	},
153408cf30kevans	{
154408cf30kevans		.ifname = "ipsec",
155408cf30kevans		.kldname = "ipsec",
156408cf30kevans	},
157408cf30kevans	{
158408cf30kevans		/*
159408cf30kevans		 * This mapping exists because there is a conflicting enc module
160408cf30kevans		 * in CAM.  ifconfig's guessing behavior will attempt to match
161408cf30kevans		 * the ifname to a module as well as if_${ifname} and clash with
162408cf30kevans		 * CAM enc.  This is an assertion of the correct module to load.
163408cf30kevans		 */
164408cf30kevans		.ifname = "enc",
165408cf30kevans		.kldname = "if_enc",
166408cf30kevans	},
1670f415eekevans};
1680f415eekevans
1690f415eekevans
17076ccec8petervoid
17168cd876samopt_register(struct option *p)
17276ccec8peter{
17368cd876sam	p->next = opts;
17468cd876sam	opts = p;
17576ccec8peter}
17676ccec8peter
17768cd876samstatic void
17871bc4d4impusage(void)
179c2cd7dapeter{
18068cd876sam	char options[1024];
18168cd876sam	struct option *p;
18268cd876sam
18368cd876sam	/* XXX not right but close enough for now */
18468cd876sam	options[0] = '\0';
18568cd876sam	for (p = opts; p != NULL; p = p->next) {
18668cd876sam		strlcat(options, p->opt_usage, sizeof(options));
18768cd876sam		strlcat(options, " ", sizeof(options));
18868cd876sam	}
18968cd876sam
19068cd876sam	fprintf(stderr,
191700d268allanjude	"usage: ifconfig [-f type:format] %sinterface address_family\n"
192700d268allanjude	"                [address [dest_address]] [parameters]\n"
19368cd876sam	"       ifconfig interface create\n"
19468cd876sam	"       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
19568cd876sam	"       ifconfig -l [-d] [-u] [address_family]\n"
19668cd876sam	"       ifconfig %s[-d] [-m] [-u] [-v]\n",
19768cd876sam		options, options, options);
198c2cd7dapeter	exit(1);
199c2cd7dapeter}
20076ccec8peter
201baaa04fvsevolod#define ORDERS_SIZE(x) sizeof(x) / sizeof(x[0])
202baaa04fvsevolod
2036a39979vsevolodstatic int
2046a39979vsevolodcalcorders(struct ifaddrs *ifa, struct ifa_queue *q)
2056a39979vsevolod{
2066a39979vsevolod	struct ifaddrs *prev;
2076a39979vsevolod	struct ifa_order_elt *cur;
208baaa04fvsevolod	unsigned int ord, af, ifa_ord;
2096a39979vsevolod
2106a39979vsevolod	prev = NULL;
2116a39979vsevolod	cur = NULL;
2126a39979vsevolod	ord = 0;
2136a39979vsevolod	ifa_ord = 0;
2146a39979vsevolod
2156a39979vsevolod	while (ifa != NULL) {
216baaa04fvsevolod		if (prev == NULL ||
217baaa04fvsevolod		    strcmp(ifa->ifa_name, prev->ifa_name) != 0) {
2186a39979vsevolod			cur = calloc(1, sizeof(*cur));
2196a39979vsevolod
2206a39979vsevolod			if (cur == NULL)
2216a39979vsevolod				return (-1);
2226a39979vsevolod
2236a39979vsevolod			TAILQ_INSERT_TAIL(q, cur, link);
2246a39979vsevolod			cur->if_order = ifa_ord ++;
2256a39979vsevolod			cur->ifa = ifa;
2266a39979vsevolod			ord = 0;
2276a39979vsevolod		}
2286a39979vsevolod
2296a39979vsevolod		if (ifa->ifa_addr) {
2306a39979vsevolod			af = ifa->ifa_addr->sa_family;
2316a39979vsevolod
232baaa04fvsevolod			if (af < ORDERS_SIZE(cur->af_orders) &&
233baaa04fvsevolod			    cur->af_orders[af] == 0)
2346a39979vsevolod				cur->af_orders[af] = ++ord;
2356a39979vsevolod		}
2366a39979vsevolod		prev = ifa;
237baaa04fvsevolod		ifa = ifa->ifa_next;
2386a39979vsevolod	}
2396a39979vsevolod
2406a39979vsevolod	return (0);
2416a39979vsevolod}
2426a39979vsevolod
2436a39979vsevolodstatic int
2446a39979vsevolodcmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q)
2456a39979vsevolod{
2466a39979vsevolod	struct ifa_order_elt *cur, *e1, *e2;
247baaa04fvsevolod	unsigned int af1, af2;
248baaa04fvsevolod	int ret;
2496a39979vsevolod
2506a39979vsevolod	e1 = e2 = NULL;
2516a39979vsevolod
2526a39979vsevolod	ret = strcmp(a->ifa_name, b->ifa_name);
2536a39979vsevolod	if (ret != 0) {
2546a39979vsevolod		TAILQ_FOREACH(cur, q, link) {
2556a39979vsevolod			if (e1 && e2)
2566a39979vsevolod				break;
2576a39979vsevolod
2586a39979vsevolod			if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0)
2596a39979vsevolod				e1 = cur;
2606a39979vsevolod			else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0)
2616a39979vsevolod				e2 = cur;
2626a39979vsevolod		}
2636a39979vsevolod
2646a39979vsevolod		if (!e1 || !e2)
2656a39979vsevolod			return (0);
2666a39979vsevolod		else
2676a39979vsevolod			return (e1->if_order - e2->if_order);
2686a39979vsevolod
2696a39979vsevolod	} else if (a->ifa_addr != NULL && b->ifa_addr != NULL) {
2706a39979vsevolod		TAILQ_FOREACH(cur, q, link) {
2716a39979vsevolod			if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) {
2726a39979vsevolod				e1 = cur;
2736a39979vsevolod				break;
2746a39979vsevolod			}
2756a39979vsevolod		}
2766a39979vsevolod
2776a39979vsevolod		if (!e1)
2786a39979vsevolod			return (0);
2796a39979vsevolod
2806a39979vsevolod		af1 = a->ifa_addr->sa_family;
2816a39979vsevolod		af2 = b->ifa_addr->sa_family;
2826a39979vsevolod
283baaa04fvsevolod		if (af1 < ORDERS_SIZE(e1->af_orders) &&
284baaa04fvsevolod		    af2 < ORDERS_SIZE(e1->af_orders))
285143df1bvsevolod			return (e1->af_orders[af1] - e1->af_orders[af2]);
2866a39979vsevolod	}
2876a39979vsevolod
2886a39979vsevolod	return (0);
2896a39979vsevolod}
2906a39979vsevolod
291700d268allanjudestatic void freeformat(void)
292700d268allanjude{
293700d268allanjude
294700d268allanjude	if (f_inet != NULL)
295700d268allanjude		free(f_inet);
296700d268allanjude	if (f_inet6 != NULL)
297700d268allanjude		free(f_inet6);
298700d268allanjude	if (f_ether != NULL)
299700d268allanjude		free(f_ether);
300700d268allanjude	if (f_addr != NULL)
301700d268allanjude		free(f_addr);
302700d268allanjude}
303700d268allanjude
304700d268allanjudestatic void setformat(char *input)
305700d268allanjude{
306700d268allanjude	char	*formatstr, *category, *modifier;
307700d268allanjude
308700d268allanjude	formatstr = strdup(input);
309700d268allanjude	while ((category = strsep(&formatstr, ",")) != NULL) {
310700d268allanjude		modifier = strchr(category, ':');
311700d268allanjude		if (modifier == NULL || modifier[1] == '\0') {
312700d268allanjude			warnx("Skipping invalid format specification: %s\n",
313700d268allanjude			    category);
314700d268allanjude			continue;
315700d268allanjude		}
316700d268allanjude
317700d268allanjude		/* Split the string on the separator, then seek past it */
318700d268allanjude		modifier[0] = '\0';
319700d268allanjude		modifier++;
320700d268allanjude
321700d268allanjude		if (strcmp(category, "addr") == 0)
322700d268allanjude			f_addr = strdup(modifier);
323700d268allanjude		else if (strcmp(category, "ether") == 0)
324700d268allanjude			f_ether = strdup(modifier);
325700d268allanjude		else if (strcmp(category, "inet") == 0)
326700d268allanjude			f_inet = strdup(modifier);
327700d268allanjude		else if (strcmp(category, "inet6") == 0)
328700d268allanjude			f_inet6 = strdup(modifier);
329700d268allanjude	}
330700d268allanjude	free(formatstr);
331700d268allanjude}
332700d268allanjude
333baaa04fvsevolod#undef ORDERS_SIZE
334baaa04fvsevolod
3356a39979vsevolodstatic struct ifaddrs *
3366a39979vsevolodsortifaddrs(struct ifaddrs *list,
337baaa04fvsevolod    int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *),
338baaa04fvsevolod    struct ifa_queue *q)
3396a39979vsevolod{
3406a39979vsevolod	struct ifaddrs *right, *temp, *last, *result, *next, *tail;
3416a39979vsevolod
3426a39979vsevolod	right = list;
3436a39979vsevolod	temp = list;
3446a39979vsevolod	last = list;
3456a39979vsevolod	result = NULL;
3466a39979vsevolod	next = NULL;
3476a39979vsevolod	tail = NULL;
3486a39979vsevolod
3496a39979vsevolod	if (!list || !list->ifa_next)
3506a39979vsevolod		return (list);
3516a39979vsevolod
3526a39979vsevolod	while (temp && temp->ifa_next) {
3536a39979vsevolod		last = right;
3546a39979vsevolod		right = right->ifa_next;
3556a39979vsevolod		temp = temp->ifa_next->ifa_next;
3566a39979vsevolod	}
3576a39979vsevolod
3586a39979vsevolod	last->ifa_next = NULL;
3596a39979vsevolod
3606a39979vsevolod	list = sortifaddrs(list, compare, q);
3616a39979vsevolod	right = sortifaddrs(right, compare, q);
3626a39979vsevolod
3636a39979vsevolod	while (list || right) {
3646a39979vsevolod
3656a39979vsevolod		if (!right) {
3666a39979vsevolod			next = list;
3676a39979vsevolod			list = list->ifa_next;
3686a39979vsevolod		} else if (!list) {
3696a39979vsevolod			next = right;
3706a39979vsevolod			right = right->ifa_next;
3716a39979vsevolod		} else if (compare(list, right, q) <= 0) {
3726a39979vsevolod			next = list;
3736a39979vsevolod			list = list->ifa_next;
3746a39979vsevolod		} else {
3756a39979vsevolod			next = right;
3766a39979vsevolod			right = right->ifa_next;
3776a39979vsevolod		}
3786a39979vsevolod
3796a39979vsevolod		if (!result)
3806a39979vsevolod			result = next;
3816a39979vsevolod		else
3826a39979vsevolod			tail->ifa_next = next;
3836a39979vsevolod
3846a39979vsevolod		tail = next;
3856a39979vsevolod	}
3866a39979vsevolod
3876a39979vsevolod	return (result);
3886a39979vsevolod}
3896a39979vsevolod
39033ef68fkpvoid printifnamemaybe()
39133ef68fkp{
39233ef68fkp	if (printifname)
39333ef68fkp		printf("%s\n", name);
39433ef68fkp}
39533ef68fkp
3961ee570ewollmanint
39771bc4d4impmain(int argc, char *argv[])
398d038e02rgrimes{
39968cd876sam	int c, all, namesonly, downonly, uponly;
40068cd876sam	const struct afswtch *afp = NULL;
401cd822ecsam	int ifindex;
4026a39979vsevolod	struct ifaddrs *ifap, *sifap, *ifa;
403cd822ecsam	struct ifreq paifr;
404cd822ecsam	const struct sockaddr_dl *sdl;
405700d268allanjude	char options[1024], *cp, *envformat, *namecp = NULL;
4066a39979vsevolod	struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q);
4076a39979vsevolod	struct ifa_order_elt *cur, *tmp;
408dd5a75deugen	const char *ifname, *matchgroup, *nogroup;
40968cd876sam	struct option *p;
410a032478sam	size_t iflen;
411247f8f7pkelsey	int flags;
41268cd876sam
413fca2195thompsa	all = downonly = uponly = namesonly = noload = verbose = 0;
4148e48e06allanjude	f_inet = f_inet6 = f_ether = f_addr = NULL;
415dd5a75deugen	matchgroup = nogroup = NULL;
416700d268allanjude
417700d268allanjude	envformat = getenv("IFCONFIG_FORMAT");
418700d268allanjude	if (envformat != NULL)
419700d268allanjude		setformat(envformat);
420700d268allanjude
42133ef68fkp	/*
42233ef68fkp	 * Ensure we print interface name when expected to,
42333ef68fkp	 * even if we terminate early due to error.
42433ef68fkp	 */
42533ef68fkp	atexit(printifnamemaybe);
426c2cd7dapeter
427c2cd7dapeter	/* Parse leading line options */
428dd5a75deugen	strlcpy(options, "G:adf:klmnuv", sizeof(options));
42968cd876sam	for (p = opts; p != NULL; p = p->next)
43068cd876sam		strlcat(options, p->opt, sizeof(options));
43168cd876sam	while ((c = getopt(argc, argv, options)) != -1) {
432c2cd7dapeter		switch (c) {
433c2cd7dapeter		case 'a':	/* scan all interfaces */
434c2cd7dapeter			all++;
435c2cd7dapeter			break;
4361e69f4ebrooks		case 'd':	/* restrict scan to "down" interfaces */
4371e69f4ebrooks			downonly++;
43870f0bdfshin			break;
439700d268allanjude		case 'f':
440700d268allanjude			if (optarg == NULL)
441700d268allanjude				usage();
442700d268allanjude			setformat(optarg);
443700d268allanjude			break;
444dd5a75deugen		case 'G':
445dd5a75deugen			if (optarg == NULL || all == 0)
446dd5a75deugen				usage();
447dd5a75deugen			nogroup = optarg;
448dd5a75deugen			break;
4492df666arwatson		case 'k':
4502df666arwatson			printkeys++;
4512df666arwatson			break;
452c2cd7dapeter		case 'l':	/* scan interface names only */
453c2cd7dapeter			namesonly++;
454c2cd7dapeter			break;
4551e69f4ebrooks		case 'm':	/* show media choices in status */
4561e69f4ebrooks			supmedia = 1;
457c2cd7dapeter			break;
458fca2195thompsa		case 'n':	/* suppress module loading */
459fca2195thompsa			noload++;
460fca2195thompsa			break;
461668d29bsteve		case 'u':	/* restrict scan to "up" interfaces */
462c2cd7dapeter			uponly++;
463c2cd7dapeter			break;
46468cd876sam		case 'v':
46568cd876sam			verbose++;
46654b5e92peter			break;
467dd5a75deugen		case 'g':
468dd5a75deugen			if (all) {
469dd5a75deugen				if (optarg == NULL)
470dd5a75deugen					usage();
471dd5a75deugen				matchgroup = optarg;
472dd5a75deugen				break;
473dd5a75deugen			}
474dd5a75deugen			/* FALLTHROUGH */
475c2cd7dapeter		default:
47668cd876sam			for (p = opts; p != NULL; p = p->next)
47768cd876sam				if (p->opt[0] == c) {
47868cd876sam					p->cb(optarg);
47968cd876sam					break;
48068cd876sam				}
48168cd876sam			if (p == NULL)
48268cd876sam				usage();
483c2cd7dapeter			break;
484c2cd7dapeter		}
485c2cd7dapeter	}
486c2cd7dapeter	argc -= optind;
487c2cd7dapeter	argv += optind;
488c2cd7dapeter
489c2cd7dapeter	/* -l cannot be used with -a or -m */
490de9bff5phk	if (namesonly && (all || supmedia))
491c2cd7dapeter		usage();
492c2cd7dapeter
493c2cd7dapeter	/* nonsense.. */
494c2cd7dapeter	if (uponly && downonly)
495c2cd7dapeter		usage();
496c2cd7dapeter
497e58c321archie	/* no arguments is equivalent to '-a' */
498e58c321archie	if (!namesonly && argc < 1)
499e58c321archie		all = 1;
500e58c321archie
501c2cd7dapeter	/* -a and -l allow an address family arg to limit the output */
502c2cd7dapeter	if (all || namesonly) {
503c2cd7dapeter		if (argc > 1)
504c2cd7dapeter			usage();
505c2cd7dapeter
506cd822ecsam		ifname = NULL;
5072436924jlemon		ifindex = 0;
508c2cd7dapeter		if (argc == 1) {
50968cd876sam			afp = af_getbyname(*argv);
510b41f984bz			if (afp == NULL) {
511b41f984bz				warnx("Address family '%s' unknown.", *argv);
512c2cd7dapeter				usage();
513b41f984bz			}
51468cd876sam			if (afp->af_name != NULL)
51568cd876sam				argc--, argv++;
516c2cd7dapeter			/* leave with afp non-zero */
517c2cd7dapeter		}
518c2cd7dapeter	} else {
519dde477fcharnier		/* not listing, need an argument */
520c2cd7dapeter		if (argc < 1)
521