xref: /freebsd/sbin/ifconfig/ifconfig.c (revision eb6d21b4ca6d668cf89afd99eef7baeafa712197)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1983, 1993\n\
33 	The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35 
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
39 #endif
40 static const char rcsid[] =
41   "$FreeBSD$";
42 #endif /* not lint */
43 
44 #include <sys/param.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <sys/time.h>
49 #include <sys/module.h>
50 #include <sys/linker.h>
51 
52 #include <net/ethernet.h>
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #include <net/if_dl.h>
56 #include <net/if_types.h>
57 #include <net/route.h>
58 
59 /* IP */
60 #include <netinet/in.h>
61 #include <netinet/in_var.h>
62 #include <arpa/inet.h>
63 #include <netdb.h>
64 
65 #include <ifaddrs.h>
66 #include <ctype.h>
67 #include <err.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include <jail.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75 
76 #include "ifconfig.h"
77 
78 /*
79  * Since "struct ifreq" is composed of various union members, callers
80  * should pay special attention to interprete the value.
81  * (.e.g. little/big endian difference in the structure.)
82  */
83 struct	ifreq ifr;
84 
85 char	name[IFNAMSIZ];
86 int	setaddr;
87 int	setmask;
88 int	doalias;
89 int	clearaddr;
90 int	newaddr = 1;
91 int	verbose;
92 int	noload;
93 
94 int	supmedia = 0;
95 int	printkeys = 0;		/* Print keying material for interfaces. */
96 
97 static	int ifconfig(int argc, char *const *argv, int iscreate,
98 		const struct afswtch *afp);
99 static	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
100 		struct ifaddrs *ifa);
101 static	void tunnel_status(int s);
102 static	void usage(void);
103 
104 static struct afswtch *af_getbyname(const char *name);
105 static struct afswtch *af_getbyfamily(int af);
106 static void af_other_status(int);
107 
108 static struct option *opts = NULL;
109 
110 void
111 opt_register(struct option *p)
112 {
113 	p->next = opts;
114 	opts = p;
115 }
116 
117 static void
118 usage(void)
119 {
120 	char options[1024];
121 	struct option *p;
122 
123 	/* XXX not right but close enough for now */
124 	options[0] = '\0';
125 	for (p = opts; p != NULL; p = p->next) {
126 		strlcat(options, p->opt_usage, sizeof(options));
127 		strlcat(options, " ", sizeof(options));
128 	}
129 
130 	fprintf(stderr,
131 	"usage: ifconfig %sinterface address_family [address [dest_address]]\n"
132 	"                [parameters]\n"
133 	"       ifconfig interface create\n"
134 	"       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
135 	"       ifconfig -l [-d] [-u] [address_family]\n"
136 	"       ifconfig %s[-d] [-m] [-u] [-v]\n",
137 		options, options, options);
138 	exit(1);
139 }
140 
141 int
142 main(int argc, char *argv[])
143 {
144 	int c, all, namesonly, downonly, uponly;
145 	const struct afswtch *afp = NULL;
146 	int ifindex;
147 	struct ifaddrs *ifap, *ifa;
148 	struct ifreq paifr;
149 	const struct sockaddr_dl *sdl;
150 	char options[1024], *cp, *namecp = NULL;
151 	const char *ifname;
152 	struct option *p;
153 	size_t iflen;
154 
155 	all = downonly = uponly = namesonly = noload = verbose = 0;
156 
157 	/* Parse leading line options */
158 	strlcpy(options, "adklmnuv", sizeof(options));
159 	for (p = opts; p != NULL; p = p->next)
160 		strlcat(options, p->opt, sizeof(options));
161 	while ((c = getopt(argc, argv, options)) != -1) {
162 		switch (c) {
163 		case 'a':	/* scan all interfaces */
164 			all++;
165 			break;
166 		case 'd':	/* restrict scan to "down" interfaces */
167 			downonly++;
168 			break;
169 		case 'k':
170 			printkeys++;
171 			break;
172 		case 'l':	/* scan interface names only */
173 			namesonly++;
174 			break;
175 		case 'm':	/* show media choices in status */
176 			supmedia = 1;
177 			break;
178 		case 'n':	/* suppress module loading */
179 			noload++;
180 			break;
181 		case 'u':	/* restrict scan to "up" interfaces */
182 			uponly++;
183 			break;
184 		case 'v':
185 			verbose++;
186 			break;
187 		default:
188 			for (p = opts; p != NULL; p = p->next)
189 				if (p->opt[0] == c) {
190 					p->cb(optarg);
191 					break;
192 				}
193 			if (p == NULL)
194 				usage();
195 			break;
196 		}
197 	}
198 	argc -= optind;
199 	argv += optind;
200 
201 	/* -l cannot be used with -a or -m */
202 	if (namesonly && (all || supmedia))
203 		usage();
204 
205 	/* nonsense.. */
206 	if (uponly && downonly)
207 		usage();
208 
209 	/* no arguments is equivalent to '-a' */
210 	if (!namesonly && argc < 1)
211 		all = 1;
212 
213 	/* -a and -l allow an address family arg to limit the output */
214 	if (all || namesonly) {
215 		if (argc > 1)
216 			usage();
217 
218 		ifname = NULL;
219 		ifindex = 0;
220 		if (argc == 1) {
221 			afp = af_getbyname(*argv);
222 			if (afp == NULL)
223 				usage();
224 			if (afp->af_name != NULL)
225 				argc--, argv++;
226 			/* leave with afp non-zero */
227 		}
228 	} else {
229 		/* not listing, need an argument */
230 		if (argc < 1)
231 			usage();
232 
233 		ifname = *argv;
234 		argc--, argv++;
235 
236 		/* check and maybe load support for this interface */
237 		ifmaybeload(ifname);
238 
239 		ifindex = if_nametoindex(ifname);
240 		if (ifindex == 0) {
241 			/*
242 			 * NOTE:  We must special-case the `create' command
243 			 * right here as we would otherwise fail when trying
244 			 * to find the interface.
245 			 */
246 			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
247 			    strcmp(argv[0], "plumb") == 0)) {
248 				iflen = strlcpy(name, ifname, sizeof(name));
249 				if (iflen >= sizeof(name))
250 					errx(1, "%s: cloning name too long",
251 					    ifname);
252 				ifconfig(argc, argv, 1, NULL);
253 				exit(0);
254 			}
255 			/*
256 			 * NOTE:  We have to special-case the `-vnet' command
257 			 * right here as we would otherwise fail when trying
258 			 * to find the interface as it lives in another vnet.
259 			 */
260 			if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) {
261 				iflen = strlcpy(name, ifname, sizeof(name));
262 				if (iflen >= sizeof(name))
263 					errx(1, "%s: interface name too long",
264 					    ifname);
265 				ifconfig(argc, argv, 0, NULL);
266 				exit(0);
267 			}
268 			errx(1, "interface %s does not exist", ifname);
269 		}
270 	}
271 
272 	/* Check for address family */
273 	if (argc > 0) {
274 		afp = af_getbyname(*argv);
275 		if (afp != NULL)
276 			argc--, argv++;
277 	}
278 
279 	if (getifaddrs(&ifap) != 0)
280 		err(EXIT_FAILURE, "getifaddrs");
281 	cp = NULL;
282 	ifindex = 0;
283 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
284 		memset(&paifr, 0, sizeof(paifr));
285 		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
286 		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
287 			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
288 			    ifa->ifa_addr->sa_len);
289 		}
290 
291 		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
292 			continue;
293 		if (ifa->ifa_addr->sa_family == AF_LINK)
294 			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
295 		else
296 			sdl = NULL;
297 		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !namesonly)
298 			continue;
299 		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
300 		if (iflen >= sizeof(name)) {
301 			warnx("%s: interface name too long, skipping",
302 			    ifa->ifa_name);
303 			continue;
304 		}
305 		cp = ifa->ifa_name;
306 
307 		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
308 			continue;
309 		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
310 			continue;
311 		/*
312 		 * Are we just listing the interfaces?
313 		 */
314 		if (namesonly) {
315 			if (namecp == cp)
316 				continue;
317 			if (afp != NULL) {
318 				/* special case for "ether" address family */
319 				if (!strcmp(afp->af_name, "ether")) {
320 					if (sdl == NULL ||
321 					    sdl->sdl_type != IFT_ETHER ||
322 					    sdl->sdl_alen != ETHER_ADDR_LEN)
323 						continue;
324 				} else {
325 					if (ifa->ifa_addr->sa_family != afp->af_af)
326 						continue;
327 				}
328 			}
329 			namecp = cp;
330 			ifindex++;
331 			if (ifindex > 1)
332 				printf(" ");
333 			fputs(name, stdout);
334 			continue;
335 		}
336 		ifindex++;
337 
338 		if (argc > 0)
339 			ifconfig(argc, argv, 0, afp);
340 		else
341 			status(afp, sdl, ifa);
342 	}
343 	if (namesonly)
344 		printf("\n");
345 	freeifaddrs(ifap);
346 
347 	exit(0);
348 }
349 
350 static struct afswtch *afs = NULL;
351 
352 void
353 af_register(struct afswtch *p)
354 {
355 	p->af_next = afs;
356 	afs = p;
357 }
358 
359 static struct afswtch *
360 af_getbyname(const char *name)
361 {
362 	struct afswtch *afp;
363 
364 	for (afp = afs; afp !=  NULL; afp = afp->af_next)
365 		if (strcmp(afp->af_name, name) == 0)
366 			return afp;
367 	return NULL;
368 }
369 
370 static struct afswtch *
371 af_getbyfamily(int af)
372 {
373 	struct afswtch *afp;
374 
375 	for (afp = afs; afp != NULL; afp = afp->af_next)
376 		if (afp->af_af == af)
377 			return afp;
378 	return NULL;
379 }
380 
381 static void
382 af_other_status(int s)
383 {
384 	struct afswtch *afp;
385 	uint8_t afmask[howmany(AF_MAX, NBBY)];
386 
387 	memset(afmask, 0, sizeof(afmask));
388 	for (afp = afs; afp != NULL; afp = afp->af_next) {
389 		if (afp->af_other_status == NULL)
390 			continue;
391 		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
392 			continue;
393 		afp->af_other_status(s);
394 		setbit(afmask, afp->af_af);
395 	}
396 }
397 
398 static void
399 af_all_tunnel_status(int s)
400 {
401 	struct afswtch *afp;
402 	uint8_t afmask[howmany(AF_MAX, NBBY)];
403 
404 	memset(afmask, 0, sizeof(afmask));
405 	for (afp = afs; afp != NULL; afp = afp->af_next) {
406 		if (afp->af_status_tunnel == NULL)
407 			continue;
408 		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
409 			continue;
410 		afp->af_status_tunnel(s);
411 		setbit(afmask, afp->af_af);
412 	}
413 }
414 
415 static struct cmd *cmds = NULL;
416 
417 void
418 cmd_register(struct cmd *p)
419 {
420 	p->c_next = cmds;
421 	cmds = p;
422 }
423 
424 static const struct cmd *
425 cmd_lookup(const char *name, int iscreate)
426 {
427 #define	N(a)	(sizeof(a)/sizeof(a[0]))
428 	const struct cmd *p;
429 
430 	for (p = cmds; p != NULL; p = p->c_next)
431 		if (strcmp(name, p->c_name) == 0) {
432 			if (iscreate) {
433 				if (p->c_iscloneop)
434 					return p;
435 			} else {
436 				if (!p->c_iscloneop)
437 					return p;
438 			}
439 		}
440 	return NULL;
441 #undef N
442 }
443 
444 struct callback {
445 	callback_func *cb_func;
446 	void	*cb_arg;
447 	struct callback *cb_next;
448 };
449 static struct callback *callbacks = NULL;
450 
451 void
452 callback_register(callback_func *func, void *arg)
453 {
454 	struct callback *cb;
455 
456 	cb = malloc(sizeof(struct callback));
457 	if (cb == NULL)
458 		errx(1, "unable to allocate memory for callback");
459 	cb->cb_func = func;
460 	cb->cb_arg = arg;
461 	cb->cb_next = callbacks;
462 	callbacks = cb;
463 }
464 
465 /* specially-handled commands */
466 static void setifaddr(const char *, int, int, const struct afswtch *);
467 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
468 
469 static void setifdstaddr(const char *, int, int, const struct afswtch *);
470 static const struct cmd setifdstaddr_cmd =
471 	DEF_CMD("ifdstaddr", 0, setifdstaddr);
472 
473 static int
474 ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
475 {
476 	const struct afswtch *afp, *nafp;
477 	const struct cmd *p;
478 	struct callback *cb;
479 	int s;
480 
481 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
482 	afp = uafp != NULL ? uafp : af_getbyname("inet");
483 top:
484 	ifr.ifr_addr.sa_family =
485 		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
486 		AF_LOCAL : afp->af_af;
487 
488 	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
489 	    (uafp != NULL || errno != EPROTONOSUPPORT ||
490 	     (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
491 		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
492 
493 	while (argc > 0) {
494 		p = cmd_lookup(*argv, iscreate);
495 		if (iscreate && p == NULL) {
496 			/*
497 			 * Push the clone create callback so the new
498 			 * device is created and can be used for any
499 			 * remaining arguments.
500 			 */
501 			cb = callbacks;
502 			if (cb == NULL)
503 				errx(1, "internal error, no callback");
504 			callbacks = cb->cb_next;
505 			cb->cb_func(s, cb->cb_arg);
506 			iscreate = 0;
507 			/*
508 			 * Handle any address family spec that
509 			 * immediately follows and potentially
510 			 * recreate the socket.
511 			 */
512 			nafp = af_getbyname(*argv);
513 			if (nafp != NULL) {
514 				argc--, argv++;
515 				if (nafp != afp) {
516 					close(s);
517 					afp = nafp;
518 					goto top;
519 				}
520 			}
521 			/*
522 			 * Look for a normal parameter.
523 			 */
524 			continue;
525 		}
526 		if (p == NULL) {
527 			/*
528 			 * Not a recognized command, choose between setting
529 			 * the interface address and the dst address.
530 			 */
531 			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
532 		}
533 		if (p->c_u.c_func || p->c_u.c_func2) {
534 			if (p->c_parameter == NEXTARG) {
535 				if (argv[1] == NULL)
536 					errx(1, "'%s' requires argument",
537 					    p->c_name);
538 				p->c_u.c_func(argv[1], 0, s, afp);
539 				argc--, argv++;
540 			} else if (p->c_parameter == OPTARG) {
541 				p->c_u.c_func(argv[1], 0, s, afp);
542 				if (argv[1] != NULL)
543 					argc--, argv++;
544 			} else if (p->c_parameter == NEXTARG2) {
545 				if (argc < 3)
546 					errx(1, "'%s' requires 2 arguments",
547 					    p->c_name);
548 				p->c_u.c_func2(argv[1], argv[2], s, afp);
549 				argc -= 2, argv += 2;
550 			} else
551 				p->c_u.c_func(*argv, p->c_parameter, s, afp);
552 		}
553 		argc--, argv++;
554 	}
555 
556 	/*
557 	 * Do any post argument processing required by the address family.
558 	 */
559 	if (afp->af_postproc != NULL)
560 		afp->af_postproc(s, afp);
561 	/*
562 	 * Do deferred callbacks registered while processing
563 	 * command-line arguments.
564 	 */
565 	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
566 		cb->cb_func(s, cb->cb_arg);
567 	/*
568 	 * Do deferred operations.
569 	 */
570 	if (clearaddr) {
571 		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
572 			warnx("interface %s cannot change %s addresses!",
573 			      name, afp->af_name);
574 			clearaddr = 0;
575 		}
576 	}
577 	if (clearaddr) {
578 		int ret;
579 		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
580 		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
581 		if (ret < 0) {
582 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
583 				/* means no previous address for interface */
584 			} else
585 				Perror("ioctl (SIOCDIFADDR)");
586 		}
587 	}
588 	if (newaddr) {
589 		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
590 			warnx("interface %s cannot change %s addresses!",
591 			      name, afp->af_name);
592 			newaddr = 0;
593 		}
594 	}
595 	if (newaddr && (setaddr || setmask)) {
596 		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
597 		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
598 			Perror("ioctl (SIOCAIFADDR)");
599 	}
600 
601 	close(s);
602 	return(0);
603 }
604 
605 /*ARGSUSED*/
606 static void
607 setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
608 {
609 	if (afp->af_getaddr == NULL)
610 		return;
611 	/*
612 	 * Delay the ioctl to set the interface addr until flags are all set.
613 	 * The address interpretation may depend on the flags,
614 	 * and the flags may change when the address is set.
615 	 */
616 	setaddr++;
617 	if (doalias == 0 && afp->af_af != AF_LINK)
618 		clearaddr = 1;
619 	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
620 }
621 
622 static void
623 settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
624 {
625 	struct addrinfo *srcres, *dstres;
626 	int ecode;
627 
628 	if (afp->af_settunnel == NULL) {
629 		warn("address family %s does not support tunnel setup",
630 			afp->af_name);
631 		return;
632 	}
633 
634 	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
635 		errx(1, "error in parsing address string: %s",
636 		    gai_strerror(ecode));
637 
638 	if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
639 		errx(1, "error in parsing address string: %s",
640 		    gai_strerror(ecode));
641 
642 	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
643 		errx(1,
644 		    "source and destination address families do not match");
645 
646 	afp->af_settunnel(s, srcres, dstres);
647 
648 	freeaddrinfo(srcres);
649 	freeaddrinfo(dstres);
650 }
651 
652 /* ARGSUSED */
653 static void
654 deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
655 {
656 
657 	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
658 		err(1, "SIOCDIFPHYADDR");
659 }
660 
661 static void
662 setifvnet(const char *jname, int dummy __unused, int s,
663     const struct afswtch *afp)
664 {
665 	struct ifreq my_ifr;
666 
667 	memcpy(&my_ifr, &ifr, sizeof(my_ifr));
668 	my_ifr.ifr_jid = jail_getid(jname);
669 	if (my_ifr.ifr_jid < 0)
670 		errx(1, "%s", jail_errmsg);
671 	if (ioctl(s, SIOCSIFVNET, &my_ifr) < 0)
672 		err(1, "SIOCSIFVNET");
673 }
674 
675 static void
676 setifrvnet(const char *jname, int dummy __unused, int s,
677     const struct afswtch *afp)
678 {
679 	struct ifreq my_ifr;
680 
681 	memcpy(&my_ifr, &ifr, sizeof(my_ifr));
682 	my_ifr.ifr_jid = jail_getid(jname);
683 	if (my_ifr.ifr_jid < 0)
684 		errx(1, "%s", jail_errmsg);
685 	if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0)
686 		err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name);
687 }
688 
689 static void
690 setifnetmask(const char *addr, int dummy __unused, int s,
691     const struct afswtch *afp)
692 {
693 	if (afp->af_getaddr != NULL) {
694 		setmask++;
695 		afp->af_getaddr(addr, MASK);
696 	}
697 }
698 
699 static void
700 setifbroadaddr(const char *addr, int dummy __unused, int s,
701     const struct afswtch *afp)
702 {
703 	if (afp->af_getaddr != NULL)
704 		afp->af_getaddr(addr, DSTADDR);
705 }
706 
707 static void
708 setifipdst(const char *addr, int dummy __unused, int s,
709     const struct afswtch *afp)
710 {
711 	const struct afswtch *inet;
712 
713 	inet = af_getbyname("inet");
714 	if (inet == NULL)
715 		return;
716 	inet->af_getaddr(addr, DSTADDR);
717 	clearaddr = 0;
718 	newaddr = 0;
719 }
720 
721 static void
722 notealias(const char *addr, int param, int s, const struct afswtch *afp)
723 {
724 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
725 	if (setaddr && doalias == 0 && param < 0)
726 		if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
727 			bcopy((caddr_t)rqtosa(af_addreq),
728 			      (caddr_t)rqtosa(af_ridreq),
729 			      rqtosa(af_addreq)->sa_len);
730 	doalias = param;
731 	if (param < 0) {
732 		clearaddr = 1;
733 		newaddr = 0;
734 	} else
735 		clearaddr = 0;
736 #undef rqtosa
737 }
738 
739 /*ARGSUSED*/
740 static void
741 setifdstaddr(const char *addr, int param __unused, int s,
742     const struct afswtch *afp)
743 {
744 	if (afp->af_getaddr != NULL)
745 		afp->af_getaddr(addr, DSTADDR);
746 }
747 
748 /*
749  * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
750  * of the ifreq structure, which may confuse other parts of ifconfig.
751  * Make a private copy so we can avoid that.
752  */
753 static void
754 setifflags(const char *vname, int value, int s, const struct afswtch *afp)
755 {
756 	struct ifreq		my_ifr;
757 	int flags;
758 
759 	memset(&my_ifr, 0, sizeof(my_ifr));
760 	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
761 
762  	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
763  		Perror("ioctl (SIOCGIFFLAGS)");
764  		exit(1);
765  	}
766 	flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16);
767 
768 	if (value < 0) {
769 		value = -value;
770 		flags &= ~value;
771 	} else
772 		flags |= value;
773 	my_ifr.ifr_flags = flags & 0xffff;
774 	my_ifr.ifr_flagshigh = flags >> 16;
775 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
776 		Perror(vname);
777 }
778 
779 void
780 setifcap(const char *vname, int value, int s, const struct afswtch *afp)
781 {
782 	int flags;
783 
784  	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
785  		Perror("ioctl (SIOCGIFCAP)");
786  		exit(1);
787  	}
788 	flags = ifr.ifr_curcap;
789 	if (value < 0) {
790 		value = -value;
791 		flags &= ~value;
792 	} else
793 		flags |= value;
794 	flags &= ifr.ifr_reqcap;
795 	ifr.ifr_reqcap = flags;
796 	if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
797 		Perror(vname);
798 }
799 
800 static void
801 setifmetric(const char *val, int dummy __unused, int s,
802     const struct afswtch *afp)
803 {
804 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
805 	ifr.ifr_metric = atoi(val);
806 	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
807 		warn("ioctl (set metric)");
808 }
809 
810 static void
811 setifmtu(const char *val, int dummy __unused, int s,
812     const struct afswtch *afp)
813 {
814 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
815 	ifr.ifr_mtu = atoi(val);
816 	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
817 		warn("ioctl (set mtu)");
818 }
819 
820 static void
821 setifname(const char *val, int dummy __unused, int s,
822     const struct afswtch *afp)
823 {
824 	char *newname;
825 
826 	newname = strdup(val);
827 	if (newname == NULL) {
828 		warn("no memory to set ifname");
829 		return;
830 	}
831 	ifr.ifr_data = newname;
832 	if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
833 		warn("ioctl (set name)");
834 		free(newname);
835 		return;
836 	}
837 	strlcpy(name, newname, sizeof(name));
838 	free(newname);
839 }
840 
841 #define	IFFBITS \
842 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
843 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
844 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
845 
846 #define	IFCAPBITS \
847 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
848 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
849 "\21VLAN_HWFILTER"
850 
851 /*
852  * Print the status of the interface.  If an address family was
853  * specified, show only it; otherwise, show them all.
854  */
855 static void
856 status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
857 	struct ifaddrs *ifa)
858 {
859 	struct ifaddrs *ift;
860 	int allfamilies, s;
861 	struct ifstat ifs;
862 
863 	if (afp == NULL) {
864 		allfamilies = 1;
865 		ifr.ifr_addr.sa_family = AF_LOCAL;
866 	} else {
867 		allfamilies = 0;
868 		ifr.ifr_addr.sa_family =
869 		    afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
870 	}
871 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
872 
873 	s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
874 	if (s < 0)
875 		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
876 
877 	printf("%s: ", name);
878 	printb("flags", ifa->ifa_flags, IFFBITS);
879 	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
880 		printf(" metric %d", ifr.ifr_metric);
881 	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
882 		printf(" mtu %d", ifr.ifr_mtu);
883 	putchar('\n');
884 
885 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
886 		if (ifr.ifr_curcap != 0) {
887 			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
888 			putchar('\n');
889 		}
890 		if (supmedia && ifr.ifr_reqcap != 0) {
891 			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
892 			putchar('\n');
893 		}
894 	}
895 
896 	tunnel_status(s);
897 
898 	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
899 		if (ift->ifa_addr == NULL)
900 			continue;
901 		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
902 			continue;
903 		if (allfamilies) {
904 			const struct afswtch *p;
905 			p = af_getbyfamily(ift->ifa_addr->sa_family);
906 			if (p != NULL && p->af_status != NULL)
907 				p->af_status(s, ift);
908 		} else if (afp->af_af == ift->ifa_addr->sa_family)
909 			afp->af_status(s, ift);
910 	}
911 #if 0
912 	if (allfamilies || afp->af_af == AF_LINK) {
913 		const struct afswtch *lafp;
914 
915 		/*
916 		 * Hack; the link level address is received separately
917 		 * from the routing information so any address is not
918 		 * handled above.  Cobble together an entry and invoke
919 		 * the status method specially.
920 		 */
921 		lafp = af_getbyname("lladdr");
922 		if (lafp != NULL) {
923 			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
924 			lafp->af_status(s, &info);
925 		}
926 	}
927 #endif
928 	if (allfamilies)
929 		af_other_status(s);
930 	else if (afp->af_other_status != NULL)
931 		afp->af_other_status(s);
932 
933 	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
934 	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
935 		printf("%s", ifs.ascii);
936 
937 	close(s);
938 	return;
939 }
940 
941 static void
942 tunnel_status(int s)
943 {
944 	af_all_tunnel_status(s);
945 }
946 
947 void
948 Perror(const char *cmd)
949 {
950 	switch (errno) {
951 
952 	case ENXIO:
953 		errx(1, "%s: no such interface", cmd);
954 		break;
955 
956 	case EPERM:
957 		errx(1, "%s: permission denied", cmd);
958 		break;
959 
960 	default:
961 		err(1, "%s", cmd);
962 	}
963 }
964 
965 /*
966  * Print a value a la the %b format of the kernel's printf
967  */
968 void
969 printb(const char *s, unsigned v, const char *bits)
970 {
971 	int i, any = 0;
972 	char c;
973 
974 	if (bits && *bits == 8)
975 		printf("%s=%o", s, v);
976 	else
977 		printf("%s=%x", s, v);
978 	bits++;
979 	if (bits) {
980 		putchar('<');
981 		while ((i = *bits++) != '\0') {
982 			if (v & (1 << (i-1))) {
983 				if (any)
984 					putchar(',');
985 				any = 1;
986 				for (; (c = *bits) > 32; bits++)
987 					putchar(c);
988 			} else
989 				for (; *bits > 32; bits++)
990 					;
991 		}
992 		putchar('>');
993 	}
994 }
995 
996 void
997 ifmaybeload(const char *name)
998 {
999 #define MOD_PREFIX_LEN		3	/* "if_" */
1000 	struct module_stat mstat;
1001 	int fileid, modid;
1002 	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
1003 	const char *cp;
1004 
1005 	/* loading suppressed by the user */
1006 	if (noload)
1007 		return;
1008 
1009 	/* trim the interface number off the end */
1010 	strlcpy(ifname, name, sizeof(ifname));
1011 	for (dp = ifname; *dp != 0; dp++)
1012 		if (isdigit(*dp)) {
1013 			*dp = 0;
1014 			break;
1015 		}
1016 
1017 	/* turn interface and unit into module name */
1018 	strcpy(ifkind, "if_");
1019 	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
1020 	    sizeof(ifkind) - MOD_PREFIX_LEN);
1021 
1022 	/* scan files in kernel */
1023 	mstat.version = sizeof(struct module_stat);
1024 	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
1025 		/* scan modules in file */
1026 		for (modid = kldfirstmod(fileid); modid > 0;
1027 		     modid = modfnext(modid)) {
1028 			if (modstat(modid, &mstat) < 0)
1029 				continue;
1030 			/* strip bus name if present */
1031 			if ((cp = strchr(mstat.name, '/')) != NULL) {
1032 				cp++;
1033 			} else {
1034 				cp = mstat.name;
1035 			}
1036 			/* already loaded? */
1037 			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
1038 			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
1039 				return;
1040 		}
1041 	}
1042 
1043 	/* not present, we should try to load it */
1044 	kldload(ifkind);
1045 }
1046 
1047 static struct cmd basic_cmds[] = {
1048 	DEF_CMD("up",		IFF_UP,		setifflags),
1049 	DEF_CMD("down",		-IFF_UP,	setifflags),
1050 	DEF_CMD("arp",		-IFF_NOARP,	setifflags),
1051 	DEF_CMD("-arp",		IFF_NOARP,	setifflags),
1052 	DEF_CMD("debug",	IFF_DEBUG,	setifflags),
1053 	DEF_CMD("-debug",	-IFF_DEBUG,	setifflags),
1054 	DEF_CMD("promisc",	IFF_PPROMISC,	setifflags),
1055 	DEF_CMD("-promisc",	-IFF_PPROMISC,	setifflags),
1056 	DEF_CMD("add",		IFF_UP,		notealias),
1057 	DEF_CMD("alias",	IFF_UP,		notealias),
1058 	DEF_CMD("-alias",	-IFF_UP,	notealias),
1059 	DEF_CMD("delete",	-IFF_UP,	notealias),
1060 	DEF_CMD("remove",	-IFF_UP,	notealias),
1061 #ifdef notdef
1062 #define	EN_SWABIPS	0x1000
1063 	DEF_CMD("swabips",	EN_SWABIPS,	setifflags),
1064 	DEF_CMD("-swabips",	-EN_SWABIPS,	setifflags),
1065 #endif
1066 	DEF_CMD_ARG("netmask",			setifnetmask),
1067 	DEF_CMD_ARG("metric",			setifmetric),
1068 	DEF_CMD_ARG("broadcast",		setifbroadaddr),
1069 	DEF_CMD_ARG("ipdst",			setifipdst),
1070 	DEF_CMD_ARG2("tunnel",			settunnel),
1071 	DEF_CMD("-tunnel", 0,			deletetunnel),
1072 	DEF_CMD("deletetunnel", 0,		deletetunnel),
1073 	DEF_CMD_ARG("vnet",			setifvnet),
1074 	DEF_CMD_ARG("-vnet",			setifrvnet),
1075 	DEF_CMD("link0",	IFF_LINK0,	setifflags),
1076 	DEF_CMD("-link0",	-IFF_LINK0,	setifflags),
1077 	DEF_CMD("link1",	IFF_LINK1,	setifflags),
1078 	DEF_CMD("-link1",	-IFF_LINK1,	setifflags),
1079 	DEF_CMD("link2",	IFF_LINK2,	setifflags),
1080 	DEF_CMD("-link2",	-IFF_LINK2,	setifflags),
1081 	DEF_CMD("monitor",	IFF_MONITOR,	setifflags),
1082 	DEF_CMD("-monitor",	-IFF_MONITOR,	setifflags),
1083 	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
1084 	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
1085 	DEF_CMD("rxcsum",	IFCAP_RXCSUM,	setifcap),
1086 	DEF_CMD("-rxcsum",	-IFCAP_RXCSUM,	setifcap),
1087 	DEF_CMD("txcsum",	IFCAP_TXCSUM,	setifcap),
1088 	DEF_CMD("-txcsum",	-IFCAP_TXCSUM,	setifcap),
1089 	DEF_CMD("netcons",	IFCAP_NETCONS,	setifcap),
1090 	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
1091 	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
1092 	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
1093 	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
1094 	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
1095 	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
1096 	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
1097 	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
1098 	DEF_CMD("-wol",		-IFCAP_WOL,	setifcap),
1099 	DEF_CMD("wol_ucast",	IFCAP_WOL_UCAST,	setifcap),
1100 	DEF_CMD("-wol_ucast",	-IFCAP_WOL_UCAST,	setifcap),
1101 	DEF_CMD("wol_mcast",	IFCAP_WOL_MCAST,	setifcap),
1102 	DEF_CMD("-wol_mcast",	-IFCAP_WOL_MCAST,	setifcap),
1103 	DEF_CMD("wol_magic",	IFCAP_WOL_MAGIC,	setifcap),
1104 	DEF_CMD("-wol_magic",	-IFCAP_WOL_MAGIC,	setifcap),
1105 	DEF_CMD("normal",	-IFF_LINK0,	setifflags),
1106 	DEF_CMD("compress",	IFF_LINK0,	setifflags),
1107 	DEF_CMD("noicmp",	IFF_LINK1,	setifflags),
1108 	DEF_CMD_ARG("mtu",			setifmtu),
1109 	DEF_CMD_ARG("name",			setifname),
1110 };
1111 
1112 static __constructor void
1113 ifconfig_ctor(void)
1114 {
1115 #define	N(a)	(sizeof(a) / sizeof(a[0]))
1116 	size_t i;
1117 
1118 	for (i = 0; i < N(basic_cmds);  i++)
1119 		cmd_register(&basic_cmds[i]);
1120 #undef N
1121 }
1122