1/*
2 * Copyright (c) 2009-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * Copyright (c) 1983, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 4. Neither the name of the University nor the names of its contributors
42 *    may be used to endorse or promote products derived from this software
43 *    without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58#include <sys/cdefs.h>
59
60#ifndef lint
61__unused static const char copyright[] =
62"@(#) Copyright (c) 1983, 1993\n\
63	The Regents of the University of California.  All rights reserved.\n";
64#endif /* not lint */
65
66#include <sys/param.h>
67#include <sys/ioctl.h>
68#include <sys/socket.h>
69#include <sys/sysctl.h>
70#include <sys/time.h>
71#ifndef __APPLE__
72#include <sys/module.h>
73#include <sys/linker.h>
74#endif
75
76#include <net/ethernet.h>
77#include <net/if.h>
78#include <net/if_var.h>
79#include <net/if_dl.h>
80#include <net/if_types.h>
81#include <net/if_mib.h>
82#include <net/route.h>
83#include <net/pktsched/pktsched.h>
84
85/* IP */
86#include <netinet/in.h>
87#include <netinet/in_var.h>
88#include <arpa/inet.h>
89#include <netdb.h>
90
91#include <ifaddrs.h>
92#include <ctype.h>
93#include <err.h>
94#include <errno.h>
95#include <fcntl.h>
96#include <stdio.h>
97#include <stdlib.h>
98#include <string.h>
99#include <unistd.h>
100
101#include "ifconfig.h"
102
103/*
104 * Since "struct ifreq" is composed of various union members, callers
105 * should pay special attention to interprete the value.
106 * (.e.g. little/big endian difference in the structure.)
107 */
108struct	ifreq ifr;
109
110char	name[IFNAMSIZ];
111int	setaddr;
112int	setmask;
113int	doalias;
114int	clearaddr;
115int	newaddr = 1;
116int	noload;
117int all;
118
119int bond_details = 0;
120int	supmedia = 0;
121#if TARGET_OS_EMBEDDED
122int	verbose = 1;
123int	showrtref = 1;
124#else /* !TARGET_OS_EMBEDDED */
125int	verbose = 0;
126int	showrtref = 0;
127#endif /* !TARGET_OS_EMBEDDED */
128int	printkeys = 0;		/* Print keying material for interfaces. */
129
130static	int ifconfig(int argc, char *const *argv, int iscreate,
131		const struct afswtch *afp);
132static	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
133		struct ifaddrs *ifa);
134static char *bytes_to_str(unsigned long long bytes);
135static char *bps_to_str(unsigned long long rate);
136static char *ns_to_str(unsigned long long nsec);
137static	void tunnel_status(int s);
138static	void usage(void);
139static char *sched2str(unsigned int s);
140static char *tl2str(unsigned int s);
141static char *ift2str(unsigned int t, unsigned int f, unsigned int sf);
142
143static struct afswtch *af_getbyname(const char *name);
144static struct afswtch *af_getbyfamily(int af);
145static void af_other_status(int);
146
147static struct option *opts = NULL;
148
149void
150opt_register(struct option *p)
151{
152	p->next = opts;
153	opts = p;
154}
155
156static void
157usage(void)
158{
159	char options[1024];
160	struct option *p;
161
162	/* XXX not right but close enough for now */
163	options[0] = '\0';
164	for (p = opts; p != NULL; p = p->next) {
165		strlcat(options, p->opt_usage, sizeof(options));
166		strlcat(options, " ", sizeof(options));
167	}
168
169	fprintf(stderr,
170	"usage: ifconfig %sinterface address_family [address [dest_address]]\n"
171	"                [parameters]\n"
172	"       ifconfig interface create\n"
173	"       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
174	"       ifconfig -l [-d] [-u] [address_family]\n"
175	"       ifconfig %s[-d] [-m] [-u] [-v]\n",
176		options, options, options);
177	exit(1);
178}
179
180int
181main(int argc, char *argv[])
182{
183	int c, namesonly, downonly, uponly;
184	const struct afswtch *afp = NULL;
185	int ifindex;
186	struct ifaddrs *ifap, *ifa;
187	struct ifreq paifr;
188	const struct sockaddr_dl *sdl;
189	char options[1024], *cp;
190	const char *ifname;
191	struct option *p;
192	size_t iflen;
193
194	all = downonly = uponly = namesonly = noload = 0;
195
196	/* Parse leading line options */
197#ifndef __APPLE__
198	strlcpy(options, "adklmnuv", sizeof(options));
199#else
200	strlcpy(options, "abdlmruv", sizeof(options));
201#endif
202	for (p = opts; p != NULL; p = p->next)
203		strlcat(options, p->opt, sizeof(options));
204	while ((c = getopt(argc, argv, options)) != -1) {
205		switch (c) {
206		case 'a':	/* scan all interfaces */
207			all++;
208			break;
209		case 'b':	/* bond detailed output */
210			bond_details++;
211			break;
212		case 'd':	/* restrict scan to "down" interfaces */
213			downonly++;
214			break;
215#ifndef __APPLE__
216		case 'k':
217			printkeys++;
218			break;
219#endif
220		case 'l':	/* scan interface names only */
221			namesonly++;
222			break;
223		case 'm':	/* show media choices in status */
224			supmedia = 1;
225			break;
226#ifndef __APPLE__
227		case 'n':	/* suppress module loading */
228			noload++;
229			break;
230#endif
231		case 'r':
232			showrtref++;
233			break;
234		case 'u':	/* restrict scan to "up" interfaces */
235			uponly++;
236			break;
237		case 'v':
238			verbose++;
239			break;
240		default:
241			for (p = opts; p != NULL; p = p->next)
242				if (p->opt[0] == c) {
243					p->cb(optarg);
244					break;
245				}
246			if (p == NULL)
247				usage();
248			break;
249		}
250	}
251	argc -= optind;
252	argv += optind;
253
254	/* -l cannot be used with -a or -q or -m or -b */
255	if (namesonly &&
256	    (all || supmedia || bond_details))
257		usage();
258
259	/* nonsense.. */
260	if (uponly && downonly)
261		usage();
262
263	/* no arguments is equivalent to '-a' */
264	if (!namesonly && argc < 1)
265		all = 1;
266
267	/* -a and -l allow an address family arg to limit the output */
268	if (all || namesonly) {
269		if (argc > 1)
270			usage();
271
272		ifname = NULL;
273		ifindex = 0;
274		if (argc == 1) {
275			afp = af_getbyname(*argv);
276			if (afp == NULL)
277				usage();
278			if (afp->af_name != NULL)
279				argc--, argv++;
280			/* leave with afp non-zero */
281		}
282	} else {
283		/* not listing, need an argument */
284		if (argc < 1)
285			usage();
286
287		ifname = *argv;
288		argc--, argv++;
289
290#ifdef notdef
291		/* check and maybe load support for this interface */
292		ifmaybeload(ifname);
293#endif
294		ifindex = if_nametoindex(ifname);
295		if (ifindex == 0) {
296			/*
297			 * NOTE:  We must special-case the `create' command
298			 * right here as we would otherwise fail when trying
299			 * to find the interface.
300			 */
301			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
302			    strcmp(argv[0], "plumb") == 0)) {
303				iflen = strlcpy(name, ifname, sizeof(name));
304				if (iflen >= sizeof(name))
305					errx(1, "%s: cloning name too long",
306					    ifname);
307				ifconfig(argc, argv, 1, NULL);
308				exit(0);
309			}
310			errx(1, "interface %s does not exist", ifname);
311		}
312	}
313
314	/* Check for address family */
315	if (argc > 0) {
316		afp = af_getbyname(*argv);
317		if (afp != NULL)
318			argc--, argv++;
319	}
320
321	if (getifaddrs(&ifap) != 0)
322		err(EXIT_FAILURE, "getifaddrs");
323	cp = NULL;
324	ifindex = 0;
325	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
326		memset(&paifr, 0, sizeof(paifr));
327		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
328		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
329			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
330			    ifa->ifa_addr->sa_len);
331		}
332
333		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
334			continue;
335		if (ifa->ifa_addr->sa_family == AF_LINK)
336			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
337		else
338			sdl = NULL;
339		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
340			continue;
341		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
342		if (iflen >= sizeof(name)) {
343			warnx("%s: interface name too long, skipping",
344			    ifa->ifa_name);
345			continue;
346		}
347		cp = ifa->ifa_name;
348
349		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
350			continue;
351		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
352			continue;
353		ifindex++;
354		/*
355		 * Are we just listing the interfaces?
356		 */
357		if (namesonly) {
358			if (ifindex > 1)
359				printf(" ");
360			fputs(name, stdout);
361			continue;
362		}
363
364		if (argc > 0)
365			ifconfig(argc, argv, 0, afp);
366		else
367			status(afp, sdl, ifa);
368	}
369	if (namesonly)
370		printf("\n");
371	freeifaddrs(ifap);
372
373	exit(0);
374}
375
376static struct afswtch *afs = NULL;
377
378void
379af_register(struct afswtch *p)
380{
381	p->af_next = afs;
382	afs = p;
383}
384
385static struct afswtch *
386af_getbyname(const char *name)
387{
388	struct afswtch *afp;
389
390	for (afp = afs; afp !=  NULL; afp = afp->af_next)
391		if (strcmp(afp->af_name, name) == 0)
392			return afp;
393	return NULL;
394}
395
396static struct afswtch *
397af_getbyfamily(int af)
398{
399	struct afswtch *afp;
400
401	for (afp = afs; afp != NULL; afp = afp->af_next)
402		if (afp->af_af == af)
403			return afp;
404	return NULL;
405}
406
407static void
408af_other_status(int s)
409{
410	struct afswtch *afp;
411	uint8_t afmask[howmany(AF_MAX, NBBY)];
412
413	memset(afmask, 0, sizeof(afmask));
414	for (afp = afs; afp != NULL; afp = afp->af_next) {
415		if (afp->af_other_status == NULL)
416			continue;
417		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
418			continue;
419		afp->af_other_status(s);
420		setbit(afmask, afp->af_af);
421	}
422}
423
424static void
425af_all_tunnel_status(int s)
426{
427	struct afswtch *afp;
428	uint8_t afmask[howmany(AF_MAX, NBBY)];
429
430	memset(afmask, 0, sizeof(afmask));
431	for (afp = afs; afp != NULL; afp = afp->af_next) {
432		if (afp->af_status_tunnel == NULL)
433			continue;
434		if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
435			continue;
436		afp->af_status_tunnel(s);
437		setbit(afmask, afp->af_af);
438	}
439}
440
441static struct cmd *cmds = NULL;
442
443void
444cmd_register(struct cmd *p)
445{
446	p->c_next = cmds;
447	cmds = p;
448}
449
450static const struct cmd *
451cmd_lookup(const char *name)
452{
453#define	N(a)	(sizeof(a)/sizeof(a[0]))
454	const struct cmd *p;
455
456	for (p = cmds; p != NULL; p = p->c_next)
457		if (strcmp(name, p->c_name) == 0)
458			return p;
459	return NULL;
460#undef N
461}
462
463struct callback {
464	callback_func *cb_func;
465	void	*cb_arg;
466	struct callback *cb_next;
467};
468static struct callback *callbacks = NULL;
469
470void
471callback_register(callback_func *func, void *arg)
472{
473	struct callback *cb;
474
475	cb = malloc(sizeof(struct callback));
476	if (cb == NULL)
477		errx(1, "unable to allocate memory for callback");
478	cb->cb_func = func;
479	cb->cb_arg = arg;
480	cb->cb_next = callbacks;
481	callbacks = cb;
482}
483
484/* specially-handled commands */
485static void setifaddr(const char *, int, int, const struct afswtch *);
486static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
487
488static void setifdstaddr(const char *, int, int, const struct afswtch *);
489static const struct cmd setifdstaddr_cmd =
490	DEF_CMD("ifdstaddr", 0, setifdstaddr);
491
492static int
493ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp)
494{
495	const struct afswtch *nafp;
496	struct callback *cb;
497	int s;
498
499	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
500top:
501	if (afp == NULL)
502		afp = af_getbyname("inet");
503	ifr.ifr_addr.sa_family =
504		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
505		AF_INET : afp->af_af;
506
507	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
508		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
509
510	while (argc > 0) {
511		const struct cmd *p;
512
513		p = cmd_lookup(*argv);
514		if (p == NULL) {
515			/*
516			 * Not a recognized command, choose between setting
517			 * the interface address and the dst address.
518			 */
519			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
520		}
521		if (p->c_u.c_func || p->c_u.c_func2) {
522			if (iscreate && !p->c_iscloneop) {
523				/*
524				 * Push the clone create callback so the new
525				 * device is created and can be used for any
526				 * remaining arguments.
527				 */
528				cb = callbacks;
529				if (cb == NULL)
530					errx(1, "internal error, no callback");
531				callbacks = cb->cb_next;
532				cb->cb_func(s, cb->cb_arg);
533				iscreate = 0;
534				/*
535				 * Handle any address family spec that
536				 * immediately follows and potentially
537				 * recreate the socket.
538				 */
539				nafp = af_getbyname(*argv);
540				if (nafp != NULL) {
541					argc--, argv++;
542					if (nafp != afp) {
543						close(s);
544						afp = nafp;
545						goto top;
546					}
547				}
548			}
549			if (p->c_parameter == NEXTARG) {
550				if (argv[1] == NULL)
551					errx(1, "'%s' requires argument",
552					    p->c_name);
553				p->c_u.c_func(argv[1], 0, s, afp);
554				argc--, argv++;
555			} else if (p->c_parameter == OPTARG) {
556				p->c_u.c_func(argv[1], 0, s, afp);
557				if (argv[1] != NULL)
558					argc--, argv++;
559			} else if (p->c_parameter == NEXTARG2) {
560				if (argc < 3)
561					errx(1, "'%s' requires 2 arguments",
562					    p->c_name);
563				p->c_u.c_func2(argv[1], argv[2], s, afp);
564				argc -= 2, argv += 2;
565			} else
566				p->c_u.c_func(*argv, p->c_parameter, s, afp);
567		}
568		argc--, argv++;
569	}
570
571	/*
572	 * Do any post argument processing required by the address family.
573	 */
574	if (afp->af_postproc != NULL)
575		afp->af_postproc(s, afp);
576	/*
577	 * Do deferred callbacks registered while processing
578	 * command-line arguments.
579	 */
580	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
581		cb->cb_func(s, cb->cb_arg);
582	/*
583	 * Do deferred operations.
584	 */
585	if (clearaddr) {
586		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
587			warnx("interface %s cannot change %s addresses!",
588			      name, afp->af_name);
589			clearaddr = 0;
590		}
591	}
592	if (clearaddr) {
593		int ret;
594		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
595		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
596		if (ret < 0) {
597			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
598				/* means no previous address for interface */
599			} else
600				Perror("ioctl (SIOCDIFADDR)");
601		}
602	}
603	if (newaddr) {
604		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
605			warnx("interface %s cannot change %s addresses!",
606			      name, afp->af_name);
607			newaddr = 0;
608		}
609	}
610	if (newaddr && (setaddr || setmask)) {
611		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
612		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
613			Perror("ioctl (SIOCAIFADDR)");
614	}
615
616	close(s);
617	return(0);
618}
619
620/*ARGSUSED*/
621static void
622setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
623{
624	if (afp->af_getaddr == NULL)
625		return;
626	/*
627	 * Delay the ioctl to set the interface addr until flags are all set.
628	 * The address interpretation may depend on the flags,
629	 * and the flags may change when the address is set.
630	 */
631	setaddr++;
632	if (doalias == 0 && afp->af_af != AF_LINK)
633		clearaddr = 1;
634	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
635}
636
637static void
638settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
639{
640	struct addrinfo *srcres, *dstres;
641	int ecode;
642
643	if (afp->af_settunnel == NULL) {
644		warn("address family %s does not support tunnel setup",
645			afp->af_name);
646		return;
647	}
648
649	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
650		errx(1, "error in parsing address string: %s",
651		    gai_strerror(ecode));
652
653	if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
654		errx(1, "error in parsing address string: %s",
655		    gai_strerror(ecode));
656
657	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
658		errx(1,
659		    "source and destination address families do not match");
660
661	afp->af_settunnel(s, srcres, dstres);
662
663	freeaddrinfo(srcres);
664	freeaddrinfo(dstres);
665}
666
667/* ARGSUSED */
668static void
669deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
670{
671
672	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
673		err(1, "SIOCDIFPHYADDR");
674}
675
676static void
677setifnetmask(const char *addr, int dummy __unused, int s,
678    const struct afswtch *afp)
679{
680	if (afp->af_getaddr != NULL) {
681		setmask++;
682		afp->af_getaddr(addr, MASK);
683	}
684}
685
686static void
687setifbroadaddr(const char *addr, int dummy __unused, int s,
688    const struct afswtch *afp)
689{
690	if (afp->af_getaddr != NULL)
691		afp->af_getaddr(addr, DSTADDR);
692}
693
694static void
695setifipdst(const char *addr, int dummy __unused, int s,
696    const struct afswtch *afp)
697{
698	const struct afswtch *inet;
699
700	inet = af_getbyname("inet");
701	if (inet == NULL)
702		return;
703	inet->af_getaddr(addr, DSTADDR);
704	clearaddr = 0;
705	newaddr = 0;
706}
707
708static void
709notealias(const char *addr, int param, int s, const struct afswtch *afp)
710{
711#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
712	if (setaddr && doalias == 0 && param < 0)
713		if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
714			bcopy((caddr_t)rqtosa(af_addreq),
715			      (caddr_t)rqtosa(af_ridreq),
716			      rqtosa(af_addreq)->sa_len);
717	doalias = param;
718	if (param < 0) {
719		clearaddr = 1;
720		newaddr = 0;
721	} else
722		clearaddr = 0;
723#undef rqtosa
724}
725
726/*ARGSUSED*/
727static void
728setifdstaddr(const char *addr, int param __unused, int s,
729    const struct afswtch *afp)
730{
731	if (afp->af_getaddr != NULL)
732		afp->af_getaddr(addr, DSTADDR);
733}
734
735/*
736 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
737 * of the ifreq structure, which may confuse other parts of ifconfig.
738 * Make a private copy so we can avoid that.
739 */
740static void
741setifflags(const char *vname, int value, int s, const struct afswtch *afp)
742{
743	struct ifreq		my_ifr;
744	int flags;
745
746	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
747
748 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
749 		Perror("ioctl (SIOCGIFFLAGS)");
750 		exit(1);
751 	}
752	strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name));
753	flags = my_ifr.ifr_flags;
754
755	if (value < 0) {
756		value = -value;
757		flags &= ~value;
758	} else
759		flags |= value;
760	my_ifr.ifr_flags = flags & 0xffff;
761	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
762		Perror(vname);
763}
764
765#ifdef SIOCGIFCAP
766void
767setifcap(const char *vname, int value, int s, const struct afswtch *afp)
768{
769	int flags;
770
771 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
772 		Perror("ioctl (SIOCGIFCAP)");
773 		exit(1);
774 	}
775	flags = ifr.ifr_curcap;
776	if (value < 0) {
777		value = -value;
778		flags &= ~value;
779	} else
780		flags |= value;
781	flags &= ifr.ifr_reqcap;
782	ifr.ifr_reqcap = flags;
783	if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
784		Perror(vname);
785}
786#endif
787
788static void
789setifmetric(const char *val, int dummy __unused, int s,
790    const struct afswtch *afp)
791{
792	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
793	ifr.ifr_metric = atoi(val);
794	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
795		warn("ioctl (set metric)");
796}
797
798static void
799setifmtu(const char *val, int dummy __unused, int s,
800    const struct afswtch *afp)
801{
802	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
803	ifr.ifr_mtu = atoi(val);
804	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
805		warn("ioctl (set mtu)");
806}
807
808#ifndef __APPLE__
809static void
810setifname(const char *val, int dummy __unused, int s,
811    const struct afswtch *afp)
812{
813	char *newname;
814
815	newname = strdup(val);
816	if (newname == NULL) {
817		warn("no memory to set ifname");
818		return;
819	}
820	ifr.ifr_data = newname;
821	if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
822		warn("ioctl (set name)");
823		free(newname);
824		return;
825	}
826	strlcpy(name, newname, sizeof(name));
827	free(newname);
828}
829#endif
830
831static void
832setrouter(const char *vname, int value, int s, const struct afswtch *afp)
833{
834	if (afp->af_setrouter == NULL) {
835		warn("address family %s does not support router mode",
836		    afp->af_name);
837		return;
838	}
839
840	afp->af_setrouter(s, value);
841}
842
843static void
844setifdesc(const char *val, int dummy __unused, int s, const struct afswtch *afp)
845{
846	struct if_descreq ifdr;
847
848	bzero(&ifdr, sizeof (ifdr));
849	strncpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
850	ifdr.ifdr_len = strlen(val);
851	strncpy((char *)ifdr.ifdr_desc, val, sizeof (ifdr.ifdr_desc));
852
853	if (ioctl(s, SIOCSIFDESC, (caddr_t)&ifdr) < 0) {
854		warn("ioctl (set desc)");
855	}
856}
857
858static void
859settbr(const char *val, int dummy __unused, int s, const struct afswtch *afp)
860{
861	struct if_linkparamsreq iflpr;
862	long double bps;
863	u_int64_t rate;
864	u_int32_t percent = 0;
865	char *cp;
866
867	errno = 0;
868	bzero(&iflpr, sizeof (iflpr));
869	strncpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
870
871	bps = strtold(val, &cp);
872	if (val == cp || errno != 0) {
873		warn("Invalid value '%s'", val);
874		return;
875	}
876	rate = (u_int64_t)bps;
877	if (cp != NULL) {
878		if (!strcmp(cp, "b") || !strcmp(cp, "bps")) {
879			; /* nothing */
880		} else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbps")) {
881			rate *= 1000;
882		} else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbps")) {
883			rate *= 1000 * 1000;
884		} else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbps")) {
885			rate *= 1000 * 1000 * 1000;
886		} else if (!strcmp(cp, "%")) {
887			percent = rate;
888			if (percent == 0 || percent > 100) {
889				printf("Value out of range '%s'", val);
890				return;
891			}
892		} else if (*cp != '\0') {
893			printf("Unknown unit '%s'", cp);
894			return;
895		}
896	}
897	iflpr.iflpr_output_tbr_rate = rate;
898	iflpr.iflpr_output_tbr_percent = percent;
899	if (ioctl(s, SIOCSIFLINKPARAMS, &iflpr) < 0 &&
900	    errno != ENOENT && errno != ENXIO && errno != ENODEV) {
901		warn("ioctl (set link params)");
902	} else if (errno == ENXIO) {
903		printf("TBR cannot be set on %s\n", name);
904	} else if (errno == ENOENT || rate == 0) {
905		printf("%s: TBR is now disabled\n", name);
906	} else if (errno == ENODEV) {
907		printf("%s: requires absolute TBR rate\n", name);
908	} else if (percent != 0) {
909		printf("%s: TBR rate set to %u%% of effective link rate\n",
910		    name, percent);
911	} else {
912		printf("%s: TBR rate set to %s\n", name, bps_to_str(rate));
913	}
914}
915
916static void
917setthrottle(const char *val, int dummy __unused, int s,
918    const struct afswtch *afp)
919{
920	struct if_throttlereq iftr;
921	char *cp;
922
923	errno = 0;
924	bzero(&iftr, sizeof (iftr));
925	strncpy(iftr.ifthr_name, name, sizeof (iftr.ifthr_name));
926
927	iftr.ifthr_level = strtold(val, &cp);
928	if (val == cp || errno != 0) {
929		warn("Invalid value '%s'", val);
930		return;
931	}
932
933	if (ioctl(s, SIOCSIFTHROTTLE, &iftr) < 0 && errno != ENXIO) {
934		warn("ioctl (set throttling level)");
935	} else if (errno == ENXIO) {
936		printf("throttling level cannot be set on %s\n", name);
937	} else {
938		printf("%s: throttling level set to %d\n", name,
939		    iftr.ifthr_level);
940	}
941}
942
943static void
944setlog(const char *val, int dummy __unused, int s,
945    const struct afswtch *afp)
946{
947	char *cp;
948
949	errno = 0;
950	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
951
952	ifr.ifr_log.ifl_level = strtold(val, &cp);
953	if (val == cp || errno != 0) {
954		warn("Invalid value '%s'", val);
955		return;
956	}
957	ifr.ifr_log.ifl_flags = (IFRLOGF_DLIL|IFRLOGF_FAMILY|IFRLOGF_DRIVER|
958	    IFRLOGF_FIRMWARE);
959
960	if (ioctl(s, SIOCSIFLOG, &ifr) < 0)
961		warn("ioctl (set logging parameters)");
962}
963
964void
965setcl2k(const char *vname, int value, int s, const struct afswtch *afp)
966{
967	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
968	ifr.ifr_ifru.ifru_2kcl = value;
969
970	if (ioctl(s, SIOCSIF2KCL, (caddr_t)&ifr) < 0)
971		Perror(vname);
972}
973
974#define	IFFBITS \
975"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
976"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
977"\20MULTICAST"
978
979#define	IFEFBITS \
980"\020\1AUTOCONFIGURING\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \
981"\12VLAN\13BOND\14ARPLL\15NOWINDOWSCALE\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \
982"\21ROUTER6\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \
983"\27AWDL_RESTRICTED\30CL2K\35SENDLIST\36DIRECTLINK\40UPDOWNCHANGE"
984
985#define	IFCAPBITS \
986"\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \
987"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS"
988
989#define	IFRLOGF_BITS \
990"\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE"
991
992/*
993 * Print the status of the interface.  If an address family was
994 * specified, show only it; otherwise, show them all.
995 */
996static void
997status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
998	struct ifaddrs *ifa)
999{
1000	struct ifaddrs *ift;
1001	int allfamilies, s;
1002	struct ifstat ifs;
1003	struct if_descreq ifdr;
1004	struct if_linkparamsreq iflpr;
1005	int mib[6];
1006	struct ifmibdata_supplemental ifmsupp;
1007	size_t miblen = sizeof(struct ifmibdata_supplemental);
1008	u_int64_t eflags = 0;
1009
1010	if (afp == NULL) {
1011		allfamilies = 1;
1012		afp = af_getbyname("inet");
1013	} else
1014		allfamilies = 0;
1015
1016	ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
1017	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1018
1019	s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
1020	if (s < 0)
1021		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
1022
1023	printf("%s: ", name);
1024	printb("flags", ifa->ifa_flags, IFFBITS);
1025	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
1026		if (ifr.ifr_metric)
1027			printf(" metric %d", ifr.ifr_metric);
1028	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
1029		printf(" mtu %d", ifr.ifr_mtu);
1030	if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1)
1031		printf(" rtref %d", ifr.ifr_route_refcnt);
1032    if (verbose) {
1033        unsigned int ifindex = if_nametoindex(ifa->ifa_name);
1034        if (ifindex != 0)
1035            printf(" index %u", ifindex);
1036    }
1037	putchar('\n');
1038
1039	if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 &&
1040	    (eflags = ifr.ifr_eflags) != 0) {
1041		printb("\teflags", eflags, IFEFBITS);
1042		putchar('\n');
1043	}
1044
1045#ifdef SIOCGIFCAP
1046	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
1047		if (ifr.ifr_curcap != 0) {
1048			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
1049			putchar('\n');
1050		}
1051		if (supmedia && ifr.ifr_reqcap != 0) {
1052			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
1053			putchar('\n');
1054		}
1055	}
1056#endif
1057
1058	tunnel_status(s);
1059
1060	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
1061		if (ift->ifa_addr == NULL)
1062			continue;
1063		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
1064			continue;
1065		if (allfamilies) {
1066			const struct afswtch *p;
1067			p = af_getbyfamily(ift->ifa_addr->sa_family);
1068			if (p != NULL && p->af_status != NULL)
1069				p->af_status(s, ift);
1070		} else if (afp->af_af == ift->ifa_addr->sa_family)
1071			afp->af_status(s, ift);
1072	}
1073#if 0
1074	if (allfamilies || afp->af_af == AF_LINK) {
1075		const struct afswtch *lafp;
1076
1077		/*
1078		 * Hack; the link level address is received separately
1079		 * from the routing information so any address is not
1080		 * handled above.  Cobble together an entry and invoke
1081		 * the status method specially.
1082		 */
1083		lafp = af_getbyname("lladdr");
1084		if (lafp != NULL) {
1085			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
1086			lafp->af_status(s, &info);
1087		}
1088	}
1089#endif
1090	if (allfamilies)
1091		af_other_status(s);
1092	else if (afp->af_other_status != NULL)
1093		afp->af_other_status(s);
1094
1095	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
1096	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
1097		printf("%s", ifs.ascii);
1098
1099	/* The rest is for when verbose is set; if not set, we're done */
1100	if (!verbose)
1101		goto done;
1102
1103	if (ioctl(s, SIOCGIFTYPE, &ifr) != -1) {
1104		char *c = ift2str(ifr.ifr_type.ift_type,
1105		    ifr.ifr_type.ift_family, ifr.ifr_type.ift_subfamily);
1106		if (c != NULL)
1107			printf("\ttype: %s\n", c);
1108	}
1109
1110	if (ioctl(s, SIOCGIFLINKQUALITYMETRIC, &ifr) != -1) {
1111		int lqm = ifr.ifr_link_quality_metric;
1112		if (verbose > 1) {
1113			printf("\tlink quality: %d ", lqm);
1114			if (lqm == IFNET_LQM_THRESH_OFF) {
1115				printf("(off)");
1116			} else if (lqm == IFNET_LQM_THRESH_UNKNOWN) {
1117				printf("(unknown)");
1118			} else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
1119			    lqm <= IFNET_LQM_THRESH_POOR)
1120				printf("(poor)");
1121			else if (lqm > IFNET_LQM_THRESH_POOR &&
1122			    lqm <= IFNET_LQM_THRESH_GOOD)
1123				printf("(good)");
1124			else
1125				printf("(?)");
1126			printf("\n");
1127		} else if (lqm > IFNET_LQM_THRESH_UNKNOWN) {
1128			printf("\tlink quality: %d ", lqm);
1129			if (lqm <= IFNET_LQM_THRESH_POOR)
1130				printf("(poor)");
1131			else if (lqm > IFNET_LQM_THRESH_POOR &&
1132			    lqm <= IFNET_LQM_THRESH_GOOD)
1133				printf("(good)");
1134			else
1135				printf("(?)");
1136			printf("\n");
1137		}
1138	}
1139
1140	bzero(&iflpr, sizeof (iflpr));
1141	strncpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
1142	if (ioctl(s, SIOCGIFLINKPARAMS, &iflpr) != -1) {
1143		u_int64_t ibw_max = iflpr.iflpr_input_bw.max_bw;
1144		u_int64_t ibw_eff = iflpr.iflpr_input_bw.eff_bw;
1145		u_int64_t obw_max = iflpr.iflpr_output_bw.max_bw;
1146		u_int64_t obw_eff = iflpr.iflpr_output_bw.eff_bw;
1147		u_int64_t obw_tbr = iflpr.iflpr_output_tbr_rate;
1148		u_int32_t obw_pct = iflpr.iflpr_output_tbr_percent;
1149		u_int64_t ilt_max = iflpr.iflpr_input_lt.max_lt;
1150		u_int64_t ilt_eff = iflpr.iflpr_input_lt.eff_lt;
1151		u_int64_t olt_max = iflpr.iflpr_output_lt.max_lt;
1152		u_int64_t olt_eff = iflpr.iflpr_output_lt.eff_lt;
1153
1154
1155		if (eflags & IFEF_TXSTART) {
1156			u_int32_t flags = iflpr.iflpr_flags;
1157			u_int32_t sched = iflpr.iflpr_output_sched;
1158			struct if_throttlereq iftr;
1159
1160			printf("\tscheduler: %s%s ",
1161			    (flags & IFLPRF_ALTQ) ? "ALTQ_" : "",
1162			    sched2str(sched));
1163			if (flags & IFLPRF_DRVMANAGED)
1164				printf("(driver managed)");
1165			printf("\n");
1166
1167			bzero(&iftr, sizeof (iftr));
1168			strncpy(iftr.ifthr_name, name,
1169			    sizeof (iftr.ifthr_name));
1170			if (ioctl(s, SIOCGIFTHROTTLE, &iftr) != -1 &&
1171			    iftr.ifthr_level != IFNET_THROTTLE_OFF)
1172				printf("\tthrottling: level %d (%s)\n",
1173				    iftr.ifthr_level, tl2str(iftr.ifthr_level));
1174		}
1175
1176		if (obw_tbr != 0 && obw_eff > obw_tbr)
1177			obw_eff = obw_tbr;
1178
1179		if (ibw_max != 0 || obw_max != 0) {
1180			if (ibw_max == obw_max && ibw_eff == obw_eff &&
1181			    ibw_max == ibw_eff && obw_tbr == 0) {
1182				printf("\tlink rate: %s\n",
1183				    bps_to_str(ibw_max));
1184			} else {
1185				printf("\tuplink rate: %s [eff] / ",
1186				    bps_to_str(obw_eff));
1187				if (obw_tbr != 0) {
1188					if (obw_pct == 0)
1189						printf("%s [tbr] / ",
1190						    bps_to_str(obw_tbr));
1191					else
1192						printf("%s [tbr %u%%] / ",
1193						    bps_to_str(obw_tbr),
1194						    obw_pct);
1195				}
1196				printf("%s", bps_to_str(obw_max));
1197				if (obw_tbr != 0)
1198					printf(" [max]");
1199				printf("\n");
1200				if (ibw_eff == ibw_max) {
1201					printf("\tdownlink rate: %s\n",
1202					    bps_to_str(ibw_max));
1203				} else {
1204					printf("\tdownlink rate: "
1205					    "%s [eff] / ", bps_to_str(ibw_eff));
1206					printf("%s [max]\n",
1207					    bps_to_str(ibw_max));
1208				}
1209			}
1210		} else if (obw_tbr != 0) {
1211			printf("\tuplink rate: %s [tbr]\n",
1212			    bps_to_str(obw_tbr));
1213		}
1214
1215		if (ilt_max != 0 || olt_max != 0) {
1216			if (ilt_max == olt_max && ilt_eff == olt_eff &&
1217			    ilt_max == ilt_eff) {
1218				printf("\tlink latency: %s\n",
1219				    ns_to_str(ilt_max));
1220			} else {
1221				if (olt_max != 0 && olt_eff == olt_max) {
1222					printf("\tuplink latency: %s\n",
1223					    ns_to_str(olt_max));
1224				} else if (olt_max != 0) {
1225					printf("\tuplink latency: "
1226					    "%s [eff] / ", ns_to_str(olt_eff));
1227					printf("%s [max]\n",
1228					    ns_to_str(olt_max));
1229				}
1230				if (ilt_max != 0 && ilt_eff == ilt_max) {
1231					printf("\tdownlink latency: %s\n",
1232					    ns_to_str(ilt_max));
1233				} else if (ilt_max != 0) {
1234					printf("\tdownlink latency: "
1235					    "%s [eff] / ", ns_to_str(ilt_eff));
1236					printf("%s [max]\n",
1237					    ns_to_str(ilt_max));
1238				}
1239			}
1240		}
1241	}
1242
1243	/* Common OID prefix */
1244	mib[0] = CTL_NET;
1245	mib[1] = PF_LINK;
1246	mib[2] = NETLINK_GENERIC;
1247	mib[3] = IFMIB_IFDATA;
1248	mib[4] = if_nametoindex(name);
1249	mib[5] = IFDATA_SUPPLEMENTAL;
1250	if (sysctl(mib, 6, &ifmsupp, &miblen, (void *)0, 0) == -1)
1251		err(1, "sysctl IFDATA_SUPPLEMENTAL");
1252
1253	if (ifmsupp.ifmd_data_extended.ifi_alignerrs != 0) {
1254		printf("\tunaligned pkts: %llu\n",
1255		    ifmsupp.ifmd_data_extended.ifi_alignerrs);
1256	}
1257	if (ifmsupp.ifmd_data_extended.ifi_dt_bytes != 0) {
1258		printf("\tdata milestone interval: %s\n",
1259		    bytes_to_str(ifmsupp.ifmd_data_extended.ifi_dt_bytes));
1260	}
1261
1262	bzero(&ifdr, sizeof (ifdr));
1263	strncpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
1264	if (ioctl(s, SIOCGIFDESC, &ifdr) != -1 && ifdr.ifdr_len) {
1265		printf("\tdesc: %s\n", ifdr.ifdr_desc);
1266	}
1267
1268	if (ioctl(s, SIOCGIFLOG, &ifr) != -1 && ifr.ifr_log.ifl_level) {
1269		printf("\tlogging: level %d ", ifr.ifr_log.ifl_level);
1270		printb("facilities", ifr.ifr_log.ifl_flags, IFRLOGF_BITS);
1271		putchar('\n');
1272	}
1273
1274	if (ioctl(s, SIOCGIFDELEGATE, &ifr) != -1 && ifr.ifr_delegated) {
1275		char delegatedif[IFNAMSIZ+1];
1276		if (if_indextoname(ifr.ifr_delegated, delegatedif) != NULL)
1277			printf("\teffective interface: %s\n", delegatedif);
1278	}
1279
1280done:
1281	close(s);
1282	return;
1283}
1284
1285#define	KILOBYTES	1024
1286#define	MEGABYTES	(KILOBYTES * KILOBYTES)
1287#define	GIGABYTES	(KILOBYTES * KILOBYTES * KILOBYTES)
1288
1289static char *
1290bytes_to_str(unsigned long long bytes)
1291{
1292        static char buf[32];
1293        const char *u;
1294        long double n = bytes, t;
1295
1296        if (bytes >= GIGABYTES) {
1297                t = n / GIGABYTES;
1298                u = "GB";
1299        } else if (n >= MEGABYTES) {
1300                t = n / MEGABYTES;
1301                u = "MB";
1302        } else if (n >= KILOBYTES) {
1303                t = n / KILOBYTES;
1304                u = "KB";
1305        } else {
1306                t = n;
1307                u = "bytes";
1308        }
1309
1310        snprintf(buf, sizeof (buf), "%-4.2Lf %s", t, u);
1311        return (buf);
1312}
1313
1314#define	GIGABIT_PER_SEC	1000000000	/* gigabit per second */
1315#define MEGABIT_PER_SEC	1000000		/* megabit per second */
1316#define	KILOBIT_PER_SEC	1000		/* kilobit per second */
1317
1318static char *
1319bps_to_str(unsigned long long rate)
1320{
1321        static char buf[32];
1322        const char *u;
1323        long double n = rate, t;
1324
1325        if (rate >= GIGABIT_PER_SEC) {
1326                t = n / GIGABIT_PER_SEC;
1327                u = "Gbps";
1328        } else if (n >= MEGABIT_PER_SEC) {
1329                t = n / MEGABIT_PER_SEC;
1330                u = "Mbps";
1331        } else if (n >= KILOBIT_PER_SEC) {
1332                t = n / KILOBIT_PER_SEC;
1333                u = "Kbps";
1334        } else {
1335                t = n;
1336                u = "bps ";
1337        }
1338
1339        snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
1340        return (buf);
1341}
1342
1343#define	NSEC_PER_SEC	1000000000	/* nanosecond per second */
1344#define	USEC_PER_SEC	1000000		/* microsecond per second */
1345#define	MSEC_PER_SEC	1000		/* millisecond per second */
1346
1347static char *
1348ns_to_str(unsigned long long nsec)
1349{
1350        static char buf[32];
1351        const char *u;
1352        long double n = nsec, t;
1353
1354        if (nsec >= NSEC_PER_SEC) {
1355                t = n / NSEC_PER_SEC;
1356                u = "sec ";
1357        } else if (n >= USEC_PER_SEC) {
1358                t = n / USEC_PER_SEC;
1359                u = "msec";
1360        } else if (n >= MSEC_PER_SEC) {
1361                t = n / MSEC_PER_SEC;
1362                u = "usec";
1363        } else {
1364                t = n;
1365                u = "nsec";
1366        }
1367
1368        snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
1369        return (buf);
1370}
1371
1372static void
1373tunnel_status(int s)
1374{
1375	af_all_tunnel_status(s);
1376}
1377
1378void
1379Perror(const char *cmd)
1380{
1381	switch (errno) {
1382
1383	case ENXIO:
1384		errx(1, "%s: no such interface", cmd);
1385		break;
1386
1387	case EPERM:
1388		errx(1, "%s: permission denied", cmd);
1389		break;
1390
1391	default:
1392		err(1, "%s", cmd);
1393	}
1394}
1395
1396/*
1397 * Print a value a la the %b format of the kernel's printf
1398 */
1399void
1400printb(const char *s, unsigned v, const char *bits)
1401{
1402	int i, any = 0;
1403	char c;
1404
1405	if (bits && *bits == 8)
1406		printf("%s=%o", s, v);
1407	else
1408		printf("%s=%x", s, v);
1409	bits++;
1410	if (bits) {
1411		putchar('<');
1412		while ((i = *bits++) != '\0') {
1413			if (v & (1 << (i-1))) {
1414				if (any)
1415					putchar(',');
1416				any = 1;
1417				for (; (c = *bits) > 32; bits++)
1418					putchar(c);
1419			} else
1420				for (; *bits > 32; bits++)
1421					;
1422		}
1423		putchar('>');
1424	}
1425}
1426
1427#ifndef __APPLE__
1428void
1429ifmaybeload(const char *name)
1430{
1431#define MOD_PREFIX_LEN		3	/* "if_" */
1432	struct module_stat mstat;
1433	int fileid, modid;
1434	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
1435	const char *cp;
1436
1437	/* loading suppressed by the user */
1438	if (noload)
1439		return;
1440
1441	/* trim the interface number off the end */
1442	strlcpy(ifname, name, sizeof(ifname));
1443	for (dp = ifname; *dp != 0; dp++)
1444		if (isdigit(*dp)) {
1445			*dp = 0;
1446			break;
1447		}
1448
1449	/* turn interface and unit into module name */
1450	strlcpy(ifkind, "if_", sizeof(ifkind));
1451	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
1452	    sizeof(ifkind) - MOD_PREFIX_LEN);
1453
1454	/* scan files in kernel */
1455	mstat.version = sizeof(struct module_stat);
1456	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
1457		/* scan modules in file */
1458		for (modid = kldfirstmod(fileid); modid > 0;
1459		     modid = modfnext(modid)) {
1460			if (modstat(modid, &mstat) < 0)
1461				continue;
1462			/* strip bus name if present */
1463			if ((cp = strchr(mstat.name, '/')) != NULL) {
1464				cp++;
1465			} else {
1466				cp = mstat.name;
1467			}
1468			/* already loaded? */
1469			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
1470			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
1471				return;
1472		}
1473	}
1474
1475	/* not present, we should try to load it */
1476	kldload(ifkind);
1477}
1478#endif
1479
1480static struct cmd basic_cmds[] = {
1481	DEF_CMD("up",		IFF_UP,		setifflags),
1482	DEF_CMD("down",		-IFF_UP,	setifflags),
1483	DEF_CMD("arp",		-IFF_NOARP,	setifflags),
1484	DEF_CMD("-arp",		IFF_NOARP,	setifflags),
1485	DEF_CMD("debug",	IFF_DEBUG,	setifflags),
1486	DEF_CMD("-debug",	-IFF_DEBUG,	setifflags),
1487#ifdef IFF_PPROMISC
1488	DEF_CMD("promisc",	IFF_PPROMISC,	setifflags),
1489	DEF_CMD("-promisc",	-IFF_PPROMISC,	setifflags),
1490#endif /* IFF_PPROMISC */
1491	DEF_CMD("add",		IFF_UP,		notealias),
1492	DEF_CMD("alias",	IFF_UP,		notealias),
1493	DEF_CMD("-alias",	-IFF_UP,	notealias),
1494	DEF_CMD("delete",	-IFF_UP,	notealias),
1495	DEF_CMD("remove",	-IFF_UP,	notealias),
1496#ifdef notdef
1497#define	EN_SWABIPS	0x1000
1498	DEF_CMD("swabips",	EN_SWABIPS,	setifflags),
1499	DEF_CMD("-swabips",	-EN_SWABIPS,	setifflags),
1500#endif
1501	DEF_CMD_ARG("netmask",			setifnetmask),
1502	DEF_CMD_ARG("metric",			setifmetric),
1503	DEF_CMD_ARG("broadcast",		setifbroadaddr),
1504	DEF_CMD_ARG("ipdst",			setifipdst),
1505	DEF_CMD_ARG2("tunnel",			settunnel),
1506	DEF_CMD("-tunnel", 0,			deletetunnel),
1507	DEF_CMD("deletetunnel", 0,		deletetunnel),
1508	DEF_CMD("link0",	IFF_LINK0,	setifflags),
1509	DEF_CMD("-link0",	-IFF_LINK0,	setifflags),
1510	DEF_CMD("link1",	IFF_LINK1,	setifflags),
1511	DEF_CMD("-link1",	-IFF_LINK1,	setifflags),
1512	DEF_CMD("link2",	IFF_LINK2,	setifflags),
1513	DEF_CMD("-link2",	-IFF_LINK2,	setifflags),
1514#ifdef IFF_MONITOR
1515	DEF_CMD("monitor",	IFF_MONITOR:,	setifflags),
1516	DEF_CMD("-monitor",	-IFF_MONITOR,	setifflags),
1517#endif /* IFF_MONITOR */
1518#ifdef IFF_STATICARP
1519	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
1520	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
1521#endif /* IFF_STATICARP */
1522#ifdef IFCAP_RXCSUM
1523	DEF_CMD("rxcsum",	IFCAP_RXCSUM,	setifcap),
1524	DEF_CMD("-rxcsum",	-IFCAP_RXCSUM,	setifcap),
1525#endif /* IFCAP_RXCSUM */
1526#ifdef IFCAP_TXCSUM
1527	DEF_CMD("txcsum",	IFCAP_TXCSUM,	setifcap),
1528	DEF_CMD("-txcsum",	-IFCAP_TXCSUM,	setifcap),
1529#endif /* IFCAP_TXCSUM */
1530#ifdef IFCAP_NETCONS
1531	DEF_CMD("netcons",	IFCAP_NETCONS,	setifcap),
1532	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
1533#endif /* IFCAP_NETCONS */
1534#ifdef IFCAP_POLLING
1535	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
1536	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
1537#endif /* IFCAP_POLLING */
1538#ifdef IFCAP_TSO
1539	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
1540	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
1541#endif /* IFCAP_TSO */
1542#ifdef IFCAP_LRO
1543	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
1544	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
1545#endif /* IFCAP_LRO */
1546#ifdef IFCAP_WOL
1547	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
1548	DEF_CMD("-wol",		-IFCAP_WOL,	setifcap),
1549#endif /* IFCAP_WOL */
1550#ifdef IFCAP_WOL_UCAST
1551	DEF_CMD("wol_ucast",	IFCAP_WOL_UCAST,	setifcap),
1552	DEF_CMD("-wol_ucast",	-IFCAP_WOL_UCAST,	setifcap),
1553#endif /* IFCAP_WOL_UCAST */
1554#ifdef IFCAP_WOL_MCAST
1555	DEF_CMD("wol_mcast",	IFCAP_WOL_MCAST,	setifcap),
1556	DEF_CMD("-wol_mcast",	-IFCAP_WOL_MCAST,	setifcap),
1557#endif /* IFCAP_WOL_MCAST */
1558#ifdef IFCAP_WOL_MAGIC
1559	DEF_CMD("wol_magic",	IFCAP_WOL_MAGIC,	setifcap),
1560	DEF_CMD("-wol_magic",	-IFCAP_WOL_MAGIC,	setifcap),
1561#endif /* IFCAP_WOL_MAGIC */
1562	DEF_CMD("normal",	-IFF_LINK0,	setifflags),
1563	DEF_CMD("compress",	IFF_LINK0,	setifflags),
1564	DEF_CMD("noicmp",	IFF_LINK1,	setifflags),
1565	DEF_CMD_ARG("mtu",			setifmtu),
1566#ifdef notdef
1567	DEF_CMD_ARG("name",			setifname),
1568#endif /* notdef */
1569#ifdef IFCAP_AV
1570	DEF_CMD("av", IFCAP_AV, setifcap),
1571	DEF_CMD("-av", -IFCAP_AV, setifcap),
1572#endif /* IFCAP_AV */
1573	DEF_CMD("router",	1,		setrouter),
1574	DEF_CMD("-router",	0,		setrouter),
1575	DEF_CMD_ARG("desc",			setifdesc),
1576	DEF_CMD_ARG("tbr",			settbr),
1577	DEF_CMD_ARG("throttle",			setthrottle),
1578	DEF_CMD_ARG("log",			setlog),
1579	DEF_CMD("cl2k",	1,			setcl2k),
1580	DEF_CMD("-cl2k",	0,		setcl2k),
1581};
1582
1583static __constructor void
1584ifconfig_ctor(void)
1585{
1586#define	N(a)	(sizeof(a) / sizeof(a[0]))
1587	int i;
1588
1589	for (i = 0; i < N(basic_cmds);  i++)
1590		cmd_register(&basic_cmds[i]);
1591#undef N
1592}
1593
1594static char *
1595sched2str(unsigned int s)
1596{
1597	char *c;
1598
1599	switch (s) {
1600	case PKTSCHEDT_NONE:
1601		c = "NONE";
1602		break;
1603	case PKTSCHEDT_CBQ:
1604		c = "CBQ";
1605		break;
1606	case PKTSCHEDT_HFSC:
1607		c = "HFSC";
1608		break;
1609	case PKTSCHEDT_PRIQ:
1610		c = "PRIQ";
1611		break;
1612	case PKTSCHEDT_FAIRQ:
1613		c = "FAIRQ";
1614		break;
1615	case PKTSCHEDT_TCQ:
1616		c = "TCQ";
1617		break;
1618	case PKTSCHEDT_QFQ:
1619		c = "QFQ";
1620		break;
1621	default:
1622		c = "UNKNOWN";
1623		break;
1624	}
1625
1626	return (c);
1627}
1628
1629static char *
1630tl2str(unsigned int s)
1631{
1632	char *c;
1633
1634	switch (s) {
1635	case IFNET_THROTTLE_OFF:
1636		c = "off";
1637		break;
1638	case IFNET_THROTTLE_OPPORTUNISTIC:
1639		c = "opportunistic";
1640		break;
1641	default:
1642		c = "unknown";
1643		break;
1644	}
1645
1646	return (c);
1647}
1648
1649static char *
1650ift2str(unsigned int t, unsigned int f, unsigned int sf)
1651{
1652	static char buf[256];
1653	char *c = NULL;
1654
1655	switch (t) {
1656	case IFT_ETHER:
1657		switch (sf) {
1658		case IFRTYPE_SUBFAMILY_USB:
1659			c = "USB Ethernet";
1660			break;
1661		case IFRTYPE_SUBFAMILY_BLUETOOTH:
1662			c = "Bluetooth PAN";
1663			break;
1664		case IFRTYPE_SUBFAMILY_WIFI:
1665			c = "Wi-Fi";
1666			break;
1667		case IFRTYPE_SUBFAMILY_THUNDERBOLT:
1668			c = "IP over Thunderbolt";
1669			break;
1670		case IFRTYPE_SUBFAMILY_ANY:
1671		default:
1672			c = "Ethernet";
1673			break;
1674		}
1675		break;
1676
1677	case IFT_IEEE1394:
1678		c = "IP over FireWire";
1679		break;
1680
1681	case IFT_PKTAP:
1682		c = "Packet capture";
1683		break;
1684
1685	case IFT_CELLULAR:
1686		c = "Cellular";
1687		break;
1688
1689	case IFT_BRIDGE:
1690	case IFT_PFLOG:
1691	case IFT_PFSYNC:
1692	case IFT_OTHER:
1693	case IFT_PPP:
1694	case IFT_LOOP:
1695	case IFT_GIF:
1696	case IFT_STF:
1697	case IFT_L2VLAN:
1698	case IFT_IEEE8023ADLAG:
1699	default:
1700		break;
1701	}
1702
1703	if (verbose > 1) {
1704		if (c == NULL) {
1705			(void) snprintf(buf, sizeof (buf),
1706			    "0x%x family: %u subfamily: %u",
1707			    ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
1708			    ifr.ifr_type.ift_subfamily);
1709		} else {
1710			(void) snprintf(buf, sizeof (buf),
1711			    "%s (0x%x) family: %u subfamily: %u", c,
1712			    ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
1713			    ifr.ifr_type.ift_subfamily);
1714		}
1715		c = buf;
1716	}
1717
1718	return (c);
1719}
1720