ifconfig.c revision 191252
1133819Stjr/*
2133819Stjr * Copyright (c) 1983, 1993
3133819Stjr *	The Regents of the University of California.  All rights reserved.
4133819Stjr *
5133819Stjr * Redistribution and use in source and binary forms, with or without
6177258Srdivacky * modification, are permitted provided that the following conditions
7133819Stjr * are met:
8133819Stjr * 1. Redistributions of source code must retain the above copyright
9133819Stjr *    notice, this list of conditions and the following disclaimer.
10133819Stjr * 2. Redistributions in binary form must reproduce the above copyright
11133819Stjr *    notice, this list of conditions and the following disclaimer in the
12133819Stjr *    documentation and/or other materials provided with the distribution.
13133819Stjr * 4. Neither the name of the University nor the names of its contributors
14164199Sru *    may be used to endorse or promote products derived from this software
15133819Stjr *    without specific prior written permission.
16133819Stjr *
17161330Sjhb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18161330Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133819Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133819Stjr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21133819Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133819Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133819Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133819Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133819Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133819Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133819Stjr * SUCH DAMAGE.
28133819Stjr */
29133819Stjr
30133819Stjr#ifndef lint
31133819Stjrstatic const char copyright[] =
32133819Stjr"@(#) Copyright (c) 1983, 1993\n\
33133819Stjr	The Regents of the University of California.  All rights reserved.\n";
34143198Ssobomax#endif /* not lint */
35133819Stjr
36133819Stjr#ifndef lint
37133819Stjr#if 0
38133819Stjrstatic char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
39133819Stjr#endif
40133819Stjrstatic const char rcsid[] =
41133819Stjr  "$FreeBSD: head/sbin/ifconfig/ifconfig.c 191252 2009-04-18 20:10:39Z rwatson $";
42133819Stjr#endif /* not lint */
43133819Stjr
44133819Stjr#include <sys/param.h>
45133819Stjr#include <sys/ioctl.h>
46133819Stjr#include <sys/socket.h>
47133819Stjr#include <sys/sysctl.h>
48133819Stjr#include <sys/time.h>
49133819Stjr#include <sys/module.h>
50133819Stjr#include <sys/linker.h>
51133819Stjr
52133819Stjr#include <net/ethernet.h>
53133819Stjr#include <net/if.h>
54133819Stjr#include <net/if_var.h>
55133819Stjr#include <net/if_dl.h>
56133819Stjr#include <net/if_types.h>
57133819Stjr#include <net/route.h>
58133819Stjr
59133819Stjr/* IP */
60133819Stjr#include <netinet/in.h>
61133819Stjr#include <netinet/in_var.h>
62133819Stjr#include <arpa/inet.h>
63133819Stjr#include <netdb.h>
64133819Stjr
65133819Stjr#include <ifaddrs.h>
66133819Stjr#include <ctype.h>
67133819Stjr#include <err.h>
68133819Stjr#include <errno.h>
69133819Stjr#include <fcntl.h>
70133819Stjr#include <stdio.h>
71133819Stjr#include <stdlib.h>
72133819Stjr#include <string.h>
73133819Stjr#include <unistd.h>
74133819Stjr
75133819Stjr#include "ifconfig.h"
76133819Stjr
77133819Stjr/*
78133819Stjr * Since "struct ifreq" is composed of various union members, callers
79133819Stjr * should pay special attention to interprete the value.
80133819Stjr * (.e.g. little/big endian difference in the structure.)
81133819Stjr */
82133819Stjrstruct	ifreq ifr;
83133819Stjr
84156919Snetchildchar	name[IFNAMSIZ];
85156919Snetchildint	setaddr;
86156919Snetchildint	setmask;
87156919Snetchildint	doalias;
88133819Stjrint	clearaddr;
89133819Stjrint	newaddr = 1;
90133819Stjrint	verbose;
91133819Stjrint	noload;
92133819Stjr
93133819Stjrint	supmedia = 0;
94133819Stjrint	printkeys = 0;		/* Print keying material for interfaces. */
95133819Stjr
96133819Stjrstatic	int ifconfig(int argc, char *const *argv, int iscreate,
97133819Stjr		const struct afswtch *afp);
98133819Stjrstatic	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
99133819Stjr		struct ifaddrs *ifa);
100133819Stjrstatic	void tunnel_status(int s);
101133819Stjrstatic	void usage(void);
102133819Stjr
103133819Stjrstatic struct afswtch *af_getbyname(const char *name);
104133819Stjrstatic struct afswtch *af_getbyfamily(int af);
105133819Stjrstatic void af_other_status(int);
106133819Stjr
107133819Stjrstatic struct option *opts = NULL;
108133819Stjr
109133819Stjrvoid
110133819Stjropt_register(struct option *p)
111133819Stjr{
112133819Stjr	p->next = opts;
113133819Stjr	opts = p;
114133819Stjr}
115133819Stjr
116133819Stjrstatic void
117133819Stjrusage(void)
118133819Stjr{
119133819Stjr	char options[1024];
120133819Stjr	struct option *p;
121133819Stjr
122133819Stjr	/* XXX not right but close enough for now */
123133819Stjr	options[0] = '\0';
124133819Stjr	for (p = opts; p != NULL; p = p->next) {
125133819Stjr		strlcat(options, p->opt_usage, sizeof(options));
126133819Stjr		strlcat(options, " ", sizeof(options));
127133819Stjr	}
128133819Stjr
129133819Stjr	fprintf(stderr,
130133819Stjr	"usage: ifconfig %sinterface address_family [address [dest_address]]\n"
131133819Stjr	"                [parameters]\n"
132133819Stjr	"       ifconfig interface create\n"
133133819Stjr	"       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
134133819Stjr	"       ifconfig -l [-d] [-u] [address_family]\n"
135133819Stjr	"       ifconfig %s[-d] [-m] [-u] [-v]\n",
136133819Stjr		options, options, options);
137133819Stjr	exit(1);
138133819Stjr}
139133819Stjr
140133819Stjrint
141133819Stjrmain(int argc, char *argv[])
142133819Stjr{
143133819Stjr	int c, all, namesonly, downonly, uponly;
144133819Stjr	const struct afswtch *afp = NULL;
145133819Stjr	int ifindex;
146133819Stjr	struct ifaddrs *ifap, *ifa;
147133819Stjr	struct ifreq paifr;
148133819Stjr	const struct sockaddr_dl *sdl;
149133819Stjr	char options[1024], *cp;
150133819Stjr	const char *ifname;
151133819Stjr	struct option *p;
152133819Stjr	size_t iflen;
153133819Stjr
154133819Stjr	all = downonly = uponly = namesonly = noload = verbose = 0;
155133819Stjr
156133819Stjr	/* Parse leading line options */
157133819Stjr	strlcpy(options, "adklmnuv", sizeof(options));
158133819Stjr	for (p = opts; p != NULL; p = p->next)
159133819Stjr		strlcat(options, p->opt, sizeof(options));
160133819Stjr	while ((c = getopt(argc, argv, options)) != -1) {
161133819Stjr		switch (c) {
162133819Stjr		case 'a':	/* scan all interfaces */
163133819Stjr			all++;
164133819Stjr			break;
165133819Stjr		case 'd':	/* restrict scan to "down" interfaces */
166133819Stjr			downonly++;
167133819Stjr			break;
168133819Stjr		case 'k':
169133819Stjr			printkeys++;
170133819Stjr			break;
171133819Stjr		case 'l':	/* scan interface names only */
172133819Stjr			namesonly++;
173133819Stjr			break;
174133819Stjr		case 'm':	/* show media choices in status */
175133819Stjr			supmedia = 1;
176133819Stjr			break;
177133819Stjr		case 'n':	/* suppress module loading */
178133819Stjr			noload++;
179133819Stjr			break;
180133819Stjr		case 'u':	/* restrict scan to "up" interfaces */
181133819Stjr			uponly++;
182133819Stjr			break;
183133819Stjr		case 'v':
184133819Stjr			verbose++;
185133819Stjr			break;
186133819Stjr		default:
187133819Stjr			for (p = opts; p != NULL; p = p->next)
188133819Stjr				if (p->opt[0] == c) {
189133819Stjr					p->cb(optarg);
190133819Stjr					break;
191133819Stjr				}
192133819Stjr			if (p == NULL)
193133819Stjr				usage();
194133819Stjr			break;
195133819Stjr		}
196133819Stjr	}
197133819Stjr	argc -= optind;
198133819Stjr	argv += optind;
199161309Snetchild
200161309Snetchild	/* -l cannot be used with -a or -m */
201161309Snetchild	if (namesonly && (all || supmedia))
202133819Stjr		usage();
203133819Stjr
204133819Stjr	/* nonsense.. */
205133819Stjr	if (uponly && downonly)
206133819Stjr		usage();
207133819Stjr
208133819Stjr	/* no arguments is equivalent to '-a' */
209133819Stjr	if (!namesonly && argc < 1)
210133819Stjr		all = 1;
211133819Stjr
212133819Stjr	/* -a and -l allow an address family arg to limit the output */
213133819Stjr	if (all || namesonly) {
214133819Stjr		if (argc > 1)
215133819Stjr			usage();
216133819Stjr
217133819Stjr		ifname = NULL;
218133819Stjr		ifindex = 0;
219133819Stjr		if (argc == 1) {
220133819Stjr			afp = af_getbyname(*argv);
221133819Stjr			if (afp == NULL)
222133819Stjr				usage();
223133819Stjr			if (afp->af_name != NULL)
224133819Stjr				argc--, argv++;
225133819Stjr			/* leave with afp non-zero */
226133819Stjr		}
227133819Stjr	} else {
228133819Stjr		/* not listing, need an argument */
229156843Snetchild		if (argc < 1)
230156843Snetchild			usage();
231156843Snetchild
232156843Snetchild		ifname = *argv;
233133819Stjr		argc--, argv++;
234133819Stjr
235133819Stjr		/* check and maybe load support for this interface */
236133819Stjr		ifmaybeload(ifname);
237133819Stjr
238133819Stjr		ifindex = if_nametoindex(ifname);
239133819Stjr		if (ifindex == 0) {
240133819Stjr			/*
241133819Stjr			 * NOTE:  We must special-case the `create' command
242133819Stjr			 * right here as we would otherwise fail when trying
243133819Stjr			 * to find the interface.
244133819Stjr			 */
245133819Stjr			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
246133819Stjr			    strcmp(argv[0], "plumb") == 0)) {
247133819Stjr				iflen = strlcpy(name, ifname, sizeof(name));
248133819Stjr				if (iflen >= sizeof(name))
249133819Stjr					errx(1, "%s: cloning name too long",
250133819Stjr					    ifname);
251133819Stjr				ifconfig(argc, argv, 1, NULL);
252133819Stjr				exit(0);
253133819Stjr			}
254133819Stjr			errx(1, "interface %s does not exist", ifname);
255133819Stjr		}
256133819Stjr	}
257133819Stjr
258133819Stjr	/* Check for address family */
259133819Stjr	if (argc > 0) {
260133819Stjr		afp = af_getbyname(*argv);
261133819Stjr		if (afp != NULL)
262133819Stjr			argc--, argv++;
263133819Stjr	}
264133819Stjr
265133819Stjr	if (getifaddrs(&ifap) != 0)
266133819Stjr		err(EXIT_FAILURE, "getifaddrs");
267133819Stjr	cp = NULL;
268156919Snetchild	ifindex = 0;
269156843Snetchild	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
270156919Snetchild		memset(&paifr, 0, sizeof(paifr));
271156843Snetchild		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
272133819Stjr		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
273133819Stjr			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
274133819Stjr			    ifa->ifa_addr->sa_len);
275133819Stjr		}
276133819Stjr
277133819Stjr		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
278133819Stjr			continue;
279133819Stjr		if (ifa->ifa_addr->sa_family == AF_LINK)
280133819Stjr			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
281133819Stjr		else
282133819Stjr			sdl = NULL;
283133819Stjr		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
284133819Stjr			continue;
285133819Stjr		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
286133819Stjr		if (iflen >= sizeof(name)) {
287133819Stjr			warnx("%s: interface name too long, skipping",
288133819Stjr			    ifa->ifa_name);
289133819Stjr			continue;
290133819Stjr		}
291133819Stjr		cp = ifa->ifa_name;
292133819Stjr
293133819Stjr		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
294133819Stjr			continue;
295156843Snetchild		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
296156843Snetchild			continue;
297156843Snetchild		ifindex++;
298156843Snetchild		/*
299147142Ssobomax		 * Are we just listing the interfaces?
300147142Ssobomax		 */
301147142Ssobomax		if (namesonly) {
302147142Ssobomax			if (ifindex > 1)
303133819Stjr				printf(" ");
304133819Stjr			fputs(name, stdout);
305133819Stjr			continue;
306133819Stjr		}
307133819Stjr
308133819Stjr		if (argc > 0)
309133819Stjr			ifconfig(argc, argv, 0, afp);
310133819Stjr		else
311133819Stjr			status(afp, sdl, ifa);
312133819Stjr	}
313133819Stjr	if (namesonly)
314133819Stjr		printf("\n");
315133819Stjr	freeifaddrs(ifap);
316133819Stjr
317133819Stjr	exit(0);
318133819Stjr}
319133819Stjr
320133819Stjrstatic struct afswtch *afs = NULL;
321133819Stjr
322133819Stjrvoid
323133819Stjraf_register(struct afswtch *p)
324133819Stjr{
325133819Stjr	p->af_next = afs;
326133819Stjr	afs = p;
327133819Stjr}
328133819Stjr
329133819Stjrstatic struct afswtch *
330133819Stjraf_getbyname(const char *name)
331133819Stjr{
332133819Stjr	struct afswtch *afp;
333133819Stjr
334133819Stjr	for (afp = afs; afp !=  NULL; afp = afp->af_next)
335133819Stjr		if (strcmp(afp->af_name, name) == 0)
336133819Stjr			return afp;
337133819Stjr	return NULL;
338133819Stjr}
339133819Stjr
340133819Stjrstatic struct afswtch *
341133819Stjraf_getbyfamily(int af)
342133819Stjr{
343133819Stjr	struct afswtch *afp;
344166730Sjkim
345166730Sjkim	for (afp = afs; afp != NULL; afp = afp->af_next)
346166730Sjkim		if (afp->af_af == af)
347133819Stjr			return afp;
348133819Stjr	return NULL;
349133819Stjr}
350133819Stjr
351133819Stjrstatic void
352133819Stjraf_other_status(int s)
353133819Stjr{
354133819Stjr	struct afswtch *afp;
355133819Stjr	uint8_t afmask[howmany(AF_MAX, NBBY)];
356133819Stjr
357133819Stjr	memset(afmask, 0, sizeof(afmask));
358133819Stjr	for (afp = afs; afp != NULL; afp = afp->af_next) {
359133819Stjr		if (afp->af_other_status == NULL)
360133819Stjr			continue;
361133819Stjr		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
362133819Stjr			continue;
363133819Stjr		afp->af_other_status(s);
364133819Stjr		setbit(afmask, afp->af_af);
365133819Stjr	}
366133819Stjr}
367133819Stjr
368133819Stjrstatic void
369133819Stjraf_all_tunnel_status(int s)
370133819Stjr{
371133819Stjr	struct afswtch *afp;
372133819Stjr	uint8_t afmask[howmany(AF_MAX, NBBY)];
373133819Stjr
374133819Stjr	memset(afmask, 0, sizeof(afmask));
375133819Stjr	for (afp = afs; afp != NULL; afp = afp->af_next) {
376161309Snetchild		if (afp->af_status_tunnel == NULL)
377161309Snetchild			continue;
378161309Snetchild		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
379133819Stjr			continue;
380133819Stjr		afp->af_status_tunnel(s);
381133819Stjr		setbit(afmask, afp->af_af);
382133819Stjr	}
383133819Stjr}
384133819Stjr
385133819Stjrstatic struct cmd *cmds = NULL;
386133819Stjr
387133819Stjrvoid
388133819Stjrcmd_register(struct cmd *p)
389133819Stjr{
390133819Stjr	p->c_next = cmds;
391133819Stjr	cmds = p;
392133819Stjr}
393133819Stjr
394133819Stjrstatic const struct cmd *
395133819Stjrcmd_lookup(const char *name, int iscreate)
396133819Stjr{
397133819Stjr#define	N(a)	(sizeof(a)/sizeof(a[0]))
398133819Stjr	const struct cmd *p;
399133819Stjr
400133819Stjr	for (p = cmds; p != NULL; p = p->c_next)
401133819Stjr		if (strcmp(name, p->c_name) == 0) {
402133819Stjr			if (iscreate) {
403133819Stjr				if (p->c_iscloneop)
404133819Stjr					return p;
405133819Stjr			} else {
406133819Stjr				if (!p->c_iscloneop)
407133819Stjr					return p;
408133819Stjr			}
409133819Stjr		}
410133819Stjr	return NULL;
411133819Stjr#undef N
412133819Stjr}
413133819Stjr
414133819Stjrstruct callback {
415133819Stjr	callback_func *cb_func;
416133819Stjr	void	*cb_arg;
417133819Stjr	struct callback *cb_next;
418133819Stjr};
419133819Stjrstatic struct callback *callbacks = NULL;
420133819Stjr
421133819Stjrvoid
422133819Stjrcallback_register(callback_func *func, void *arg)
423133819Stjr{
424133819Stjr	struct callback *cb;
425133819Stjr
426133819Stjr	cb = malloc(sizeof(struct callback));
427133819Stjr	if (cb == NULL)
428133819Stjr		errx(1, "unable to allocate memory for callback");
429133819Stjr	cb->cb_func = func;
430133819Stjr	cb->cb_arg = arg;
431133819Stjr	cb->cb_next = callbacks;
432133819Stjr	callbacks = cb;
433133819Stjr}
434133819Stjr
435133819Stjr/* specially-handled commands */
436133819Stjrstatic void setifaddr(const char *, int, int, const struct afswtch *);
437133819Stjrstatic const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
438133819Stjr
439133819Stjrstatic void setifdstaddr(const char *, int, int, const struct afswtch *);
440133819Stjrstatic const struct cmd setifdstaddr_cmd =
441133819Stjr	DEF_CMD("ifdstaddr", 0, setifdstaddr);
442133819Stjr
443133819Stjrstatic int
444133819Stjrifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
445133819Stjr{
446133819Stjr	const struct afswtch *afp, *nafp;
447133819Stjr	const struct cmd *p;
448133819Stjr	struct callback *cb;
449133819Stjr	int s;
450133819Stjr
451133819Stjr	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
452133819Stjr	afp = uafp != NULL ? uafp : af_getbyname("inet");
453133819Stjrtop:
454133819Stjr	ifr.ifr_addr.sa_family =
455133819Stjr		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
456133819Stjr		AF_LOCAL : afp->af_af;
457133819Stjr
458133819Stjr	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
459133819Stjr	    (uafp != NULL || errno != EPROTONOSUPPORT ||
460133819Stjr	     (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
461133819Stjr		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
462133819Stjr
463133819Stjr	while (argc > 0) {
464133819Stjr		p = cmd_lookup(*argv, iscreate);
465133819Stjr		if (iscreate && p == NULL) {
466133819Stjr			/*
467133819Stjr			 * Push the clone create callback so the new
468133819Stjr			 * device is created and can be used for any
469133819Stjr			 * remaining arguments.
470133819Stjr			 */
471133819Stjr			cb = callbacks;
472133819Stjr			if (cb == NULL)
473133819Stjr				errx(1, "internal error, no callback");
474133819Stjr			callbacks = cb->cb_next;
475133819Stjr			cb->cb_func(s, cb->cb_arg);
476133819Stjr			iscreate = 0;
477133819Stjr			/*
478133819Stjr			 * Handle any address family spec that
479133819Stjr			 * immediately follows and potentially
480133819Stjr			 * recreate the socket.
481133819Stjr			 */
482133819Stjr			nafp = af_getbyname(*argv);
483133819Stjr			if (nafp != NULL) {
484133819Stjr				argc--, argv++;
485133819Stjr				if (nafp != afp) {
486133819Stjr					close(s);
487133819Stjr					afp = nafp;
488133819Stjr					goto top;
489133819Stjr				}
490133819Stjr			}
491133819Stjr			/*
492133819Stjr			 * Look for a normal parameter.
493133819Stjr			 */
494133819Stjr			continue;
495133819Stjr		}
496133819Stjr		if (p == NULL) {
497133819Stjr			/*
498133819Stjr			 * Not a recognized command, choose between setting
499133819Stjr			 * the interface address and the dst address.
500133819Stjr			 */
501133819Stjr			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
502133819Stjr		}
503133819Stjr		if (p->c_u.c_func || p->c_u.c_func2) {
504133819Stjr			if (p->c_parameter == NEXTARG) {
505133819Stjr				if (argv[1] == NULL)
506133819Stjr					errx(1, "'%s' requires argument",
507133819Stjr					    p->c_name);
508133819Stjr				p->c_u.c_func(argv[1], 0, s, afp);
509133819Stjr				argc--, argv++;
510133819Stjr			} else if (p->c_parameter == OPTARG) {
511133819Stjr				p->c_u.c_func(argv[1], 0, s, afp);
512133819Stjr				if (argv[1] != NULL)
513133819Stjr					argc--, argv++;
514133819Stjr			} else if (p->c_parameter == NEXTARG2) {
515133819Stjr				if (argc < 3)
516133819Stjr					errx(1, "'%s' requires 2 arguments",
517133819Stjr					    p->c_name);
518133819Stjr				p->c_u.c_func2(argv[1], argv[2], s, afp);
519133819Stjr				argc -= 2, argv += 2;
520133819Stjr			} else
521133819Stjr				p->c_u.c_func(*argv, p->c_parameter, s, afp);
522133819Stjr		}
523133819Stjr		argc--, argv++;
524133819Stjr	}
525133819Stjr
526133819Stjr	/*
527163736Snetchild	 * Do any post argument processing required by the address family.
528163736Snetchild	 */
529163736Snetchild	if (afp->af_postproc != NULL)
530163736Snetchild		afp->af_postproc(s, afp);
531163736Snetchild	/*
532133819Stjr	 * Do deferred callbacks registered while processing
533133819Stjr	 * command-line arguments.
534133819Stjr	 */
535133819Stjr	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
536133819Stjr		cb->cb_func(s, cb->cb_arg);
537133819Stjr	/*
538133819Stjr	 * Do deferred operations.
539133819Stjr	 */
540133819Stjr	if (clearaddr) {
541133819Stjr		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
542133819Stjr			warnx("interface %s cannot change %s addresses!",
543133819Stjr			      name, afp->af_name);
544133819Stjr			clearaddr = 0;
545133819Stjr		}
546133819Stjr	}
547133819Stjr	if (clearaddr) {
548133819Stjr		int ret;
549158407Snetchild		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
550158407Snetchild		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
551133819Stjr		if (ret < 0) {
552133819Stjr			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
553165690Snetchild				/* means no previous address for interface */
554165690Snetchild			} else
555165690Snetchild				Perror("ioctl (SIOCDIFADDR)");
556165690Snetchild		}
557133819Stjr	}
558133819Stjr	if (newaddr) {
559133819Stjr		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
560133819Stjr			warnx("interface %s cannot change %s addresses!",
561133819Stjr			      name, afp->af_name);
562133819Stjr			newaddr = 0;
563133819Stjr		}
564133819Stjr	}
565133819Stjr	if (newaddr && (setaddr || setmask)) {
566133819Stjr		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
567133819Stjr		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
568133819Stjr			Perror("ioctl (SIOCAIFADDR)");
569133819Stjr	}
570133819Stjr
571133819Stjr	close(s);
572133819Stjr	return(0);
573133819Stjr}
574133819Stjr
575133819Stjr/*ARGSUSED*/
576133819Stjrstatic void
577133819Stjrsetifaddr(const char *addr, int param, int s, const struct afswtch *afp)
578133819Stjr{
579133819Stjr	if (afp->af_getaddr == NULL)
580133819Stjr		return;
581133819Stjr	/*
582133819Stjr	 * Delay the ioctl to set the interface addr until flags are all set.
583133819Stjr	 * The address interpretation may depend on the flags,
584133819Stjr	 * and the flags may change when the address is set.
585133819Stjr	 */
586133819Stjr	setaddr++;
587133819Stjr	if (doalias == 0 && afp->af_af != AF_LINK)
588133819Stjr		clearaddr = 1;
589133819Stjr	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
590133819Stjr}
591133819Stjr
592133819Stjrstatic void
593133819Stjrsettunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
594133819Stjr{
595133819Stjr	struct addrinfo *srcres, *dstres;
596133819Stjr	int ecode;
597133819Stjr
598133819Stjr	if (afp->af_settunnel == NULL) {
599133819Stjr		warn("address family %s does not support tunnel setup",
600133819Stjr			afp->af_name);
601133819Stjr		return;
602133819Stjr	}
603133819Stjr
604133819Stjr	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
605133819Stjr		errx(1, "error in parsing address string: %s",
606133819Stjr		    gai_strerror(ecode));
607133819Stjr
608133819Stjr	if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
609133819Stjr		errx(1, "error in parsing address string: %s",
610133819Stjr		    gai_strerror(ecode));
611133819Stjr
612133819Stjr	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
613133819Stjr		errx(1,
614133819Stjr		    "source and destination address families do not match");
615133819Stjr
616133819Stjr	afp->af_settunnel(s, srcres, dstres);
617133819Stjr
618133819Stjr	freeaddrinfo(srcres);
619133819Stjr	freeaddrinfo(dstres);
620133819Stjr}
621133819Stjr
622133819Stjr/* ARGSUSED */
623133819Stjrstatic void
624133819Stjrdeletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
625133819Stjr{
626133819Stjr
627133819Stjr	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
628133819Stjr		err(1, "SIOCDIFPHYADDR");
629133819Stjr}
630133819Stjr
631133819Stjrstatic void
632133819Stjrsetifnetmask(const char *addr, int dummy __unused, int s,
633133819Stjr    const struct afswtch *afp)
634133819Stjr{
635133819Stjr	if (afp->af_getaddr != NULL) {
636133819Stjr		setmask++;
637133819Stjr		afp->af_getaddr(addr, MASK);
638133819Stjr	}
639133819Stjr}
640133819Stjr
641133819Stjrstatic void
642133819Stjrsetifbroadaddr(const char *addr, int dummy __unused, int s,
643133819Stjr    const struct afswtch *afp)
644133819Stjr{
645133819Stjr	if (afp->af_getaddr != NULL)
646133819Stjr		afp->af_getaddr(addr, DSTADDR);
647133819Stjr}
648133819Stjr
649133819Stjrstatic void
650133819Stjrsetifipdst(const char *addr, int dummy __unused, int s,
651133819Stjr    const struct afswtch *afp)
652133819Stjr{
653133819Stjr	const struct afswtch *inet;
654133819Stjr
655133819Stjr	inet = af_getbyname("inet");
656133819Stjr	if (inet == NULL)
657133819Stjr		return;
658133819Stjr	inet->af_getaddr(addr, DSTADDR);
659133819Stjr	clearaddr = 0;
660133819Stjr	newaddr = 0;
661133819Stjr}
662133819Stjr
663133819Stjrstatic void
664133819Stjrnotealias(const char *addr, int param, int s, const struct afswtch *afp)
665133819Stjr{
666133819Stjr#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
667133819Stjr	if (setaddr && doalias == 0 && param < 0)
668133819Stjr		if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
669133819Stjr			bcopy((caddr_t)rqtosa(af_addreq),
670133819Stjr			      (caddr_t)rqtosa(af_ridreq),
671133819Stjr			      rqtosa(af_addreq)->sa_len);
672133819Stjr	doalias = param;
673133819Stjr	if (param < 0) {
674133819Stjr		clearaddr = 1;
675133819Stjr		newaddr = 0;
676133819Stjr	} else
677133819Stjr		clearaddr = 0;
678133819Stjr#undef rqtosa
679133819Stjr}
680133819Stjr
681133819Stjr/*ARGSUSED*/
682133819Stjrstatic void
683133819Stjrsetifdstaddr(const char *addr, int param __unused, int s,
684133819Stjr    const struct afswtch *afp)
685133819Stjr{
686161309Snetchild	if (afp->af_getaddr != NULL)
687161309Snetchild		afp->af_getaddr(addr, DSTADDR);
688161309Snetchild}
689133819Stjr
690133819Stjr/*
691133819Stjr * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
692133819Stjr * of the ifreq structure, which may confuse other parts of ifconfig.
693133819Stjr * Make a private copy so we can avoid that.
694133819Stjr */
695133819Stjrstatic void
696133819Stjrsetifflags(const char *vname, int value, int s, const struct afswtch *afp)
697133819Stjr{
698133819Stjr	struct ifreq		my_ifr;
699133819Stjr	int flags;
700133819Stjr
701133819Stjr	memset(&my_ifr, 0, sizeof(my_ifr));
702133819Stjr	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
703133819Stjr
704133819Stjr 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
705133819Stjr 		Perror("ioctl (SIOCGIFFLAGS)");
706133819Stjr 		exit(1);
707133819Stjr 	}
708133819Stjr	flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16);
709133819Stjr
710133819Stjr	if (value < 0) {
711133819Stjr		value = -value;
712133819Stjr		flags &= ~value;
713133819Stjr	} else
714133819Stjr		flags |= value;
715133819Stjr	my_ifr.ifr_flags = flags & 0xffff;
716133819Stjr	my_ifr.ifr_flagshigh = flags >> 16;
717133819Stjr	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
718133819Stjr		Perror(vname);
719133819Stjr}
720133819Stjr
721133819Stjrvoid
722133819Stjrsetifcap(const char *vname, int value, int s, const struct afswtch *afp)
723133819Stjr{
724133819Stjr	int flags;
725161309Snetchild
726161309Snetchild 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
727161309Snetchild 		Perror("ioctl (SIOCGIFCAP)");
728161309Snetchild 		exit(1);
729161309Snetchild 	}
730161309Snetchild	flags = ifr.ifr_curcap;
731161309Snetchild	if (value < 0) {
732161309Snetchild		value = -value;
733161309Snetchild		flags &= ~value;
734161309Snetchild	} else
735161309Snetchild		flags |= value;
736161309Snetchild	flags &= ifr.ifr_reqcap;
737177258Srdivacky	ifr.ifr_reqcap = flags;
738177258Srdivacky	if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
739177258Srdivacky		Perror(vname);
740177258Srdivacky}
741177258Srdivacky
742171999Skibstatic void
743171999Skibsetifmetric(const char *val, int dummy __unused, int s,
744171999Skib    const struct afswtch *afp)
745171999Skib{
746171999Skib	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
747168036Sjkim	ifr.ifr_metric = atoi(val);
748168036Sjkim	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
749168036Sjkim		warn("ioctl (set metric)");
750133819Stjr}
751133819Stjr
752133819Stjrstatic void
753161309Snetchildsetifmtu(const char *val, int dummy __unused, int s,
754161309Snetchild    const struct afswtch *afp)
755161309Snetchild{
756159801Snetchild	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
757159801Snetchild	ifr.ifr_mtu = atoi(val);
758159801Snetchild	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
759159801Snetchild		warn("ioctl (set mtu)");
760159801Snetchild}
761159801Snetchild
762159801Snetchildstatic void
763159801Snetchildsetifname(const char *val, int dummy __unused, int s,
764159801Snetchild    const struct afswtch *afp)
765159801Snetchild{
766159801Snetchild	char *newname;
767159801Snetchild
768159801Snetchild	newname = strdup(val);
769159801Snetchild	if (newname == NULL) {
770159801Snetchild		warn("no memory to set ifname");
771159801Snetchild		return;
772161309Snetchild	}
773159801Snetchild	ifr.ifr_data = newname;
774159801Snetchild	if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
775159801Snetchild		warn("ioctl (set name)");
776159801Snetchild		free(newname);
777159801Snetchild		return;
778159801Snetchild	}
779159801Snetchild	strlcpy(name, newname, sizeof(name));
780159801Snetchild	free(newname);
781159801Snetchild}
782159801Snetchild
783159801Snetchild#define	IFFBITS \
784159801Snetchild"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
785159801Snetchild"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
786159801Snetchild"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
787159801Snetchild
788159801Snetchild#define	IFCAPBITS \
789159801Snetchild"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
790161309Snetchild"\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
791161309Snetchild"\21VLAN_HWFILTER"
792159801Snetchild
793159801Snetchild/*
794161309Snetchild * Print the status of the interface.  If an address family was
795161309Snetchild * specified, show only it; otherwise, show them all.
796159801Snetchild */
797159801Snetchildstatic void
798161309Snetchildstatus(const struct afswtch *afp, const struct sockaddr_dl *sdl,
799161309Snetchild	struct ifaddrs *ifa)
800159801Snetchild{
801159801Snetchild	struct ifaddrs *ift;
802161309Snetchild	int allfamilies, s;
803161309Snetchild	struct ifstat ifs;
804161309Snetchild
805161309Snetchild	if (afp == NULL) {
806159801Snetchild		allfamilies = 1;
807159801Snetchild		ifr.ifr_addr.sa_family = AF_LOCAL;
808161666Snetchild	} else {
809172220Sdwmalone		allfamilies = 0;
810161666Snetchild		ifr.ifr_addr.sa_family =
811159801Snetchild		    afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
812159801Snetchild	}
813159801Snetchild	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
814159801Snetchild
815159801Snetchild	s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
816161309Snetchild	if (s < 0)
817161309Snetchild		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
818161309Snetchild
819159801Snetchild	printf("%s: ", name);
820159801Snetchild	printb("flags", ifa->ifa_flags, IFFBITS);
821165690Snetchild	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
822165690Snetchild		printf(" metric %d", ifr.ifr_metric);
823159801Snetchild	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
824159801Snetchild		printf(" mtu %d", ifr.ifr_mtu);
825159801Snetchild	putchar('\n');
826159801Snetchild
827159801Snetchild	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
828159801Snetchild		if (ifr.ifr_curcap != 0) {
829159801Snetchild			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
830159801Snetchild			putchar('\n');
831159801Snetchild		}
832159801Snetchild		if (supmedia && ifr.ifr_reqcap != 0) {
833159801Snetchild			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
834159801Snetchild			putchar('\n');
835159801Snetchild		}
836159801Snetchild	}
837159801Snetchild
838159801Snetchild	tunnel_status(s);
839159801Snetchild
840159801Snetchild	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
841159801Snetchild		if (ift->ifa_addr == NULL)
842159801Snetchild			continue;
843159801Snetchild		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
844159801Snetchild			continue;
845159801Snetchild		if (allfamilies) {
846159801Snetchild			const struct afswtch *p;
847159801Snetchild			p = af_getbyfamily(ift->ifa_addr->sa_family);
848159801Snetchild			if (p != NULL && p->af_status != NULL)
849159801Snetchild				p->af_status(s, ift);
850159801Snetchild		} else if (afp->af_af == ift->ifa_addr->sa_family)
851159801Snetchild			afp->af_status(s, ift);
852159801Snetchild	}
853159801Snetchild#if 0
854159801Snetchild	if (allfamilies || afp->af_af == AF_LINK) {
855159801Snetchild		const struct afswtch *lafp;
856159801Snetchild
857159801Snetchild		/*
858159801Snetchild		 * Hack; the link level address is received separately
859159801Snetchild		 * from the routing information so any address is not
860159801Snetchild		 * handled above.  Cobble together an entry and invoke
861159801Snetchild		 * the status method specially.
862159801Snetchild		 */
863159801Snetchild		lafp = af_getbyname("lladdr");
864159801Snetchild		if (lafp != NULL) {
865159801Snetchild			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
866159801Snetchild			lafp->af_status(s, &info);
867159801Snetchild		}
868159801Snetchild	}
869159801Snetchild#endif
870159801Snetchild	if (allfamilies)
871159801Snetchild		af_other_status(s);
872159801Snetchild	else if (afp->af_other_status != NULL)
873159801Snetchild		afp->af_other_status(s);
874159801Snetchild
875159801Snetchild	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
876159801Snetchild	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
877159801Snetchild		printf("%s", ifs.ascii);
878159801Snetchild
879159801Snetchild	close(s);
880159801Snetchild	return;
881159801Snetchild}
882159801Snetchild
883159801Snetchildstatic void
884159801Snetchildtunnel_status(int s)
885159801Snetchild{
886159801Snetchild	af_all_tunnel_status(s);
887159801Snetchild}
888168014Sjulian
889168014Sjulianvoid
890168014SjulianPerror(const char *cmd)
891168014Sjulian{
892159801Snetchild	switch (errno) {
893159801Snetchild
894159801Snetchild	case ENXIO:
895159801Snetchild		errx(1, "%s: no such interface", cmd);
896159801Snetchild		break;
897159801Snetchild
898159801Snetchild	case EPERM:
899159801Snetchild		errx(1, "%s: permission denied", cmd);
900159801Snetchild		break;
901159801Snetchild
902159801Snetchild	default:
903159801Snetchild		err(1, "%s", cmd);
904159801Snetchild	}
905159801Snetchild}
906159801Snetchild
907159801Snetchild/*
908159801Snetchild * Print a value a la the %b format of the kernel's printf
909159801Snetchild */
910159801Snetchildvoid
911159801Snetchildprintb(const char *s, unsigned v, const char *bits)
912159801Snetchild{
913159801Snetchild	int i, any = 0;
914159801Snetchild	char c;
915159801Snetchild
916159801Snetchild	if (bits && *bits == 8)
917159801Snetchild		printf("%s=%o", s, v);
918159801Snetchild	else
919159801Snetchild		printf("%s=%x", s, v);
920159801Snetchild	bits++;
921159801Snetchild	if (bits) {
922159801Snetchild		putchar('<');
923159801Snetchild		while ((i = *bits++) != '\0') {
924159801Snetchild			if (v & (1 << (i-1))) {
925159801Snetchild				if (any)
926159801Snetchild					putchar(',');
927159801Snetchild				any = 1;
928159801Snetchild				for (; (c = *bits) > 32; bits++)
929159801Snetchild					putchar(c);
930159801Snetchild			} else
931159801Snetchild				for (; *bits > 32; bits++)
932159801Snetchild					;
933159801Snetchild		}
934159801Snetchild		putchar('>');
935159801Snetchild	}
936159801Snetchild}
937159801Snetchild
938143198Ssobomaxvoid
939133819Stjrifmaybeload(const char *name)
940133819Stjr{
941133819Stjr#define MOD_PREFIX_LEN		3	/* "if_" */
942133819Stjr	struct module_stat mstat;
943133819Stjr	int fileid, modid;
944133819Stjr	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
945133819Stjr	const char *cp;
946133819Stjr
947133819Stjr	/* loading suppressed by the user */
948133819Stjr	if (noload)
949133819Stjr		return;
950133819Stjr
951156919Snetchild	/* trim the interface number off the end */
952133819Stjr	strlcpy(ifname, name, sizeof(ifname));
953133819Stjr	for (dp = ifname; *dp != 0; dp++)
954133819Stjr		if (isdigit(*dp)) {
955133819Stjr			*dp = 0;
956133819Stjr			break;
957133819Stjr		}
958133819Stjr
959133819Stjr	/* turn interface and unit into module name */
960133819Stjr	strcpy(ifkind, "if_");
961133819Stjr	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
962133819Stjr	    sizeof(ifkind) - MOD_PREFIX_LEN);
963133819Stjr
964133819Stjr	/* scan files in kernel */
965133819Stjr	mstat.version = sizeof(struct module_stat);
966133819Stjr	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
967133819Stjr		/* scan modules in file */
968133819Stjr		for (modid = kldfirstmod(fileid); modid > 0;
969133819Stjr		     modid = modfnext(modid)) {
970133819Stjr			if (modstat(modid, &mstat) < 0)
971133819Stjr				continue;
972133819Stjr			/* strip bus name if present */
973133819Stjr			if ((cp = strchr(mstat.name, '/')) != NULL) {
974133819Stjr				cp++;
975133819Stjr			} else {
976133819Stjr				cp = mstat.name;
977133819Stjr			}
978133819Stjr			/* already loaded? */
979133819Stjr			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
980133819Stjr			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
981133819Stjr				return;
982161309Snetchild		}
983133819Stjr	}
984133819Stjr
985133819Stjr	/* not present, we should try to load it */
986133819Stjr	kldload(ifkind);
987133819Stjr}
988133819Stjr
989133819Stjrstatic struct cmd basic_cmds[] = {
990156843Snetchild	DEF_CMD("up",		IFF_UP,		setifflags),
991133819Stjr	DEF_CMD("down",		-IFF_UP,	setifflags),
992133819Stjr	DEF_CMD("arp",		-IFF_NOARP,	setifflags),
993133819Stjr	DEF_CMD("-arp",		IFF_NOARP,	setifflags),
994133819Stjr	DEF_CMD("debug",	IFF_DEBUG,	setifflags),
995133819Stjr	DEF_CMD("-debug",	-IFF_DEBUG,	setifflags),
996133819Stjr	DEF_CMD("promisc",	IFF_PPROMISC,	setifflags),
997133819Stjr	DEF_CMD("-promisc",	-IFF_PPROMISC,	setifflags),
998133819Stjr	DEF_CMD("add",		IFF_UP,		notealias),
999133819Stjr	DEF_CMD("alias",	IFF_UP,		notealias),
1000156919Snetchild	DEF_CMD("-alias",	-IFF_UP,	notealias),
1001133819Stjr	DEF_CMD("delete",	-IFF_UP,	notealias),
1002133819Stjr	DEF_CMD("remove",	-IFF_UP,	notealias),
1003133819Stjr#ifdef notdef
1004133819Stjr#define	EN_SWABIPS	0x1000
1005133819Stjr	DEF_CMD("swabips",	EN_SWABIPS,	setifflags),
1006156843Snetchild	DEF_CMD("-swabips",	-EN_SWABIPS,	setifflags),
1007147142Ssobomax#endif
1008133819Stjr	DEF_CMD_ARG("netmask",			setifnetmask),
1009133819Stjr	DEF_CMD_ARG("metric",			setifmetric),
1010133819Stjr	DEF_CMD_ARG("broadcast",		setifbroadaddr),
1011133819Stjr	DEF_CMD_ARG("ipdst",			setifipdst),
1012133819Stjr	DEF_CMD_ARG2("tunnel",			settunnel),
1013133819Stjr	DEF_CMD("-tunnel", 0,			deletetunnel),
1014133819Stjr	DEF_CMD("deletetunnel", 0,		deletetunnel),
1015133819Stjr	DEF_CMD("link0",	IFF_LINK0,	setifflags),
1016133819Stjr	DEF_CMD("-link0",	-IFF_LINK0,	setifflags),
1017133819Stjr	DEF_CMD("link1",	IFF_LINK1,	setifflags),
1018166730Sjkim	DEF_CMD("-link1",	-IFF_LINK1,	setifflags),
1019133819Stjr	DEF_CMD("link2",	IFF_LINK2,	setifflags),
1020133819Stjr	DEF_CMD("-link2",	-IFF_LINK2,	setifflags),
1021133819Stjr	DEF_CMD("monitor",	IFF_MONITOR,	setifflags),
1022133819Stjr	DEF_CMD("-monitor",	-IFF_MONITOR,	setifflags),
1023133819Stjr	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
1024133819Stjr	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
1025133819Stjr	DEF_CMD("rxcsum",	IFCAP_RXCSUM,	setifcap),
1026133819Stjr	DEF_CMD("-rxcsum",	-IFCAP_RXCSUM,	setifcap),
1027133819Stjr	DEF_CMD("txcsum",	IFCAP_TXCSUM,	setifcap),
1028133819Stjr	DEF_CMD("-txcsum",	-IFCAP_TXCSUM,	setifcap),
1029133819Stjr	DEF_CMD("netcons",	IFCAP_NETCONS,	setifcap),
1030133819Stjr	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
1031133819Stjr	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
1032133819Stjr	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
1033133819Stjr	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
1034133819Stjr	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
1035133819Stjr	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
1036133819Stjr	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
1037133819Stjr	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
1038133819Stjr	DEF_CMD("-wol",		-IFCAP_WOL,	setifcap),
1039133819Stjr	DEF_CMD("wol_ucast",	IFCAP_WOL_UCAST,	setifcap),
1040133819Stjr	DEF_CMD("-wol_ucast",	-IFCAP_WOL_UCAST,	setifcap),
1041133819Stjr	DEF_CMD("wol_mcast",	IFCAP_WOL_MCAST,	setifcap),
1042133819Stjr	DEF_CMD("-wol_mcast",	-IFCAP_WOL_MCAST,	setifcap),
1043133819Stjr	DEF_CMD("wol_magic",	IFCAP_WOL_MAGIC,	setifcap),
1044133819Stjr	DEF_CMD("-wol_magic",	-IFCAP_WOL_MAGIC,	setifcap),
1045133819Stjr	DEF_CMD("normal",	-IFF_LINK0,	setifflags),
1046133819Stjr	DEF_CMD("compress",	IFF_LINK0,	setifflags),
1047133819Stjr	DEF_CMD("noicmp",	IFF_LINK1,	setifflags),
1048133819Stjr	DEF_CMD_ARG("mtu",			setifmtu),
1049133819Stjr	DEF_CMD_ARG("name",			setifname),
1050133819Stjr};
1051133819Stjr
1052133819Stjrstatic __constructor void
1053133819Stjrifconfig_ctor(void)
1054133819Stjr{
1055133819Stjr#define	N(a)	(sizeof(a) / sizeof(a[0]))
1056133819Stjr	int i;
1057133819Stjr
1058133819Stjr	for (i = 0; i < N(basic_cmds);  i++)
1059133819Stjr		cmd_register(&basic_cmds[i]);
1060133819Stjr#undef N
1061133819Stjr}
1062133819Stjr