ifconfig.c revision 179894
1145516Sdarrenr/*
2145516Sdarrenr * Copyright (c) 1983, 1993
3145516Sdarrenr *	The Regents of the University of California.  All rights reserved.
4145516Sdarrenr *
5145516Sdarrenr * Redistribution and use in source and binary forms, with or without
6145516Sdarrenr * modification, are permitted provided that the following conditions
7145516Sdarrenr * are met:
8145516Sdarrenr * 1. Redistributions of source code must retain the above copyright
9145516Sdarrenr *    notice, this list of conditions and the following disclaimer.
10145516Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright
11145516Sdarrenr *    notice, this list of conditions and the following disclaimer in the
12145516Sdarrenr *    documentation and/or other materials provided with the distribution.
13145516Sdarrenr * 4. Neither the name of the University nor the names of its contributors
14145516Sdarrenr *    may be used to endorse or promote products derived from this software
15145516Sdarrenr *    without specific prior written permission.
16145516Sdarrenr *
17145516Sdarrenr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18145516Sdarrenr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19145516Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20145516Sdarrenr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21145516Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22145516Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23145516Sdarrenr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24145516Sdarrenr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25145516Sdarrenr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26145516Sdarrenr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27145516Sdarrenr * SUCH DAMAGE.
28145516Sdarrenr */
29145516Sdarrenr
30145516Sdarrenr#ifndef lint
31145516Sdarrenrstatic const char copyright[] =
32145516Sdarrenr"@(#) Copyright (c) 1983, 1993\n\
33145516Sdarrenr	The Regents of the University of California.  All rights reserved.\n";
34145516Sdarrenr#endif /* not lint */
35145516Sdarrenr
36145516Sdarrenr#ifndef lint
37145516Sdarrenr#if 0
38145516Sdarrenrstatic char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
39145516Sdarrenr#endif
40145516Sdarrenrstatic const char rcsid[] =
41145516Sdarrenr  "$FreeBSD: head/sbin/ifconfig/ifconfig.c 179894 2008-06-20 17:26:34Z thompsa $";
42145516Sdarrenr#endif /* not lint */
43145516Sdarrenr
44145516Sdarrenr#include <sys/param.h>
45145516Sdarrenr#include <sys/ioctl.h>
46145516Sdarrenr#include <sys/socket.h>
47145516Sdarrenr#include <sys/sysctl.h>
48145516Sdarrenr#include <sys/time.h>
49145516Sdarrenr#include <sys/module.h>
50145516Sdarrenr#include <sys/linker.h>
51145516Sdarrenr
52145516Sdarrenr#include <net/ethernet.h>
53145516Sdarrenr#include <net/if.h>
54145516Sdarrenr#include <net/if_gre.h>
55145516Sdarrenr#include <net/if_var.h>
56145516Sdarrenr#include <net/if_dl.h>
57145516Sdarrenr#include <net/if_types.h>
58145516Sdarrenr#include <net/route.h>
59145516Sdarrenr
60145516Sdarrenr/* IP */
61145516Sdarrenr#include <netinet/in.h>
62145516Sdarrenr#include <netinet/in_var.h>
63145516Sdarrenr#include <arpa/inet.h>
64145516Sdarrenr#include <netdb.h>
65145516Sdarrenr
66145516Sdarrenr#include <ifaddrs.h>
67145516Sdarrenr#include <ctype.h>
68145516Sdarrenr#include <err.h>
69145516Sdarrenr#include <errno.h>
70145516Sdarrenr#include <fcntl.h>
71145516Sdarrenr#include <stdio.h>
72145516Sdarrenr#include <stdlib.h>
73145516Sdarrenr#include <string.h>
74145516Sdarrenr#include <unistd.h>
75145516Sdarrenr
76145516Sdarrenr#include "ifconfig.h"
77145516Sdarrenr
78145516Sdarrenr/*
79145516Sdarrenr * Since "struct ifreq" is composed of various union members, callers
80145516Sdarrenr * should pay special attention to interprete the value.
81145516Sdarrenr * (.e.g. little/big endian difference in the structure.)
82145516Sdarrenr */
83145516Sdarrenrstruct	ifreq ifr;
84145516Sdarrenr
85145516Sdarrenrchar	name[IFNAMSIZ];
86145516Sdarrenrint	setaddr;
87145516Sdarrenrint	setmask;
88145516Sdarrenrint	doalias;
89145516Sdarrenrint	clearaddr;
90145516Sdarrenrint	newaddr = 1;
91145516Sdarrenrint	verbose;
92145516Sdarrenrint	noload;
93145516Sdarrenr
94145516Sdarrenrint	supmedia = 0;
95145516Sdarrenrint	printkeys = 0;		/* Print keying material for interfaces. */
96145516Sdarrenr
97145516Sdarrenrstatic	int ifconfig(int argc, char *const *argv, int iscreate,
98145516Sdarrenr		const struct afswtch *afp);
99145516Sdarrenrstatic	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
100145516Sdarrenr		struct ifaddrs *ifa);
101145516Sdarrenrstatic	void tunnel_status(int s);
102145516Sdarrenrstatic	void usage(void);
103145516Sdarrenr
104145516Sdarrenrstatic struct afswtch *af_getbyname(const char *name);
105145516Sdarrenrstatic struct afswtch *af_getbyfamily(int af);
106145516Sdarrenrstatic void af_other_status(int);
107145516Sdarrenr
108145516Sdarrenrstatic struct option *opts = NULL;
109145516Sdarrenr
110145516Sdarrenrvoid
111145516Sdarrenropt_register(struct option *p)
112145516Sdarrenr{
113145516Sdarrenr	p->next = opts;
114145516Sdarrenr	opts = p;
115145516Sdarrenr}
116145516Sdarrenr
117145516Sdarrenrstatic void
118145516Sdarrenrusage(void)
119145516Sdarrenr{
120145516Sdarrenr	char options[1024];
121145516Sdarrenr	struct option *p;
122145516Sdarrenr
123145516Sdarrenr	/* XXX not right but close enough for now */
124145516Sdarrenr	options[0] = '\0';
125145516Sdarrenr	for (p = opts; p != NULL; p = p->next) {
126145516Sdarrenr		strlcat(options, p->opt_usage, sizeof(options));
127145516Sdarrenr		strlcat(options, " ", sizeof(options));
128145516Sdarrenr	}
129145516Sdarrenr
130145516Sdarrenr	fprintf(stderr,
131145516Sdarrenr	"usage: ifconfig %sinterface address_family [address [dest_address]]\n"
132145516Sdarrenr	"                [parameters]\n"
133145516Sdarrenr	"       ifconfig interface create\n"
134145516Sdarrenr	"       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
135145516Sdarrenr	"       ifconfig -l [-d] [-u] [address_family]\n"
136145516Sdarrenr	"       ifconfig %s[-d] [-m] [-u] [-v]\n",
137145516Sdarrenr		options, options, options);
138145516Sdarrenr	exit(1);
139145516Sdarrenr}
140145516Sdarrenr
141145516Sdarrenrint
142145516Sdarrenrmain(int argc, char *argv[])
143145516Sdarrenr{
144145516Sdarrenr	int c, all, namesonly, downonly, uponly;
145145516Sdarrenr	const struct afswtch *afp = NULL;
146145516Sdarrenr	int ifindex;
147145516Sdarrenr	struct ifaddrs *ifap, *ifa;
148145516Sdarrenr	struct ifreq paifr;
149145516Sdarrenr	const struct sockaddr_dl *sdl;
150145516Sdarrenr	char options[1024], *cp;
151145516Sdarrenr	const char *ifname;
152145516Sdarrenr	struct option *p;
153145516Sdarrenr	size_t iflen;
154145516Sdarrenr
155145516Sdarrenr	all = downonly = uponly = namesonly = noload = verbose = 0;
156145516Sdarrenr
157145516Sdarrenr	/* Parse leading line options */
158145516Sdarrenr	strlcpy(options, "adklmnuv", sizeof(options));
159145516Sdarrenr	for (p = opts; p != NULL; p = p->next)
160145516Sdarrenr		strlcat(options, p->opt, sizeof(options));
161145516Sdarrenr	while ((c = getopt(argc, argv, options)) != -1) {
162145516Sdarrenr		switch (c) {
163145516Sdarrenr		case 'a':	/* scan all interfaces */
164145516Sdarrenr			all++;
165145516Sdarrenr			break;
166145516Sdarrenr		case 'd':	/* restrict scan to "down" interfaces */
167145516Sdarrenr			downonly++;
168145516Sdarrenr			break;
169145516Sdarrenr		case 'k':
170145516Sdarrenr			printkeys++;
171145516Sdarrenr			break;
172145516Sdarrenr		case 'l':	/* scan interface names only */
173145516Sdarrenr			namesonly++;
174145516Sdarrenr			break;
175145516Sdarrenr		case 'm':	/* show media choices in status */
176145516Sdarrenr			supmedia = 1;
177145516Sdarrenr			break;
178145516Sdarrenr		case 'n':	/* suppress module loading */
179145516Sdarrenr			noload++;
180145516Sdarrenr			break;
181145516Sdarrenr		case 'u':	/* restrict scan to "up" interfaces */
182145516Sdarrenr			uponly++;
183145516Sdarrenr			break;
184145516Sdarrenr		case 'v':
185145516Sdarrenr			verbose++;
186145516Sdarrenr			break;
187145516Sdarrenr		default:
188145516Sdarrenr			for (p = opts; p != NULL; p = p->next)
189145516Sdarrenr				if (p->opt[0] == c) {
190145516Sdarrenr					p->cb(optarg);
191145516Sdarrenr					break;
192145516Sdarrenr				}
193145516Sdarrenr			if (p == NULL)
194145516Sdarrenr				usage();
195145516Sdarrenr			break;
196145516Sdarrenr		}
197145516Sdarrenr	}
198145516Sdarrenr	argc -= optind;
199145516Sdarrenr	argv += optind;
200145516Sdarrenr
201145516Sdarrenr	/* -l cannot be used with -a or -m */
202145516Sdarrenr	if (namesonly && (all || supmedia))
203145516Sdarrenr		usage();
204145516Sdarrenr
205145516Sdarrenr	/* nonsense.. */
206145516Sdarrenr	if (uponly && downonly)
207145516Sdarrenr		usage();
208145516Sdarrenr
209145516Sdarrenr	/* no arguments is equivalent to '-a' */
210145516Sdarrenr	if (!namesonly && argc < 1)
211145516Sdarrenr		all = 1;
212145516Sdarrenr
213145516Sdarrenr	/* -a and -l allow an address family arg to limit the output */
214145516Sdarrenr	if (all || namesonly) {
215145516Sdarrenr		if (argc > 1)
216145516Sdarrenr			usage();
217145516Sdarrenr
218145516Sdarrenr		ifname = NULL;
219145516Sdarrenr		ifindex = 0;
220145516Sdarrenr		if (argc == 1) {
221145516Sdarrenr			afp = af_getbyname(*argv);
222145516Sdarrenr			if (afp == NULL)
223145516Sdarrenr				usage();
224145516Sdarrenr			if (afp->af_name != NULL)
225145516Sdarrenr				argc--, argv++;
226145516Sdarrenr			/* leave with afp non-zero */
227145516Sdarrenr		}
228145516Sdarrenr	} else {
229145516Sdarrenr		/* not listing, need an argument */
230145516Sdarrenr		if (argc < 1)
231145516Sdarrenr			usage();
232145516Sdarrenr
233145516Sdarrenr		ifname = *argv;
234145516Sdarrenr		argc--, argv++;
235145516Sdarrenr
236145516Sdarrenr		/* check and maybe load support for this interface */
237145516Sdarrenr		ifmaybeload(ifname);
238145516Sdarrenr
239145516Sdarrenr		ifindex = if_nametoindex(ifname);
240145516Sdarrenr		if (ifindex == 0) {
241145516Sdarrenr			/*
242145516Sdarrenr			 * NOTE:  We must special-case the `create' command
243145516Sdarrenr			 * right here as we would otherwise fail when trying
244145516Sdarrenr			 * to find the interface.
245145516Sdarrenr			 */
246145516Sdarrenr			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
247145516Sdarrenr			    strcmp(argv[0], "plumb") == 0)) {
248145516Sdarrenr				iflen = strlcpy(name, ifname, sizeof(name));
249145516Sdarrenr				if (iflen >= sizeof(name))
250145516Sdarrenr					errx(1, "%s: cloning name too long",
251145516Sdarrenr					    ifname);
252145516Sdarrenr				ifconfig(argc, argv, 1, NULL);
253145516Sdarrenr				exit(0);
254145516Sdarrenr			}
255145516Sdarrenr			errx(1, "interface %s does not exist", ifname);
256145516Sdarrenr		}
257145516Sdarrenr	}
258145516Sdarrenr
259145516Sdarrenr	/* Check for address family */
260145516Sdarrenr	if (argc > 0) {
261145516Sdarrenr		afp = af_getbyname(*argv);
262145516Sdarrenr		if (afp != NULL)
263145516Sdarrenr			argc--, argv++;
264145516Sdarrenr	}
265145516Sdarrenr
266145516Sdarrenr	if (getifaddrs(&ifap) != 0)
267145516Sdarrenr		err(EXIT_FAILURE, "getifaddrs");
268145516Sdarrenr	cp = NULL;
269145516Sdarrenr	ifindex = 0;
270145516Sdarrenr	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
271145516Sdarrenr		memset(&paifr, 0, sizeof(paifr));
272145516Sdarrenr		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
273145516Sdarrenr		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
274145516Sdarrenr			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
275145516Sdarrenr			    ifa->ifa_addr->sa_len);
276145516Sdarrenr		}
277145516Sdarrenr
278145516Sdarrenr		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
279145516Sdarrenr			continue;
280145516Sdarrenr		if (ifa->ifa_addr->sa_family == AF_LINK)
281145516Sdarrenr			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
282145516Sdarrenr		else
283145516Sdarrenr			sdl = NULL;
284145516Sdarrenr		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
285145516Sdarrenr			continue;
286145516Sdarrenr		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
287145516Sdarrenr		if (iflen >= sizeof(name)) {
288145516Sdarrenr			warnx("%s: interface name too long, skipping",
289145516Sdarrenr			    ifa->ifa_name);
290145516Sdarrenr			continue;
291145516Sdarrenr		}
292145516Sdarrenr		cp = ifa->ifa_name;
293145516Sdarrenr
294145516Sdarrenr		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
295145516Sdarrenr			continue;
296145516Sdarrenr		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
297145516Sdarrenr			continue;
298145516Sdarrenr		ifindex++;
299145516Sdarrenr		/*
300145516Sdarrenr		 * Are we just listing the interfaces?
301145516Sdarrenr		 */
302145516Sdarrenr		if (namesonly) {
303145516Sdarrenr			if (ifindex > 1)
304145516Sdarrenr				printf(" ");
305145516Sdarrenr			fputs(name, stdout);
306145516Sdarrenr			continue;
307145516Sdarrenr		}
308145516Sdarrenr
309145516Sdarrenr		if (argc > 0)
310145516Sdarrenr			ifconfig(argc, argv, 0, afp);
311145516Sdarrenr		else
312145516Sdarrenr			status(afp, sdl, ifa);
313145516Sdarrenr	}
314145516Sdarrenr	if (namesonly)
315145516Sdarrenr		printf("\n");
316145516Sdarrenr	freeifaddrs(ifap);
317145516Sdarrenr
318145516Sdarrenr	exit(0);
319145516Sdarrenr}
320145516Sdarrenr
321145516Sdarrenrstatic struct afswtch *afs = NULL;
322145516Sdarrenr
323145516Sdarrenrvoid
324145516Sdarrenraf_register(struct afswtch *p)
325145516Sdarrenr{
326145516Sdarrenr	p->af_next = afs;
327145516Sdarrenr	afs = p;
328145516Sdarrenr}
329145516Sdarrenr
330145516Sdarrenrstatic struct afswtch *
331145516Sdarrenraf_getbyname(const char *name)
332145516Sdarrenr{
333145516Sdarrenr	struct afswtch *afp;
334145516Sdarrenr
335145516Sdarrenr	for (afp = afs; afp !=  NULL; afp = afp->af_next)
336145516Sdarrenr		if (strcmp(afp->af_name, name) == 0)
337145516Sdarrenr			return afp;
338145516Sdarrenr	return NULL;
339145516Sdarrenr}
340145516Sdarrenr
341145516Sdarrenrstatic struct afswtch *
342145516Sdarrenraf_getbyfamily(int af)
343145516Sdarrenr{
344145516Sdarrenr	struct afswtch *afp;
345145516Sdarrenr
346145516Sdarrenr	for (afp = afs; afp != NULL; afp = afp->af_next)
347145516Sdarrenr		if (afp->af_af == af)
348145516Sdarrenr			return afp;
349145516Sdarrenr	return NULL;
350145516Sdarrenr}
351145516Sdarrenr
352145516Sdarrenrstatic void
353145516Sdarrenraf_other_status(int s)
354145516Sdarrenr{
355145516Sdarrenr	struct afswtch *afp;
356145516Sdarrenr	uint8_t afmask[howmany(AF_MAX, NBBY)];
357145516Sdarrenr
358145516Sdarrenr	memset(afmask, 0, sizeof(afmask));
359145516Sdarrenr	for (afp = afs; afp != NULL; afp = afp->af_next) {
360145516Sdarrenr		if (afp->af_other_status == NULL)
361145516Sdarrenr			continue;
362145516Sdarrenr		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
363145516Sdarrenr			continue;
364145516Sdarrenr		afp->af_other_status(s);
365145516Sdarrenr		setbit(afmask, afp->af_af);
366145516Sdarrenr	}
367145516Sdarrenr}
368145516Sdarrenr
369145516Sdarrenrstatic void
370145516Sdarrenraf_all_tunnel_status(int s)
371145516Sdarrenr{
372145516Sdarrenr	struct afswtch *afp;
373145516Sdarrenr	uint8_t afmask[howmany(AF_MAX, NBBY)];
374145516Sdarrenr
375145516Sdarrenr	memset(afmask, 0, sizeof(afmask));
376145516Sdarrenr	for (afp = afs; afp != NULL; afp = afp->af_next) {
377145516Sdarrenr		if (afp->af_status_tunnel == NULL)
378145516Sdarrenr			continue;
379145516Sdarrenr		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
380145516Sdarrenr			continue;
381145516Sdarrenr		afp->af_status_tunnel(s);
382145516Sdarrenr		setbit(afmask, afp->af_af);
383145516Sdarrenr	}
384145516Sdarrenr}
385145516Sdarrenr
386145516Sdarrenrstatic struct cmd *cmds = NULL;
387145516Sdarrenr
388145516Sdarrenrvoid
389145516Sdarrenrcmd_register(struct cmd *p)
390145516Sdarrenr{
391145516Sdarrenr	p->c_next = cmds;
392145516Sdarrenr	cmds = p;
393145516Sdarrenr}
394145516Sdarrenr
395145516Sdarrenrstatic const struct cmd *
396145516Sdarrenrcmd_lookup(const char *name)
397145516Sdarrenr{
398145516Sdarrenr#define	N(a)	(sizeof(a)/sizeof(a[0]))
399145516Sdarrenr	const struct cmd *p;
400145516Sdarrenr
401145516Sdarrenr	for (p = cmds; p != NULL; p = p->c_next)
402145516Sdarrenr		if (strcmp(name, p->c_name) == 0)
403145516Sdarrenr			return p;
404145516Sdarrenr	return NULL;
405145516Sdarrenr#undef N
406145516Sdarrenr}
407145516Sdarrenr
408145516Sdarrenrstruct callback {
409145516Sdarrenr	callback_func *cb_func;
410145516Sdarrenr	void	*cb_arg;
411145516Sdarrenr	struct callback *cb_next;
412145516Sdarrenr};
413145516Sdarrenrstatic struct callback *callbacks = NULL;
414145516Sdarrenr
415145516Sdarrenrvoid
416145516Sdarrenrcallback_register(callback_func *func, void *arg)
417145516Sdarrenr{
418145516Sdarrenr	struct callback *cb;
419145516Sdarrenr
420145516Sdarrenr	cb = malloc(sizeof(struct callback));
421145516Sdarrenr	if (cb == NULL)
422145516Sdarrenr		errx(1, "unable to allocate memory for callback");
423145516Sdarrenr	cb->cb_func = func;
424145516Sdarrenr	cb->cb_arg = arg;
425145516Sdarrenr	cb->cb_next = callbacks;
426145516Sdarrenr	callbacks = cb;
427145516Sdarrenr}
428145516Sdarrenr
429145516Sdarrenr/* specially-handled commands */
430145516Sdarrenrstatic void setifaddr(const char *, int, int, const struct afswtch *);
431145516Sdarrenrstatic const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
432145516Sdarrenr
433145516Sdarrenrstatic void setifdstaddr(const char *, int, int, const struct afswtch *);
434145516Sdarrenrstatic const struct cmd setifdstaddr_cmd =
435145516Sdarrenr	DEF_CMD("ifdstaddr", 0, setifdstaddr);
436145516Sdarrenr
437145516Sdarrenrstatic int
438145516Sdarrenrifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp)
439145516Sdarrenr{
440145516Sdarrenr	const struct afswtch *nafp;
441145516Sdarrenr	struct callback *cb;
442145516Sdarrenr	int s;
443145516Sdarrenr
444145516Sdarrenr	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
445145516Sdarrenrtop:
446145516Sdarrenr	if (afp == NULL)
447145516Sdarrenr		afp = af_getbyname("inet");
448145516Sdarrenr	ifr.ifr_addr.sa_family =
449145516Sdarrenr		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
450145516Sdarrenr		AF_INET : afp->af_af;
451145516Sdarrenr
452145516Sdarrenr	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
453145516Sdarrenr		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
454145516Sdarrenr
455145516Sdarrenr	while (argc > 0) {
456145516Sdarrenr		const struct cmd *p;
457145516Sdarrenr
458145516Sdarrenr		p = cmd_lookup(*argv);
459145516Sdarrenr		if (p == NULL) {
460145516Sdarrenr			/*
461145516Sdarrenr			 * Not a recognized command, choose between setting
462145516Sdarrenr			 * the interface address and the dst address.
463145516Sdarrenr			 */
464145516Sdarrenr			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
465145516Sdarrenr		}
466145516Sdarrenr		if (p->c_u.c_func || p->c_u.c_func2) {
467145516Sdarrenr			if (iscreate && !p->c_iscloneop) {
468145516Sdarrenr				/*
469145516Sdarrenr				 * Push the clone create callback so the new
470145516Sdarrenr				 * device is created and can be used for any
471145516Sdarrenr				 * remaining arguments.
472145516Sdarrenr				 */
473145516Sdarrenr				cb = callbacks;
474145516Sdarrenr				if (cb == NULL)
475145516Sdarrenr					errx(1, "internal error, no callback");
476145516Sdarrenr				callbacks = cb->cb_next;
477145516Sdarrenr				cb->cb_func(s, cb->cb_arg);
478145516Sdarrenr				iscreate = 0;
479145516Sdarrenr				/*
480145516Sdarrenr				 * Handle any address family spec that
481145516Sdarrenr				 * immediately follows and potentially
482145516Sdarrenr				 * recreate the socket.
483145516Sdarrenr				 */
484145516Sdarrenr				nafp = af_getbyname(*argv);
485145516Sdarrenr				if (nafp != NULL) {
486145516Sdarrenr					argc--, argv++;
487145516Sdarrenr					if (nafp != afp) {
488145516Sdarrenr						close(s);
489145516Sdarrenr						afp = nafp;
490145516Sdarrenr						goto top;
491145516Sdarrenr					}
492145516Sdarrenr				}
493145516Sdarrenr			}
494145516Sdarrenr			if (p->c_parameter == NEXTARG) {
495145516Sdarrenr				if (argv[1] == NULL)
496145516Sdarrenr					errx(1, "'%s' requires argument",
497145516Sdarrenr					    p->c_name);
498145516Sdarrenr				p->c_u.c_func(argv[1], 0, s, afp);
499145516Sdarrenr				argc--, argv++;
500145516Sdarrenr			} else if (p->c_parameter == OPTARG) {
501145516Sdarrenr				p->c_u.c_func(argv[1], 0, s, afp);
502145516Sdarrenr				if (argv[1] != NULL)
503145516Sdarrenr					argc--, argv++;
504145516Sdarrenr			} else if (p->c_parameter == NEXTARG2) {
505145516Sdarrenr				if (argc < 3)
506145516Sdarrenr					errx(1, "'%s' requires 2 arguments",
507145516Sdarrenr					    p->c_name);
508145516Sdarrenr				p->c_u.c_func2(argv[1], argv[2], s, afp);
509145516Sdarrenr				argc -= 2, argv += 2;
510145516Sdarrenr			} else
511145516Sdarrenr				p->c_u.c_func(*argv, p->c_parameter, s, afp);
512145516Sdarrenr		}
513145516Sdarrenr		argc--, argv++;
514145516Sdarrenr	}
515145516Sdarrenr
516145516Sdarrenr	/*
517145516Sdarrenr	 * Do any post argument processing required by the address family.
518145516Sdarrenr	 */
519145516Sdarrenr	if (afp->af_postproc != NULL)
520145516Sdarrenr		afp->af_postproc(s, afp);
521145516Sdarrenr	/*
522145516Sdarrenr	 * Do deferred callbacks registered while processing
523145516Sdarrenr	 * command-line arguments.
524145516Sdarrenr	 */
525145516Sdarrenr	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
526145516Sdarrenr		cb->cb_func(s, cb->cb_arg);
527145516Sdarrenr	/*
528	 * Do deferred operations.
529	 */
530	if (clearaddr) {
531		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
532			warnx("interface %s cannot change %s addresses!",
533			      name, afp->af_name);
534			clearaddr = 0;
535		}
536	}
537	if (clearaddr) {
538		int ret;
539		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
540		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
541		if (ret < 0) {
542			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
543				/* means no previous address for interface */
544			} else
545				Perror("ioctl (SIOCDIFADDR)");
546		}
547	}
548	if (newaddr) {
549		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
550			warnx("interface %s cannot change %s addresses!",
551			      name, afp->af_name);
552			newaddr = 0;
553		}
554	}
555	if (newaddr && (setaddr || setmask)) {
556		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
557		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
558			Perror("ioctl (SIOCAIFADDR)");
559	}
560
561	close(s);
562	return(0);
563}
564
565/*ARGSUSED*/
566static void
567setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
568{
569	if (afp->af_getaddr == NULL)
570		return;
571	/*
572	 * Delay the ioctl to set the interface addr until flags are all set.
573	 * The address interpretation may depend on the flags,
574	 * and the flags may change when the address is set.
575	 */
576	setaddr++;
577	if (doalias == 0 && afp->af_af != AF_LINK)
578		clearaddr = 1;
579	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
580}
581
582static void
583settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
584{
585	struct addrinfo *srcres, *dstres;
586	int ecode;
587
588	if (afp->af_settunnel == NULL) {
589		warn("address family %s does not support tunnel setup",
590			afp->af_name);
591		return;
592	}
593
594	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
595		errx(1, "error in parsing address string: %s",
596		    gai_strerror(ecode));
597
598	if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
599		errx(1, "error in parsing address string: %s",
600		    gai_strerror(ecode));
601
602	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
603		errx(1,
604		    "source and destination address families do not match");
605
606	afp->af_settunnel(s, srcres, dstres);
607
608	freeaddrinfo(srcres);
609	freeaddrinfo(dstres);
610}
611
612/* ARGSUSED */
613static void
614deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
615{
616
617	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
618		err(1, "SIOCDIFPHYADDR");
619}
620
621static void
622setifnetmask(const char *addr, int dummy __unused, int s,
623    const struct afswtch *afp)
624{
625	if (afp->af_getaddr != NULL) {
626		setmask++;
627		afp->af_getaddr(addr, MASK);
628	}
629}
630
631static void
632setifbroadaddr(const char *addr, int dummy __unused, int s,
633    const struct afswtch *afp)
634{
635	if (afp->af_getaddr != NULL)
636		afp->af_getaddr(addr, DSTADDR);
637}
638
639static void
640setifipdst(const char *addr, int dummy __unused, int s,
641    const struct afswtch *afp)
642{
643	const struct afswtch *inet;
644
645	inet = af_getbyname("inet");
646	if (inet == NULL)
647		return;
648	inet->af_getaddr(addr, DSTADDR);
649	clearaddr = 0;
650	newaddr = 0;
651}
652
653static void
654notealias(const char *addr, int param, int s, const struct afswtch *afp)
655{
656#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
657	if (setaddr && doalias == 0 && param < 0)
658		if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
659			bcopy((caddr_t)rqtosa(af_addreq),
660			      (caddr_t)rqtosa(af_ridreq),
661			      rqtosa(af_addreq)->sa_len);
662	doalias = param;
663	if (param < 0) {
664		clearaddr = 1;
665		newaddr = 0;
666	} else
667		clearaddr = 0;
668#undef rqtosa
669}
670
671/*ARGSUSED*/
672static void
673setifdstaddr(const char *addr, int param __unused, int s,
674    const struct afswtch *afp)
675{
676	if (afp->af_getaddr != NULL)
677		afp->af_getaddr(addr, DSTADDR);
678}
679
680/*
681 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
682 * of the ifreq structure, which may confuse other parts of ifconfig.
683 * Make a private copy so we can avoid that.
684 */
685static void
686setifflags(const char *vname, int value, int s, const struct afswtch *afp)
687{
688	struct ifreq		my_ifr;
689	int flags;
690
691	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
692
693 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
694 		Perror("ioctl (SIOCGIFFLAGS)");
695 		exit(1);
696 	}
697	strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name));
698	flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16);
699
700	if (value < 0) {
701		value = -value;
702		flags &= ~value;
703	} else
704		flags |= value;
705	my_ifr.ifr_flags = flags & 0xffff;
706	my_ifr.ifr_flagshigh = flags >> 16;
707	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
708		Perror(vname);
709}
710
711void
712setifcap(const char *vname, int value, int s, const struct afswtch *afp)
713{
714	int flags;
715
716 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
717 		Perror("ioctl (SIOCGIFCAP)");
718 		exit(1);
719 	}
720	flags = ifr.ifr_curcap;
721	if (value < 0) {
722		value = -value;
723		flags &= ~value;
724	} else
725		flags |= value;
726	flags &= ifr.ifr_reqcap;
727	ifr.ifr_reqcap = flags;
728	if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
729		Perror(vname);
730}
731
732static void
733setifmetric(const char *val, int dummy __unused, int s,
734    const struct afswtch *afp)
735{
736	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
737	ifr.ifr_metric = atoi(val);
738	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
739		warn("ioctl (set metric)");
740}
741
742static void
743setifmtu(const char *val, int dummy __unused, int s,
744    const struct afswtch *afp)
745{
746	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
747	ifr.ifr_mtu = atoi(val);
748	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
749		warn("ioctl (set mtu)");
750}
751
752static void
753setifgrekey(const char *val, int dummy __unused, int s,
754    const struct afswtch *afp)
755{
756	uint32_t grekey = atol(val);
757
758	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
759	ifr.ifr_data = (caddr_t)&grekey;
760	if (ioctl(s, GRESKEY, (caddr_t)&ifr) < 0)
761		warn("ioctl (set grekey)");
762}
763
764static void
765setifname(const char *val, int dummy __unused, int s,
766    const struct afswtch *afp)
767{
768	char *newname;
769
770	newname = strdup(val);
771	if (newname == NULL) {
772		warn("no memory to set ifname");
773		return;
774	}
775	ifr.ifr_data = newname;
776	if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
777		warn("ioctl (set name)");
778		free(newname);
779		return;
780	}
781	strlcpy(name, newname, sizeof(name));
782	free(newname);
783}
784
785#define	IFFBITS \
786"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
787"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
788"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP\25NEEDSGIANT"
789
790#define	IFCAPBITS \
791"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
792"\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC"
793
794/*
795 * Print the status of the interface.  If an address family was
796 * specified, show only it; otherwise, show them all.
797 */
798static void
799status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
800	struct ifaddrs *ifa)
801{
802	struct ifaddrs *ift;
803	int allfamilies, s;
804	struct ifstat ifs;
805
806	if (afp == NULL) {
807		allfamilies = 1;
808		afp = af_getbyname("inet");
809	} else
810		allfamilies = 0;
811
812	ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
813	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
814
815	s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
816	if (s < 0)
817		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
818
819	printf("%s: ", name);
820	printb("flags", ifa->ifa_flags, IFFBITS);
821	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
822		printf(" metric %d", ifr.ifr_metric);
823	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
824		printf(" mtu %d", ifr.ifr_mtu);
825	putchar('\n');
826
827	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
828		if (ifr.ifr_curcap != 0) {
829			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
830			putchar('\n');
831		}
832		if (supmedia && ifr.ifr_reqcap != 0) {
833			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
834			putchar('\n');
835		}
836	}
837
838	tunnel_status(s);
839
840	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
841		if (ift->ifa_addr == NULL)
842			continue;
843		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
844			continue;
845		if (allfamilies) {
846			const struct afswtch *p;
847			p = af_getbyfamily(ift->ifa_addr->sa_family);
848			if (p != NULL && p->af_status != NULL)
849				p->af_status(s, ift);
850		} else if (afp->af_af == ift->ifa_addr->sa_family)
851			afp->af_status(s, ift);
852	}
853#if 0
854	if (allfamilies || afp->af_af == AF_LINK) {
855		const struct afswtch *lafp;
856
857		/*
858		 * Hack; the link level address is received separately
859		 * from the routing information so any address is not
860		 * handled above.  Cobble together an entry and invoke
861		 * the status method specially.
862		 */
863		lafp = af_getbyname("lladdr");
864		if (lafp != NULL) {
865			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
866			lafp->af_status(s, &info);
867		}
868	}
869#endif
870	if (allfamilies)
871		af_other_status(s);
872	else if (afp->af_other_status != NULL)
873		afp->af_other_status(s);
874
875	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
876	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
877		printf("%s", ifs.ascii);
878
879	int grekey = 0;
880	ifr.ifr_data = (caddr_t)&grekey;
881	if (ioctl(s, GREGKEY, &ifr) == 0)
882		if (grekey != 0)
883			printf("\tgrekey: %d\n", grekey);
884
885	close(s);
886	return;
887}
888
889static void
890tunnel_status(int s)
891{
892	af_all_tunnel_status(s);
893}
894
895void
896Perror(const char *cmd)
897{
898	switch (errno) {
899
900	case ENXIO:
901		errx(1, "%s: no such interface", cmd);
902		break;
903
904	case EPERM:
905		errx(1, "%s: permission denied", cmd);
906		break;
907
908	default:
909		err(1, "%s", cmd);
910	}
911}
912
913/*
914 * Print a value a la the %b format of the kernel's printf
915 */
916void
917printb(const char *s, unsigned v, const char *bits)
918{
919	int i, any = 0;
920	char c;
921
922	if (bits && *bits == 8)
923		printf("%s=%o", s, v);
924	else
925		printf("%s=%x", s, v);
926	bits++;
927	if (bits) {
928		putchar('<');
929		while ((i = *bits++) != '\0') {
930			if (v & (1 << (i-1))) {
931				if (any)
932					putchar(',');
933				any = 1;
934				for (; (c = *bits) > 32; bits++)
935					putchar(c);
936			} else
937				for (; *bits > 32; bits++)
938					;
939		}
940		putchar('>');
941	}
942}
943
944void
945ifmaybeload(const char *name)
946{
947#define MOD_PREFIX_LEN		3	/* "if_" */
948	struct module_stat mstat;
949	int fileid, modid;
950	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
951	const char *cp;
952
953	/* loading suppressed by the user */
954	if (noload)
955		return;
956
957	/* trim the interface number off the end */
958	strlcpy(ifname, name, sizeof(ifname));
959	for (dp = ifname; *dp != 0; dp++)
960		if (isdigit(*dp)) {
961			*dp = 0;
962			break;
963		}
964
965	/* turn interface and unit into module name */
966	strcpy(ifkind, "if_");
967	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
968	    sizeof(ifkind) - MOD_PREFIX_LEN);
969
970	/* scan files in kernel */
971	mstat.version = sizeof(struct module_stat);
972	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
973		/* scan modules in file */
974		for (modid = kldfirstmod(fileid); modid > 0;
975		     modid = modfnext(modid)) {
976			if (modstat(modid, &mstat) < 0)
977				continue;
978			/* strip bus name if present */
979			if ((cp = strchr(mstat.name, '/')) != NULL) {
980				cp++;
981			} else {
982				cp = mstat.name;
983			}
984			/* already loaded? */
985			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
986			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
987				return;
988		}
989	}
990
991	/* not present, we should try to load it */
992	kldload(ifkind);
993}
994
995static struct cmd basic_cmds[] = {
996	DEF_CMD("up",		IFF_UP,		setifflags),
997	DEF_CMD("down",		-IFF_UP,	setifflags),
998	DEF_CMD("arp",		-IFF_NOARP,	setifflags),
999	DEF_CMD("-arp",		IFF_NOARP,	setifflags),
1000	DEF_CMD("debug",	IFF_DEBUG,	setifflags),
1001	DEF_CMD("-debug",	-IFF_DEBUG,	setifflags),
1002	DEF_CMD("promisc",	IFF_PPROMISC,	setifflags),
1003	DEF_CMD("-promisc",	-IFF_PPROMISC,	setifflags),
1004	DEF_CMD("add",		IFF_UP,		notealias),
1005	DEF_CMD("alias",	IFF_UP,		notealias),
1006	DEF_CMD("-alias",	-IFF_UP,	notealias),
1007	DEF_CMD("delete",	-IFF_UP,	notealias),
1008	DEF_CMD("remove",	-IFF_UP,	notealias),
1009#ifdef notdef
1010#define	EN_SWABIPS	0x1000
1011	DEF_CMD("swabips",	EN_SWABIPS,	setifflags),
1012	DEF_CMD("-swabips",	-EN_SWABIPS,	setifflags),
1013#endif
1014	DEF_CMD_ARG("netmask",			setifnetmask),
1015	DEF_CMD_ARG("metric",			setifmetric),
1016	DEF_CMD_ARG("broadcast",		setifbroadaddr),
1017	DEF_CMD_ARG("ipdst",			setifipdst),
1018	DEF_CMD_ARG2("tunnel",			settunnel),
1019	DEF_CMD("-tunnel", 0,			deletetunnel),
1020	DEF_CMD("deletetunnel", 0,		deletetunnel),
1021	DEF_CMD("link0",	IFF_LINK0,	setifflags),
1022	DEF_CMD("-link0",	-IFF_LINK0,	setifflags),
1023	DEF_CMD("link1",	IFF_LINK1,	setifflags),
1024	DEF_CMD("-link1",	-IFF_LINK1,	setifflags),
1025	DEF_CMD("link2",	IFF_LINK2,	setifflags),
1026	DEF_CMD("-link2",	-IFF_LINK2,	setifflags),
1027	DEF_CMD("monitor",	IFF_MONITOR,	setifflags),
1028	DEF_CMD("-monitor",	-IFF_MONITOR,	setifflags),
1029	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
1030	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
1031	DEF_CMD("rxcsum",	IFCAP_RXCSUM,	setifcap),
1032	DEF_CMD("-rxcsum",	-IFCAP_RXCSUM,	setifcap),
1033	DEF_CMD("txcsum",	IFCAP_TXCSUM,	setifcap),
1034	DEF_CMD("-txcsum",	-IFCAP_TXCSUM,	setifcap),
1035	DEF_CMD("netcons",	IFCAP_NETCONS,	setifcap),
1036	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
1037	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
1038	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
1039	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
1040	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
1041	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
1042	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
1043	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
1044	DEF_CMD("-wol",		-IFCAP_WOL,	setifcap),
1045	DEF_CMD("wol_ucast",	IFCAP_WOL_UCAST,	setifcap),
1046	DEF_CMD("-wol_ucast",	-IFCAP_WOL_UCAST,	setifcap),
1047	DEF_CMD("wol_mcast",	IFCAP_WOL_MCAST,	setifcap),
1048	DEF_CMD("-wol_mcast",	-IFCAP_WOL_MCAST,	setifcap),
1049	DEF_CMD("wol_magic",	IFCAP_WOL_MAGIC,	setifcap),
1050	DEF_CMD("-wol_magic",	-IFCAP_WOL_MAGIC,	setifcap),
1051	DEF_CMD("normal",	-IFF_LINK0,	setifflags),
1052	DEF_CMD("compress",	IFF_LINK0,	setifflags),
1053	DEF_CMD("noicmp",	IFF_LINK1,	setifflags),
1054	DEF_CMD_ARG("mtu",			setifmtu),
1055	DEF_CMD_ARG("name",			setifname),
1056	DEF_CMD_ARG("grekey",			setifgrekey),
1057};
1058
1059static __constructor void
1060ifconfig_ctor(void)
1061{
1062#define	N(a)	(sizeof(a) / sizeof(a[0]))
1063	int i;
1064
1065	for (i = 0; i < N(basic_cmds);  i++)
1066		cmd_register(&basic_cmds[i]);
1067#undef N
1068}
1069