]> git.saurik.com Git - apple/network_cmds.git/blame_incremental - ifconfig.tproj/ifconfig.c
network_cmds-606.100.3.tar.gz
[apple/network_cmds.git] / ifconfig.tproj / ifconfig.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2009-2019 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#include <net/network_agent.h>
85
86/* IP */
87#include <netinet/in.h>
88#include <netinet/in_var.h>
89#include <arpa/inet.h>
90#include <netdb.h>
91
92#include <ifaddrs.h>
93#include <ctype.h>
94#include <err.h>
95#include <errno.h>
96#include <fcntl.h>
97#include <math.h>
98#include <stdio.h>
99#include <stdlib.h>
100#include <string.h>
101#include <strings.h>
102#include <unistd.h>
103#include <sysexits.h>
104#include <syslog.h>
105
106#include "ifconfig.h"
107
108#ifdef __APPLE__
109#include <TargetConditionals.h>
110#endif
111
112/*
113 * Since "struct ifreq" is composed of various union members, callers
114 * should pay special attention to interprete the value.
115 * (.e.g. little/big endian difference in the structure.)
116 */
117struct ifreq ifr;
118
119char name[IFNAMSIZ];
120int setaddr;
121int setmask;
122int doalias;
123int clearaddr;
124int newaddr = 1;
125int noload;
126int all;
127
128int bond_details = 0;
129int supmedia = 0;
130#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
131int verbose = 1;
132int showrtref = 1;
133#else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
134int verbose = 0;
135int showrtref = 0;
136#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
137int printkeys = 0; /* Print keying material for interfaces. */
138
139static int ifconfig(int argc, char *const *argv, int iscreate,
140 const struct afswtch *afp);
141static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
142 struct ifaddrs *ifa);
143static char *bytes_to_str(unsigned long long bytes);
144static char *bps_to_str(unsigned long long rate);
145static char *ns_to_str(unsigned long long nsec);
146static void tunnel_status(int s);
147static void clat46_addr(int s, char *name);
148static void nat64_status(int s, char *name);
149static void usage(void);
150static char *sched2str(unsigned int s);
151static char *tl2str(unsigned int s);
152static char *ift2str(unsigned int t, unsigned int f, unsigned int sf);
153static char *iffunct2str(u_int32_t functional_type);
154
155static struct afswtch *af_getbyname(const char *name);
156static struct afswtch *af_getbyfamily(int af);
157static void af_other_status(int);
158
159static struct option *opts = NULL;
160
161void
162opt_register(struct option *p)
163{
164 p->next = opts;
165 opts = p;
166}
167
168static void
169usage(void)
170{
171 char options[1024];
172 struct option *p;
173
174 /* XXX not right but close enough for now */
175 options[0] = '\0';
176 for (p = opts; p != NULL; p = p->next) {
177 strlcat(options, p->opt_usage, sizeof(options));
178 strlcat(options, " ", sizeof(options));
179 }
180
181 fprintf(stderr,
182 "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
183 " [parameters]\n"
184 " ifconfig interface create\n"
185 " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
186 " ifconfig -l [-d] [-u] [address_family]\n"
187 " ifconfig %s[-d] [-m] [-u] [-v]\n",
188 options, options, options);
189 exit(1);
190}
191
192int
193main(int argc, char *argv[])
194{
195 int c, namesonly, downonly, uponly;
196 const struct afswtch *afp = NULL;
197 int ifindex;
198 struct ifaddrs *ifap, *ifa;
199 struct ifreq paifr;
200 const struct sockaddr_dl *sdl;
201 char options[1024], *cp;
202 const char *ifname;
203 struct option *p;
204 size_t iflen;
205
206 all = downonly = uponly = namesonly = noload = 0;
207
208 /* Parse leading line options */
209#ifndef __APPLE__
210 strlcpy(options, "adklmnuv", sizeof(options));
211#else
212 strlcpy(options, "abdlmruv", sizeof(options));
213#endif
214 for (p = opts; p != NULL; p = p->next)
215 strlcat(options, p->opt, sizeof(options));
216 while ((c = getopt(argc, argv, options)) != -1) {
217 switch (c) {
218 case 'a': /* scan all interfaces */
219 all++;
220 break;
221 case 'b': /* bond detailed output */
222 bond_details++;
223 break;
224 case 'd': /* restrict scan to "down" interfaces */
225 downonly++;
226 break;
227#ifndef __APPLE__
228 case 'k':
229 printkeys++;
230 break;
231#endif
232 case 'l': /* scan interface names only */
233 namesonly++;
234 break;
235 case 'm': /* show media choices in status */
236 supmedia = 1;
237 break;
238#ifndef __APPLE__
239 case 'n': /* suppress module loading */
240 noload++;
241 break;
242#endif
243 case 'r':
244 showrtref++;
245 break;
246 case 'u': /* restrict scan to "up" interfaces */
247 uponly++;
248 break;
249 case 'v':
250 verbose++;
251 break;
252 default:
253 for (p = opts; p != NULL; p = p->next)
254 if (p->opt[0] == c) {
255 p->cb(optarg);
256 break;
257 }
258 if (p == NULL)
259 usage();
260 break;
261 }
262 }
263 argc -= optind;
264 argv += optind;
265
266 /* -l cannot be used with -a or -q or -m or -b */
267 if (namesonly &&
268 (all || supmedia || bond_details))
269 usage();
270
271 /* nonsense.. */
272 if (uponly && downonly)
273 usage();
274
275 /* no arguments is equivalent to '-a' */
276 if (!namesonly && argc < 1)
277 all = 1;
278
279 /* -a and -l allow an address family arg to limit the output */
280 if (all || namesonly) {
281 if (argc > 1)
282 usage();
283
284 ifname = NULL;
285 if (argc == 1) {
286 afp = af_getbyname(*argv);
287 if (afp == NULL)
288 usage();
289 if (afp->af_name != NULL)
290 argc--, argv++;
291 /* leave with afp non-zero */
292 }
293 } else {
294 /* not listing, need an argument */
295 if (argc < 1)
296 usage();
297
298 ifname = *argv;
299 argc--, argv++;
300
301#ifdef notdef
302 /* check and maybe load support for this interface */
303 ifmaybeload(ifname);
304#endif
305 ifindex = if_nametoindex(ifname);
306 if (ifindex == 0) {
307 /*
308 * NOTE: We must special-case the `create' command
309 * right here as we would otherwise fail when trying
310 * to find the interface.
311 */
312 if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
313 strcmp(argv[0], "plumb") == 0)) {
314 iflen = strlcpy(name, ifname, sizeof(name));
315 if (iflen >= sizeof(name))
316 errx(1, "%s: cloning name too long",
317 ifname);
318 ifconfig(argc, argv, 1, NULL);
319 exit(0);
320 }
321 errx(1, "interface %s does not exist", ifname);
322 }
323 }
324
325 /* Check for address family */
326 if (argc > 0) {
327 afp = af_getbyname(*argv);
328 if (afp != NULL)
329 argc--, argv++;
330 }
331
332 if (getifaddrs(&ifap) != 0)
333 err(EXIT_FAILURE, "getifaddrs");
334 cp = NULL;
335 ifindex = 0;
336 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
337 memset(&paifr, 0, sizeof(paifr));
338 strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
339 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
340 memcpy(&paifr.ifr_addr, ifa->ifa_addr,
341 ifa->ifa_addr->sa_len);
342 }
343
344 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
345 continue;
346 if (ifa->ifa_addr->sa_family == AF_LINK)
347 sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
348 else
349 sdl = NULL;
350 if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
351 continue;
352 iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
353 if (iflen >= sizeof(name)) {
354 warnx("%s: interface name too long, skipping",
355 ifa->ifa_name);
356 continue;
357 }
358 cp = ifa->ifa_name;
359
360 if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
361 continue;
362 if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
363 continue;
364 ifindex++;
365 /*
366 * Are we just listing the interfaces?
367 */
368 if (namesonly) {
369 if (ifindex > 1)
370 printf(" ");
371 fputs(name, stdout);
372 continue;
373 }
374
375 if (argc > 0)
376 ifconfig(argc, argv, 0, afp);
377 else
378 status(afp, sdl, ifa);
379 }
380 if (namesonly)
381 printf("\n");
382 freeifaddrs(ifap);
383
384 exit(0);
385}
386
387static struct afswtch *afs = NULL;
388
389void
390af_register(struct afswtch *p)
391{
392 p->af_next = afs;
393 afs = p;
394}
395
396static struct afswtch *
397af_getbyname(const char *name)
398{
399 struct afswtch *afp;
400
401 for (afp = afs; afp != NULL; afp = afp->af_next)
402 if (strcmp(afp->af_name, name) == 0)
403 return afp;
404 return NULL;
405}
406
407static struct afswtch *
408af_getbyfamily(int af)
409{
410 struct afswtch *afp;
411
412 for (afp = afs; afp != NULL; afp = afp->af_next)
413 if (afp->af_af == af)
414 return afp;
415 return NULL;
416}
417
418static void
419af_other_status(int s)
420{
421 struct afswtch *afp;
422 uint8_t afmask[howmany(AF_MAX, NBBY)];
423
424 memset(afmask, 0, sizeof(afmask));
425 for (afp = afs; afp != NULL; afp = afp->af_next) {
426 if (afp->af_other_status == NULL)
427 continue;
428 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
429 continue;
430 afp->af_other_status(s);
431 setbit(afmask, afp->af_af);
432 }
433}
434
435static void
436af_all_tunnel_status(int s)
437{
438 struct afswtch *afp;
439 uint8_t afmask[howmany(AF_MAX, NBBY)];
440
441 memset(afmask, 0, sizeof(afmask));
442 for (afp = afs; afp != NULL; afp = afp->af_next) {
443 if (afp->af_status_tunnel == NULL)
444 continue;
445 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
446 continue;
447 afp->af_status_tunnel(s);
448 setbit(afmask, afp->af_af);
449 }
450}
451
452static struct cmd *cmds = NULL;
453
454void
455cmd_register(struct cmd *p)
456{
457 p->c_next = cmds;
458 cmds = p;
459}
460
461static const struct cmd *
462cmd_lookup(const char *name)
463{
464#define N(a) (sizeof(a)/sizeof(a[0]))
465 const struct cmd *p;
466
467 for (p = cmds; p != NULL; p = p->c_next)
468 if (strcmp(name, p->c_name) == 0)
469 return p;
470 return NULL;
471#undef N
472}
473
474struct callback {
475 callback_func *cb_func;
476 void *cb_arg;
477 struct callback *cb_next;
478};
479static struct callback *callbacks = NULL;
480
481void
482callback_register(callback_func *func, void *arg)
483{
484 struct callback *cb;
485
486 cb = malloc(sizeof(struct callback));
487 if (cb == NULL)
488 errx(1, "unable to allocate memory for callback");
489 cb->cb_func = func;
490 cb->cb_arg = arg;
491 cb->cb_next = callbacks;
492 callbacks = cb;
493}
494
495/* specially-handled commands */
496static void setifaddr(const char *, int, int, const struct afswtch *);
497static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
498
499static void setifdstaddr(const char *, int, int, const struct afswtch *);
500static const struct cmd setifdstaddr_cmd =
501 DEF_CMD("ifdstaddr", 0, setifdstaddr);
502
503static int
504ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp)
505{
506 const struct afswtch *nafp;
507 struct callback *cb;
508 int ret, s;
509
510 strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
511top:
512 if (afp == NULL)
513 afp = af_getbyname("inet");
514 ifr.ifr_addr.sa_family =
515 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
516 AF_INET : afp->af_af;
517
518 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
519 err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
520
521 while (argc > 0) {
522 const struct cmd *p;
523
524 p = cmd_lookup(*argv);
525 if (p == NULL) {
526 /*
527 * Not a recognized command, choose between setting
528 * the interface address and the dst address.
529 */
530 p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
531 }
532 if (p->c_u.c_func || p->c_u.c_func2) {
533 if (iscreate && !p->c_iscloneop) {
534 /*
535 * Push the clone create callback so the new
536 * device is created and can be used for any
537 * remaining arguments.
538 */
539 cb = callbacks;
540 if (cb == NULL)
541 errx(1, "internal error, no callback");
542 callbacks = cb->cb_next;
543 cb->cb_func(s, cb->cb_arg);
544 iscreate = 0;
545 /*
546 * Handle any address family spec that
547 * immediately follows and potentially
548 * recreate the socket.
549 */
550 nafp = af_getbyname(*argv);
551 if (nafp != NULL) {
552 argc--, argv++;
553 if (nafp != afp) {
554 close(s);
555 afp = nafp;
556 goto top;
557 }
558 }
559 }
560 if (p->c_parameter == NEXTARG) {
561 if (argv[1] == NULL)
562 errx(1, "'%s' requires argument",
563 p->c_name);
564 p->c_u.c_func(argv[1], 0, s, afp);
565 argc--, argv++;
566 } else if (p->c_parameter == OPTARG) {
567 p->c_u.c_func(argv[1], 0, s, afp);
568 if (argv[1] != NULL)
569 argc--, argv++;
570 } else if (p->c_parameter == NEXTARG2) {
571 if (argc < 3)
572 errx(1, "'%s' requires 2 arguments",
573 p->c_name);
574 p->c_u.c_func2(argv[1], argv[2], s, afp);
575 argc -= 2, argv += 2;
576 } else if (p->c_parameter == VAARGS) {
577 ret = p->c_u.c_funcv(argc - 1, argv + 1, s, afp);
578 if (ret < 0)
579 errx(1, "'%s' command error",
580 p->c_name);
581 argc -= ret, argv += ret;
582 } else {
583 p->c_u.c_func(*argv, p->c_parameter, s, afp);
584 }
585 }
586 argc--, argv++;
587 }
588
589 /*
590 * Do any post argument processing required by the address family.
591 */
592 if (afp->af_postproc != NULL)
593 afp->af_postproc(s, afp);
594 /*
595 * Do deferred callbacks registered while processing
596 * command-line arguments.
597 */
598 for (cb = callbacks; cb != NULL; cb = cb->cb_next)
599 cb->cb_func(s, cb->cb_arg);
600 /*
601 * Do deferred operations.
602 */
603 if (clearaddr) {
604 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
605 warnx("interface %s cannot change %s addresses!",
606 name, afp->af_name);
607 clearaddr = 0;
608 }
609 }
610 if (clearaddr) {
611 strlcpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
612 ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
613 if (ret < 0) {
614 if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
615 /* means no previous address for interface */
616 } else
617 Perror("ioctl (SIOCDIFADDR)");
618 }
619 }
620 if (newaddr) {
621 if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
622 warnx("interface %s cannot change %s addresses!",
623 name, afp->af_name);
624 newaddr = 0;
625 }
626 }
627 if (newaddr && (setaddr || setmask)) {
628 strlcpy(afp->af_addreq, name, sizeof ifr.ifr_name);
629 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
630 Perror("ioctl (SIOCAIFADDR)");
631 }
632
633 close(s);
634 return(0);
635}
636
637/*ARGSUSED*/
638static void
639setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
640{
641 if (afp->af_getaddr == NULL)
642 return;
643 /*
644 * Delay the ioctl to set the interface addr until flags are all set.
645 * The address interpretation may depend on the flags,
646 * and the flags may change when the address is set.
647 */
648 setaddr++;
649 if (doalias == 0 && afp->af_af != AF_LINK)
650 clearaddr = 1;
651 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
652}
653
654static void
655settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
656{
657 struct addrinfo *srcres, *dstres;
658 int ecode;
659
660 if (afp->af_settunnel == NULL) {
661 warn("address family %s does not support tunnel setup",
662 afp->af_name);
663 return;
664 }
665
666 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
667 errx(1, "error in parsing address string: %s",
668 gai_strerror(ecode));
669
670 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
671 errx(1, "error in parsing address string: %s",
672 gai_strerror(ecode));
673
674 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
675 errx(1,
676 "source and destination address families do not match");
677
678 afp->af_settunnel(s, srcres, dstres);
679
680 freeaddrinfo(srcres);
681 freeaddrinfo(dstres);
682}
683
684/* ARGSUSED */
685static void
686deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
687{
688
689 if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
690 err(1, "SIOCDIFPHYADDR");
691}
692
693static void
694setifnetmask(const char *addr, int dummy __unused, int s,
695 const struct afswtch *afp)
696{
697 if (afp->af_getaddr != NULL) {
698 setmask++;
699 afp->af_getaddr(addr, MASK);
700 }
701}
702
703static void
704setifbroadaddr(const char *addr, int dummy __unused, int s,
705 const struct afswtch *afp)
706{
707 if (afp->af_getaddr != NULL)
708 afp->af_getaddr(addr, DSTADDR);
709}
710
711static void
712setifipdst(const char *addr, int dummy __unused, int s,
713 const struct afswtch *afp)
714{
715 const struct afswtch *inet;
716
717 inet = af_getbyname("inet");
718 if (inet == NULL)
719 return;
720 inet->af_getaddr(addr, DSTADDR);
721 clearaddr = 0;
722 newaddr = 0;
723}
724
725static void
726notealias(const char *addr, int param, int s, const struct afswtch *afp)
727{
728#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
729 if (setaddr && doalias == 0 && param < 0)
730 if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
731 bcopy((caddr_t)rqtosa(af_addreq),
732 (caddr_t)rqtosa(af_ridreq),
733 rqtosa(af_addreq)->sa_len);
734 doalias = param;
735 if (param < 0) {
736 clearaddr = 1;
737 newaddr = 0;
738 } else
739 clearaddr = 0;
740#undef rqtosa
741}
742
743/*ARGSUSED*/
744static void
745setifdstaddr(const char *addr, int param __unused, int s,
746 const struct afswtch *afp)
747{
748 if (afp->af_getaddr != NULL)
749 afp->af_getaddr(addr, DSTADDR);
750}
751
752/*
753 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
754 * of the ifreq structure, which may confuse other parts of ifconfig.
755 * Make a private copy so we can avoid that.
756 */
757static void
758setifflags(const char *vname, int value, int s, const struct afswtch *afp)
759{
760 struct ifreq my_ifr;
761 int flags;
762
763 bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
764
765 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
766 Perror("ioctl (SIOCGIFFLAGS)");
767 exit(1);
768 }
769 strlcpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name));
770 flags = my_ifr.ifr_flags;
771
772 if (value < 0) {
773 value = -value;
774 flags &= ~value;
775 } else
776 flags |= value;
777 my_ifr.ifr_flags = flags & 0xffff;
778 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
779 Perror(vname);
780}
781
782void
783setifcap(const char *vname, int value, int s, const struct afswtch *afp)
784{
785 int flags;
786
787 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
788 Perror("ioctl (SIOCGIFCAP)");
789 exit(1);
790 }
791 flags = ifr.ifr_curcap;
792 if (value < 0) {
793 value = -value;
794 flags &= ~value;
795 } else
796 flags |= value;
797 flags &= ifr.ifr_reqcap;
798 ifr.ifr_reqcap = flags;
799 if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
800 Perror(vname);
801}
802
803static void
804setifmetric(const char *val, int dummy __unused, int s,
805 const struct afswtch *afp)
806{
807 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
808 ifr.ifr_metric = atoi(val);
809 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
810 warn("ioctl (set metric)");
811}
812
813static void
814setifmtu(const char *val, int dummy __unused, int s,
815 const struct afswtch *afp)
816{
817 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
818 ifr.ifr_mtu = atoi(val);
819 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
820 warn("ioctl (set mtu)");
821}
822
823#ifndef __APPLE__
824static void
825setifname(const char *val, int dummy __unused, int s,
826 const struct afswtch *afp)
827{
828 char *newname;
829
830 newname = strdup(val);
831 if (newname == NULL) {
832 warn("no memory to set ifname");
833 return;
834 }
835 ifr.ifr_data = newname;
836 if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
837 warn("ioctl (set name)");
838 free(newname);
839 return;
840 }
841 strlcpy(name, newname, sizeof(name));
842 free(newname);
843}
844#endif
845
846static void
847setrouter(const char *vname, int value, int s, const struct afswtch *afp)
848{
849 if (afp->af_setrouter == NULL) {
850 warn("address family %s does not support router mode",
851 afp->af_name);
852 return;
853 }
854
855 afp->af_setrouter(s, value);
856}
857
858static int
859routermode(int argc, char *const *argv, int s, const struct afswtch *afp)
860{
861 return (*afp->af_routermode)(s, argc, argv);
862}
863
864
865static void
866setifdesc(const char *val, int dummy __unused, int s, const struct afswtch *afp)
867{
868 struct if_descreq ifdr;
869
870 bzero(&ifdr, sizeof (ifdr));
871 strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
872 ifdr.ifdr_len = strlen(val);
873 strlcpy((char *)ifdr.ifdr_desc, val, sizeof (ifdr.ifdr_desc));
874
875 if (ioctl(s, SIOCSIFDESC, (caddr_t)&ifdr) < 0) {
876 warn("ioctl (set desc)");
877 }
878}
879
880static void
881settbr(const char *val, int dummy __unused, int s, const struct afswtch *afp)
882{
883 struct if_linkparamsreq iflpr;
884 long double bps;
885 u_int64_t rate;
886 u_int32_t percent = 0;
887 char *cp;
888
889 errno = 0;
890 bzero(&iflpr, sizeof (iflpr));
891 strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
892
893 bps = strtold(val, &cp);
894 if (val == cp || errno != 0) {
895 warn("Invalid value '%s'", val);
896 return;
897 }
898 rate = (u_int64_t)bps;
899 if (cp != NULL) {
900 if (!strcmp(cp, "b") || !strcmp(cp, "bps")) {
901 ; /* nothing */
902 } else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbps")) {
903 rate *= 1000;
904 } else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbps")) {
905 rate *= 1000 * 1000;
906 } else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbps")) {
907 rate *= 1000 * 1000 * 1000;
908 } else if (!strcmp(cp, "%")) {
909 percent = rate;
910 if (percent == 0 || percent > 100) {
911 printf("Value out of range '%s'", val);
912 return;
913 }
914 } else if (*cp != '\0') {
915 printf("Unknown unit '%s'", cp);
916 return;
917 }
918 }
919 iflpr.iflpr_output_tbr_rate = rate;
920 iflpr.iflpr_output_tbr_percent = percent;
921 if (ioctl(s, SIOCSIFLINKPARAMS, &iflpr) < 0 &&
922 errno != ENOENT && errno != ENXIO && errno != ENODEV) {
923 warn("ioctl (set link params)");
924 } else if (errno == ENXIO) {
925 printf("TBR cannot be set on %s\n", name);
926 } else if (errno == 0 && rate == 0) {
927 printf("%s: TBR is now disabled\n", name);
928 } else if (errno == ENODEV) {
929 printf("%s: requires absolute TBR rate\n", name);
930 } else if (percent != 0) {
931 printf("%s: TBR rate set to %u%% of effective link rate\n",
932 name, percent);
933 } else {
934 printf("%s: TBR rate set to %s\n", name, bps_to_str(rate));
935 }
936}
937
938static int
939get_int64(uint64_t *i, char const *s)
940{
941 char *cp;
942 *i = strtol(s, &cp, 10);
943 if (cp == s || errno != 0) {
944 return (-1);
945 }
946 return (0);
947}
948
949static int
950get_int32(uint32_t *i, char const *s)
951{
952 char *cp;
953 *i = strtol(s, &cp, 10);
954 if (cp == s || errno != 0) {
955 return (-1);
956 }
957 return (0);
958}
959
960static int
961get_percent(double *d, const char *s)
962{
963 char *cp;
964 *d = strtod(s, &cp) / (double)100;
965 if (*d == HUGE_VALF || *d == HUGE_VALL) {
966 return (-1);
967 }
968 if (*d == 0.0 || (*cp != '\0' && strcmp(cp, "%") != 0)) {
969 return (-1);
970 }
971 return (0);
972}
973
974static int
975get_percent_fixed_point(uint32_t *i, const char *s)
976{
977 double p;
978
979 if (get_percent(&p, s) != 0){
980 return (-1);
981 }
982
983 *i = p * IF_NETEM_PARAMS_PSCALE;
984 return (0);
985}
986
987static int
988netem_parse_args(struct if_netem_params *p, int argc, char *const *argv)
989{
990 int argc_saved = argc;
991 uint64_t bandwitdh = 0;
992 uint32_t latency = 0, jitter = 0;
993 uint32_t corruption = 0;
994 uint32_t duplication = 0;
995 uint32_t loss_p_gr_gl = 0, loss_p_gr_bl = 0, loss_p_bl_br = 0,
996 loss_p_bl_gr = 0, loss_p_br_bl = 0;
997 uint32_t reordering = 0;
998
999 bzero(p, sizeof (*p));
1000
1001 /* take out "input"/"output" */
1002 argc--, argv++;
1003
1004 for ( ; argc > 0; ) {
1005 if (strcmp(*argv, "bandwidth") == 0) {
1006 argc--, argv++;
1007 if (argc <= 0 || get_int64(&bandwitdh, *argv) != 0) {
1008 err(1, "Invalid value '%s'", *argv);
1009 }
1010 argc--, argv++;
1011 } else if (strcmp(*argv, "corruption") == 0) {
1012 argc--, argv++;
1013 if (argc <= 0 ||
1014 get_percent_fixed_point(&corruption, *argv) != 0) {
1015 err(1, "Invalid value '%s'", *argv);
1016 }
1017 argc--, argv++;
1018 } else if (strcmp(*argv, "delay") == 0) {
1019 argc--, argv++;
1020 if (argc <= 0 || get_int32(&latency, *argv) != 0) {
1021 err(1, "Invalid value '%s'", *argv);
1022 }
1023 argc--, argv++;
1024 if (argc > 0 && get_int32(&jitter, *argv) == 0) {
1025 argc--, argv++;
1026 }
1027 } else if (strcmp(*argv, "duplication") == 0) {
1028 argc--, argv++;
1029 if (argc <= 0 ||
1030 get_percent_fixed_point(&duplication, *argv) != 0) {
1031 err(1, "Invalid value '%s'", *argv);
1032 return (-1);
1033 }
1034 argc--, argv++;
1035 } else if (strcmp(*argv, "loss") == 0) {
1036 argc--, argv++;
1037 if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_gl, *argv) != 0) {
1038 err(1, "Invalid value '%s'", *argv);
1039 }
1040 /* we may have all 5 probs, use naive model if not */
1041 argc--, argv++;
1042 if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_bl, *argv) != 0) {
1043 continue;
1044 }
1045 /* if more than p_gr_gl, then should have all probs */
1046 argc--, argv++;
1047 if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_br, *argv) != 0) {
1048 err(1, "Invalid value '%s' for p_bl_br", *argv);
1049 }
1050 argc--, argv++;
1051 if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_gr, *argv) != 0) {
1052 err(1, "Invalid value '%s' for p_bl_gr", *argv);
1053 }
1054 argc--, argv++;
1055 if (argc <= 0 || get_percent_fixed_point(&loss_p_br_bl, *argv) != 0) {
1056 err(1, "Invalid value '%s' for p_br_bl", *argv);
1057 }
1058 argc--, argv++;
1059 } else if (strcmp(*argv, "reordering") == 0) {
1060 argc--, argv++;
1061 if (argc <= 0 || get_percent_fixed_point(&reordering, *argv) != 0) {
1062 err(1, "Invalid value '%s'", *argv);
1063 }
1064 argc--, argv++;
1065 } else {
1066 return (-1);
1067 }
1068 }
1069
1070 if (corruption > IF_NETEM_PARAMS_PSCALE) {
1071 err(1, "corruption percentage > 100%%");
1072 }
1073
1074 if (duplication > IF_NETEM_PARAMS_PSCALE) {
1075 err(1, "duplication percentage > 100%%");
1076 }
1077
1078 if (duplication > 0 && latency == 0) {
1079 /* we need to insert dup'ed packet with latency */
1080 err(1, "duplication needs latency param");
1081 }
1082
1083 if (latency > 1000) {
1084 err(1, "latency %dms too big (> 1 sec)", latency);
1085 }
1086
1087 if (jitter * 3 > latency) {
1088 err(1, "jitter %dms too big (latency %dms)", jitter, latency);
1089 }
1090
1091 /* if gr_gl == 0 (no loss), other prob should all be zero */
1092 if (loss_p_gr_gl == 0 &&
1093 (loss_p_gr_bl != 0 || loss_p_bl_br != 0 || loss_p_bl_gr != 0 ||
1094 loss_p_br_bl != 0)) {
1095 err(1, "loss params not all zero when gr_gl is zero");
1096 }
1097
1098 /* check state machine transition prob integrity */
1099 if (loss_p_gr_gl > IF_NETEM_PARAMS_PSCALE ||
1100 /* gr_gl = IF_NETEM_PARAMS_PSCALE for total loss */
1101 loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
1102 loss_p_bl_br > IF_NETEM_PARAMS_PSCALE ||
1103 loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE ||
1104 loss_p_br_bl > IF_NETEM_PARAMS_PSCALE ||
1105 loss_p_gr_gl + loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
1106 loss_p_bl_br + loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE) {
1107 err(1, "loss params too big");
1108 }
1109
1110 if (reordering > IF_NETEM_PARAMS_PSCALE) {
1111 err(1, "reordering percentage > 100%%");
1112 }
1113
1114 p->ifnetem_bandwidth_bps = bandwitdh;
1115 p->ifnetem_latency_ms = latency;
1116 p->ifnetem_jitter_ms = jitter;
1117 p->ifnetem_corruption_p = corruption;
1118 p->ifnetem_duplication_p = duplication;
1119 p->ifnetem_loss_p_gr_gl = loss_p_gr_gl;
1120 p->ifnetem_loss_p_gr_bl = loss_p_gr_bl;
1121 p->ifnetem_loss_p_bl_br = loss_p_bl_br;
1122 p->ifnetem_loss_p_bl_gr = loss_p_bl_gr;
1123 p->ifnetem_loss_p_br_bl = loss_p_br_bl;
1124 p->ifnetem_reordering_p = reordering;
1125
1126 return (argc_saved - argc);
1127}
1128
1129void
1130print_netem_params(struct if_netem_params *p, const char *desc)
1131{
1132 struct if_netem_params zero_params;
1133 double pscale = IF_NETEM_PARAMS_PSCALE / 100;
1134 bzero(&zero_params, sizeof (zero_params));
1135
1136 if (memcmp(p, &zero_params, sizeof (zero_params)) == 0) {
1137 printf("%s NetEm Disabled\n\n", desc);
1138 } else {
1139 printf(
1140 "%s NetEm Parameters\n"
1141 "\tbandwidth rate %llubps\n"
1142 "\tdelay latency %dms\n"
1143 "\t jitter %dms\n",
1144 desc, p->ifnetem_bandwidth_bps,
1145 p->ifnetem_latency_ms, p->ifnetem_jitter_ms);
1146 if (p->ifnetem_loss_p_gr_bl == 0 &&
1147 p->ifnetem_loss_p_bl_br == 0 &&
1148 p->ifnetem_loss_p_bl_gr == 0 &&
1149 p->ifnetem_loss_p_br_bl == 0) {
1150 printf(
1151 "\tloss %.3f%%\n",
1152 (double) p->ifnetem_loss_p_gr_gl / pscale);
1153 } else {
1154 printf(
1155 "\tloss GAP_RECV -> GAP_LOSS %.3f%%\n"
1156 "\t GAP_RECV -> BURST_LOSS %.3f%%\n"
1157 "\t BURST_LOSS -> BURST_RECV %.3f%%\n"
1158 "\t BURST_LOSS -> GAP_RECV %.3f%%\n"
1159 "\t BURST_RECV -> BURST_LOSS %.3f%%\n",
1160 (double) p->ifnetem_loss_p_gr_gl / pscale,
1161 (double) p->ifnetem_loss_p_gr_bl / pscale,
1162 (double) p->ifnetem_loss_p_bl_br / pscale,
1163 (double) p->ifnetem_loss_p_bl_gr / pscale,
1164 (double) p->ifnetem_loss_p_br_bl / pscale);
1165 }
1166 printf(
1167 "\tcorruption %.3f%%\n"
1168 "\treordering %.3f%%\n\n",
1169 (double) p->ifnetem_corruption_p / pscale,
1170 (double) p->ifnetem_reordering_p / pscale);
1171 }
1172}
1173
1174static int
1175setnetem(int argc, char *const *argv, int s, const struct afswtch *afp)
1176{
1177 struct if_linkparamsreq iflpr;
1178 struct if_netem_params input_params, output_params;
1179 int ret = 0, error = 0;
1180
1181 bzero(&iflpr, sizeof (iflpr));
1182 bzero(&input_params, sizeof (input_params));
1183 bzero(&output_params, sizeof (output_params));
1184
1185 if (argc > 1) {
1186 if (strcmp(argv[0], "input") == 0) {
1187 ret = netem_parse_args(&input_params, argc, argv);
1188 } else if (strcmp(argv[0], "output") == 0) {
1189 ret = netem_parse_args(&output_params, argc, argv);
1190 } else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
1191 goto bad_args;
1192 } else {
1193 fprintf(stderr, "uknown option %s\n", argv[0]);
1194 goto bad_args;
1195 }
1196 if (ret < 0) {
1197 goto bad_args;
1198 }
1199 }
1200
1201 errno = 0;
1202 strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
1203 error = ioctl(s, SIOCGIFLINKPARAMS, &iflpr);
1204 if (error < 0) {
1205 warn("ioctl (get link params)");
1206 }
1207
1208 if (argc == 0) {
1209 print_netem_params(&iflpr.iflpr_input_netem, "Input");
1210 print_netem_params(&iflpr.iflpr_output_netem, "Output");
1211 return (0);
1212 } else if (argc == 1) {
1213 if (strcmp(argv[0], "input") == 0) {
1214 bzero(&iflpr.iflpr_input_netem,
1215 sizeof (iflpr.iflpr_input_netem));
1216 } else if (strcmp(argv[0], "output") == 0) {
1217 bzero(&iflpr.iflpr_output_netem,
1218 sizeof (iflpr.iflpr_output_netem));
1219 } else {
1220 fprintf(stderr, "uknown option %s\n", argv[0]);
1221 goto bad_args;
1222 }
1223 printf("%s: netem is now disabled for %s\n", name, argv[0]);
1224 ret = 1;
1225 } else {
1226 if (strcmp(argv[0], "input") == 0) {
1227 iflpr.iflpr_input_netem = input_params;
1228 } else if (strcmp(argv[0], "output") == 0) {
1229 iflpr.iflpr_output_netem = output_params;
1230 }
1231 }
1232
1233 error = ioctl(s, SIOCSIFLINKPARAMS, &iflpr);
1234 if (error < 0 && errno != ENOENT && errno != ENXIO && errno != ENODEV) {
1235 warn("ioctl (set link params)");
1236 } else if (errno == ENXIO) {
1237 printf("netem cannot be set on %s\n", name);
1238 } else {
1239 printf("%s: netem configured\n", name);
1240 }
1241
1242 return (ret);
1243bad_args:
1244 fprintf(stderr, "Usage:\n"
1245 "\tTo enable/set netem params\n"
1246 "\t\tnetem <input|output>\n"
1247 "\t\t [ bandwidth BIT_PER_SEC ]\n"
1248 "\t\t [ delay DELAY_MSEC [ JITTER_MSEC ] ]\n"
1249 "\t\t [ loss PERCENTAGE ]\n"
1250 "\t\t [ duplication PERCENTAGE ]\n"
1251 "\t\t [ reordering PERCENTAGE ]\n\n"
1252 "\tTo disable <input|output> netem\n"
1253 "\t\tnetem <input|output>\n\n"
1254 "\tTo show current settings\n"
1255 "\t\tnetem\n\n");
1256 return (-1);
1257}
1258
1259static void
1260setthrottle(const char *val, int dummy __unused, int s,
1261 const struct afswtch *afp)
1262{
1263 struct if_throttlereq iftr;
1264 char *cp;
1265
1266 errno = 0;
1267 bzero(&iftr, sizeof (iftr));
1268 strlcpy(iftr.ifthr_name, name, sizeof (iftr.ifthr_name));
1269
1270 iftr.ifthr_level = strtold(val, &cp);
1271 if (val == cp || errno != 0) {
1272 warn("Invalid value '%s'", val);
1273 return;
1274 }
1275
1276 if (ioctl(s, SIOCSIFTHROTTLE, &iftr) < 0 && errno != ENXIO) {
1277 warn("ioctl (set throttling level)");
1278 } else if (errno == ENXIO) {
1279 printf("throttling level cannot be set on %s\n", name);
1280 } else {
1281 printf("%s: throttling level set to %d\n", name,
1282 iftr.ifthr_level);
1283 }
1284}
1285
1286static void
1287setdisableoutput(const char *val, int dummy __unused, int s,
1288 const struct afswtch *afp)
1289{
1290 struct ifreq ifr;
1291 char *cp;
1292 errno = 0;
1293 bzero(&ifr, sizeof (ifr));
1294 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1295
1296 ifr.ifr_ifru.ifru_disable_output = strtold(val, &cp);
1297 if (val == cp || errno != 0) {
1298 warn("Invalid value '%s'", val);
1299 return;
1300 }
1301
1302 if (ioctl(s, SIOCSIFDISABLEOUTPUT, &ifr) < 0 && errno != ENXIO) {
1303 warn("ioctl set disable output");
1304 } else if (errno == ENXIO) {
1305 printf("output thread can not be disabled on %s\n", name);
1306 } else {
1307 printf("output %s on %s\n",
1308 ((ifr.ifr_ifru.ifru_disable_output == 0) ? "enabled" : "disabled"),
1309 name);
1310 }
1311}
1312
1313static void
1314setlog(const char *val, int dummy __unused, int s,
1315 const struct afswtch *afp)
1316{
1317 char *cp;
1318
1319 errno = 0;
1320 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1321
1322 ifr.ifr_log.ifl_level = strtold(val, &cp);
1323 if (val == cp || errno != 0) {
1324 warn("Invalid value '%s'", val);
1325 return;
1326 }
1327 ifr.ifr_log.ifl_flags = (IFRLOGF_DLIL|IFRLOGF_FAMILY|IFRLOGF_DRIVER|
1328 IFRLOGF_FIRMWARE);
1329
1330 if (ioctl(s, SIOCSIFLOG, &ifr) < 0)
1331 warn("ioctl (set logging parameters)");
1332}
1333
1334void
1335setcl2k(const char *vname, int value, int s, const struct afswtch *afp)
1336{
1337 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1338 ifr.ifr_ifru.ifru_2kcl = value;
1339
1340 if (ioctl(s, SIOCSIF2KCL, (caddr_t)&ifr) < 0)
1341 Perror(vname);
1342}
1343
1344void
1345setexpensive(const char *vname, int value, int s, const struct afswtch *afp)
1346{
1347 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1348 ifr.ifr_ifru.ifru_expensive = value;
1349
1350 if (ioctl(s, SIOCSIFEXPENSIVE, (caddr_t)&ifr) < 0)
1351 Perror(vname);
1352}
1353
1354#ifdef SIOCSIFCONSTRAINED
1355void
1356setconstrained(const char *vname, int value, int s, const struct afswtch *afp)
1357{
1358 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1359 ifr.ifr_ifru.ifru_constrained = value;
1360
1361 if (ioctl(s, SIOCSIFCONSTRAINED, (caddr_t)&ifr) < 0)
1362 Perror(vname);
1363}
1364#endif
1365
1366static void
1367setifmpklog(const char *vname, int value, int s, const struct afswtch *afp)
1368{
1369 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1370 ifr.ifr_ifru.ifru_mpk_log = value;
1371
1372 if (ioctl(s, SIOCSIFMPKLOG, (caddr_t)&ifr) < 0)
1373 Perror(vname);
1374}
1375
1376void
1377settimestamp(const char *vname, int value, int s, const struct afswtch *afp)
1378{
1379 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1380
1381 if (value == 0) {
1382 if (ioctl(s, SIOCSIFTIMESTAMPDISABLE, (caddr_t)&ifr) < 0)
1383 Perror(vname);
1384 } else {
1385 if (ioctl(s, SIOCSIFTIMESTAMPENABLE, (caddr_t)&ifr) < 0)
1386 Perror(vname);
1387 }
1388}
1389
1390void
1391setecnmode(const char *val, int dummy __unused, int s,
1392 const struct afswtch *afp)
1393{
1394 char *cp;
1395
1396 if (strcmp(val, "default") == 0)
1397 ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DEFAULT;
1398 else if (strcmp(val, "enable") == 0)
1399 ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_ENABLE;
1400 else if (strcmp(val, "disable") == 0)
1401 ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DISABLE;
1402 else {
1403 ifr.ifr_ifru.ifru_ecn_mode = strtold(val, &cp);
1404 if (val == cp || errno != 0) {
1405 warn("Invalid ECN mode value '%s'", val);
1406 return;
1407 }
1408 }
1409
1410 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1411
1412 if (ioctl(s, SIOCSECNMODE, (caddr_t)&ifr) < 0)
1413 Perror("ioctl(SIOCSECNMODE)");
1414}
1415
1416void
1417setprobeconnectivity(const char *vname, int value, int s, const struct afswtch *afp)
1418{
1419 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1420 ifr.ifr_ifru.ifru_probe_connectivity = value;
1421
1422 if (ioctl(s, SIOCSIFPROBECONNECTIVITY, (caddr_t)&ifr) < 0)
1423 Perror(vname);
1424}
1425
1426#if defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED)
1427
1428void
1429setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1430{
1431 u_long ioc;
1432
1433#if (DEBUG | DEVELOPMENT)
1434 printf("%s(%s, %s)\n", __func__, cmd, arg);
1435#endif /* (DEBUG | DEVELOPMENT) */
1436
1437 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1438
1439 if (strcmp(cmd, "mode") == 0) {
1440 ioc = SIOCSQOSMARKINGMODE;
1441
1442 if (strcmp(arg, "fastlane") == 0)
1443 ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE;
1444 else if (strcmp(arg, "rfc4594") == 0)
1445 ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_RFC4594;
1446 else if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "off") == 0)
1447 ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
1448 else
1449 err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
1450 } else if (strcmp(cmd, "enabled") == 0) {
1451 ioc = SIOCSQOSMARKINGENABLED;
1452 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1453 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1454 ifr.ifr_qosmarking_enabled = 1;
1455 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1456 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1457 ifr.ifr_qosmarking_enabled = 0;
1458 else
1459 err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
1460 } else {
1461 err(EX_USAGE, "qosmarking takes mode or enabled");
1462 }
1463
1464 if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
1465 err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
1466}
1467
1468void
1469setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1470{
1471 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1472
1473 warnx("### fastlane is obsolete, use qosmarking ###");
1474
1475 if (strcmp(cmd, "capable") == 0) {
1476 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1477 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1478 setqosmarking("mode", "fastlane", s, afp);
1479 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1480 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1481 setqosmarking("mode", "off", s, afp);
1482 else
1483 err(EX_USAGE, "bad value for fastlane %s", cmd);
1484 } else if (strcmp(cmd, "enable") == 0) {
1485 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1486 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1487 setqosmarking("enabled", "1", s, afp);
1488 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1489 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1490 setqosmarking("enabled", "0", s, afp);
1491 else
1492 err(EX_USAGE, "bad value for fastlane %s", cmd);
1493 } else {
1494 err(EX_USAGE, "fastlane takes capable or enable");
1495 }
1496}
1497
1498#else /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
1499
1500void
1501setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1502{
1503 int value;
1504 u_long ioc;
1505
1506 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1507
1508 if (strcmp(cmd, "capable") == 0)
1509 ioc = SIOCSFASTLANECAPABLE;
1510 else if (strcmp(cmd, "enable") == 0)
1511 ioc = SIOCSFASTLEENABLED;
1512 else
1513 err(EX_USAGE, "fastlane takes capable or enabled");
1514
1515 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1516 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1517 value = 1;
1518 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1519 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1520 value = 0;
1521 else
1522 err(EX_USAGE, "bad value for fastlane %s", cmd);
1523
1524 if (ioc == SIOCSFASTLANECAPABLE)
1525 ifr.ifr_fastlane_capable = value;
1526 else
1527 ifr.ifr_fastlane_enabled = value;
1528
1529 if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
1530 err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
1531}
1532
1533
1534void
1535setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1536{
1537 if (strcmp(cmd, "mode") == 0) {
1538 if (strcmp(arg, "fastlane") == 0)
1539 setfastlane("capable", "on", s, afp);
1540 else if (strcmp(arg, "none") == 0)
1541 setfastlane("capable", "off", s, afp);
1542 else
1543 err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
1544 } else if (strcmp(cmd, "enabled") == 0) {
1545 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1546 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1547 setfastlane("enable", "on", s, afp);
1548 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1549 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1550 setfastlane("enable", "off", s, afp);
1551 else
1552 err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
1553 } else {
1554 err(EX_USAGE, "qosmarking takes mode or enabled");
1555 }
1556}
1557
1558#endif /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
1559
1560void
1561setlowpowermode(const char *vname, int value, int s, const struct afswtch *afp)
1562{
1563 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1564 ifr.ifr_low_power_mode = !!value;
1565
1566 if (ioctl(s, SIOCSIFLOWPOWER, (caddr_t)&ifr) < 0)
1567 Perror(vname);
1568}
1569
1570struct str2num {
1571 const char *str;
1572 uint32_t num;
1573};
1574
1575static struct str2num subfamily_str2num[] = {
1576 { .str = "any", .num = IFRTYPE_SUBFAMILY_ANY },
1577 { .str = "USB", .num = IFRTYPE_SUBFAMILY_USB },
1578 { .str = "Bluetooth", .num = IFRTYPE_SUBFAMILY_BLUETOOTH },
1579 { .str = "Wi-Fi", .num = IFRTYPE_SUBFAMILY_WIFI },
1580 { .str = "wifi", .num = IFRTYPE_SUBFAMILY_WIFI },
1581 { .str = "Thunderbolt", .num = IFRTYPE_SUBFAMILY_THUNDERBOLT },
1582 { .str = "reserverd", .num = IFRTYPE_SUBFAMILY_RESERVED },
1583 { .str = "intcoproc", .num = IFRTYPE_SUBFAMILY_INTCOPROC },
1584 { .str = "QuickRelay", .num = IFRTYPE_SUBFAMILY_QUICKRELAY },
1585 { .str = "Default", .num = IFRTYPE_SUBFAMILY_DEFAULT },
1586 { .str = NULL, .num = 0 },
1587};
1588
1589static uint32_t
1590get_num_from_str(struct str2num* str2nums, const char *str)
1591{
1592 struct str2num *str2num = str2nums;
1593
1594 while (str2num != NULL && str2num->str != NULL) {
1595 if (strcasecmp(str2num->str, str) == 0) {
1596 return str2num->num;
1597 }
1598 str2num++;
1599 }
1600 return 0;
1601}
1602
1603static void
1604setifsubfamily(const char *val, int dummy __unused, int s,
1605 const struct afswtch *afp)
1606{
1607 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1608
1609 char *endptr;
1610 uint32_t subfamily = strtoul(val, &endptr, 0);
1611 if (*endptr != 0) {
1612 subfamily = get_num_from_str(subfamily_str2num, val);
1613 if (subfamily == 0) {
1614 return;
1615 }
1616 }
1617
1618 ifr.ifr_type.ift_subfamily = subfamily;
1619 if (ioctl(s, SIOCSIFSUBFAMILY, (caddr_t)&ifr) < 0)
1620 warn("ioctl(SIOCSIFSUBFAMILY)");
1621}
1622
1623void
1624setifavailability(const char *vname, int value, int s, const struct afswtch *afp)
1625{
1626 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1627 ifr.ifr_interface_state.valid_bitmask = IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID;
1628 if (value == 0) {
1629 ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE;
1630 } else {
1631 ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_AVAILABLE;
1632 }
1633 if (ioctl(s, SIOCSIFINTERFACESTATE, (caddr_t)&ifr) < 0)
1634 warn("ioctl(SIOCSIFINTERFACESTATE)");
1635}
1636
1637static void
1638show_routermode(int s)
1639{
1640 struct afswtch *afp;
1641
1642 afp = af_getbyname("inet");
1643 if (afp != NULL) {
1644 (*afp->af_routermode)(s, 0, NULL);
1645 }
1646}
1647
1648static void
1649show_routermode6(void)
1650{
1651 struct afswtch *afp;
1652 static int s = -1;
1653
1654 afp = af_getbyname("inet6");
1655 if (afp != NULL) {
1656 if (s < 0) {
1657 s = socket(AF_INET6, SOCK_DGRAM, 0);
1658 if (s < 0) {
1659 perror("socket");
1660 return;
1661 }
1662 }
1663 (*afp->af_routermode)(s, 0, NULL);
1664 }
1665}
1666
1667#define IFFBITS \
1668"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
1669"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
1670"\20MULTICAST"
1671
1672#define IFEFBITS \
1673"\020\1AUTOCONFIGURING\4PROBE_CONNECTIVITY\5FASTLN_CAP\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \
1674"\12VLAN\13BOND\14ARPLL\15CLAT46\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \
1675"\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \
1676"\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\33CHANNEL_DRV\34CA" \
1677"\35SENDLIST\36DIRECTLINK\37FASTLN_ON\40UPDOWNCHANGE"
1678
1679#define IFXFBITS \
1680"\020\1WOL\2TIMESTAMP\3NOAUTONX\4LEGACY\5TXLOWINET\6RXLOWINET\7ALLOCKPI" \
1681"\10LOWPOWER\11MPKLOG\12CONSTRAINED"
1682
1683#define IFCAPBITS \
1684"\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \
1685"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS\13CHANNEL_IO\14HW_TIMESTAMP\15SW_TIMESTAMP" \
1686"\16PARTIAL_CSUM\17ZEROINVERT_CSUM"
1687
1688#define IFRLOGF_BITS \
1689"\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE"
1690
1691/*
1692 * Print the status of the interface. If an address family was
1693 * specified, show only it; otherwise, show them all.
1694 */
1695static void
1696status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
1697 struct ifaddrs *ifa)
1698{
1699 struct ifaddrs *ift;
1700 int allfamilies, s;
1701 struct ifstat ifs;
1702 struct if_descreq ifdr;
1703 struct if_linkparamsreq iflpr;
1704 int mib[6];
1705 struct ifmibdata_supplemental ifmsupp;
1706 size_t miblen = sizeof(struct ifmibdata_supplemental);
1707 u_int64_t eflags = 0;
1708 u_int64_t xflags = 0;
1709 int curcap = 0;
1710
1711 if (afp == NULL) {
1712 allfamilies = 1;
1713 afp = af_getbyname("inet");
1714 } else
1715 allfamilies = 0;
1716
1717 ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
1718 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1719
1720 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
1721 if (s < 0)
1722 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
1723
1724 printf("%s: ", name);
1725 printb("flags", ifa->ifa_flags, IFFBITS);
1726 if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
1727 if (ifr.ifr_metric)
1728 printf(" metric %d", ifr.ifr_metric);
1729 if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
1730 printf(" mtu %d", ifr.ifr_mtu);
1731 if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1)
1732 printf(" rtref %d", ifr.ifr_route_refcnt);
1733 if (verbose) {
1734 unsigned int ifindex = if_nametoindex(ifa->ifa_name);
1735 if (ifindex != 0)
1736 printf(" index %u", ifindex);
1737 }
1738#ifdef SIOCGIFCONSTRAINED
1739 // Constrained is stored in if_xflags which isn't exposed directly
1740 if (ioctl(s, SIOCGIFCONSTRAINED, (caddr_t)&ifr) == 0 &&
1741 ifr.ifr_constrained != 0) {
1742 printf(" constrained");
1743 }
1744#endif
1745 putchar('\n');
1746
1747 if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 &&
1748 (eflags = ifr.ifr_eflags) != 0) {
1749 printb("\teflags", eflags, IFEFBITS);
1750 putchar('\n');
1751 }
1752
1753 if (verbose && ioctl(s, SIOCGIFXFLAGS, (caddr_t)&ifr) != -1 &&
1754 (xflags = ifr.ifr_xflags) != 0) {
1755 printb("\txflags", xflags, IFXFBITS);
1756 putchar('\n');
1757 }
1758
1759 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
1760 if (ifr.ifr_curcap != 0) {
1761 curcap = ifr.ifr_curcap;
1762 printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
1763 putchar('\n');
1764 }
1765 if (supmedia && ifr.ifr_reqcap != 0) {
1766 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
1767 putchar('\n');
1768 }
1769 }
1770
1771 tunnel_status(s);
1772
1773 for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
1774 if (ift->ifa_addr == NULL)
1775 continue;
1776 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
1777 continue;
1778 if (allfamilies) {
1779 const struct afswtch *p;
1780 p = af_getbyfamily(ift->ifa_addr->sa_family);
1781 if (p != NULL && p->af_status != NULL)
1782 p->af_status(s, ift);
1783 } else if (afp->af_af == ift->ifa_addr->sa_family)
1784 afp->af_status(s, ift);
1785 }
1786
1787/* Print CLAT46 address */
1788 clat46_addr(s, name);
1789
1790/* Print NAT64 prefix */
1791 nat64_status(s, name);
1792
1793#if 0
1794 if (allfamilies || afp->af_af == AF_LINK) {
1795 const struct afswtch *lafp;
1796
1797 /*
1798 * Hack; the link level address is received separately
1799 * from the routing information so any address is not
1800 * handled above. Cobble together an entry and invoke
1801 * the status method specially.
1802 */
1803 lafp = af_getbyname("lladdr");
1804 if (lafp != NULL) {
1805 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
1806 lafp->af_status(s, &info);
1807 }
1808 }
1809#endif
1810 if (allfamilies)
1811 af_other_status(s);
1812 else if (afp->af_other_status != NULL)
1813 afp->af_other_status(s);
1814
1815 strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
1816 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
1817 printf("%s", ifs.ascii);
1818
1819 /* The rest is for when verbose is set; if not set, we're done */
1820 if (!verbose)
1821 goto done;
1822
1823 if (ioctl(s, SIOCGIFTYPE, &ifr) != -1) {
1824 char *c = ift2str(ifr.ifr_type.ift_type,
1825 ifr.ifr_type.ift_family, ifr.ifr_type.ift_subfamily);
1826 if (c != NULL)
1827 printf("\ttype: %s\n", c);
1828 }
1829
1830 if (verbose > 1) {
1831 if (ioctl(s, SIOCGIFFUNCTIONALTYPE, &ifr) != -1) {
1832 char *c = iffunct2str(ifr.ifr_functional_type);
1833 if (c != NULL)
1834 printf("\tfunctional type: %s\n", c);
1835 }
1836 }
1837 {
1838 struct if_agentidsreq ifar;
1839 memset(&ifar, 0, sizeof(ifar));
1840
1841 strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
1842
1843 if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != -1) {
1844 if (ifar.ifar_count != 0) {
1845 ifar.ifar_uuids = calloc(ifar.ifar_count, sizeof(uuid_t));
1846 if (ifar.ifar_uuids != NULL) {
1847 if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != 1) {
1848 for (int agent_i = 0; agent_i < ifar.ifar_count; agent_i++) {
1849 struct netagent_req nar;
1850 memset(&nar, 0, sizeof(nar));
1851
1852 uuid_copy(nar.netagent_uuid, ifar.ifar_uuids[agent_i]);
1853
1854 if (ioctl(s, SIOCGIFAGENTDATA, &nar) != 1) {
1855 printf("\tagent domain:%s type:%s flags:0x%x desc:\"%s\"\n",
1856 nar.netagent_domain, nar.netagent_type,
1857 nar.netagent_flags, nar.netagent_desc);
1858 }
1859 }
1860 }
1861 free(ifar.ifar_uuids);
1862 }
1863 }
1864 }
1865 }
1866
1867 if (ioctl(s, SIOCGIFLINKQUALITYMETRIC, &ifr) != -1) {
1868 int lqm = ifr.ifr_link_quality_metric;
1869 if (verbose > 1) {
1870 printf("\tlink quality: %d ", lqm);
1871 if (lqm == IFNET_LQM_THRESH_OFF)
1872 printf("(off)");
1873 else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
1874 printf("(unknown)");
1875 else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
1876 lqm <= IFNET_LQM_THRESH_BAD)
1877 printf("(bad)");
1878 else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
1879 lqm <= IFNET_LQM_THRESH_POOR)
1880 printf("(poor)");
1881 else if (lqm > IFNET_LQM_THRESH_POOR &&
1882 lqm <= IFNET_LQM_THRESH_GOOD)
1883 printf("(good)");
1884 else
1885 printf("(?)");
1886 printf("\n");
1887 } else if (lqm > IFNET_LQM_THRESH_UNKNOWN) {
1888 printf("\tlink quality: %d ", lqm);
1889 if (lqm <= IFNET_LQM_THRESH_BAD)
1890 printf("(bad)");
1891 else if (lqm <= IFNET_LQM_THRESH_POOR)
1892 printf("(poor)");
1893 else if (lqm <= IFNET_LQM_THRESH_GOOD)
1894 printf("(good)");
1895 else
1896 printf("(?)");
1897 printf("\n");
1898 }
1899 }
1900
1901 {
1902 if (ioctl(s, SIOCGIFINTERFACESTATE, &ifr) != -1) {
1903 printf("\tstate");
1904 if (ifr.ifr_interface_state.valid_bitmask &
1905 IF_INTERFACE_STATE_RRC_STATE_VALID) {
1906 uint8_t rrc_state = ifr.ifr_interface_state.rrc_state;
1907
1908 printf(" rrc: %u ", rrc_state);
1909 if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
1910 printf("(connected)");
1911 else if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_IDLE)
1912 printf("(idle)");
1913 else
1914 printf("(?)");
1915 }
1916 if (ifr.ifr_interface_state.valid_bitmask &
1917 IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
1918 uint8_t ifavail = ifr.ifr_interface_state.interface_availability;
1919
1920 printf(" availability: %u ", ifavail);
1921 if (ifavail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
1922 printf("(true)");
1923 else if (ifavail == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
1924 printf("(false)");
1925 else
1926 printf("(?)");
1927 } else {
1928 printf(" availability: (not valid)");
1929 }
1930 if (verbose > 1 &&
1931 ifr.ifr_interface_state.valid_bitmask &
1932 IF_INTERFACE_STATE_LQM_STATE_VALID) {
1933 int8_t lqm = ifr.ifr_interface_state.lqm_state;
1934
1935 printf(" lqm: %d", lqm);
1936
1937 if (lqm == IFNET_LQM_THRESH_OFF)
1938 printf("(off)");
1939 else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
1940 printf("(unknown)");
1941 else if (lqm == IFNET_LQM_THRESH_BAD)
1942 printf("(bad)");
1943 else if (lqm == IFNET_LQM_THRESH_POOR)
1944 printf("(poor)");
1945 else if (lqm == IFNET_LQM_THRESH_GOOD)
1946 printf("(good)");
1947 else
1948 printf("(?)");
1949 }
1950 }
1951 printf("\n");
1952 }
1953
1954 bzero(&iflpr, sizeof (iflpr));
1955 strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
1956 if (ioctl(s, SIOCGIFLINKPARAMS, &iflpr) != -1) {
1957 u_int64_t ibw_max = iflpr.iflpr_input_bw.max_bw;
1958 u_int64_t ibw_eff = iflpr.iflpr_input_bw.eff_bw;
1959 u_int64_t obw_max = iflpr.iflpr_output_bw.max_bw;
1960 u_int64_t obw_eff = iflpr.iflpr_output_bw.eff_bw;
1961 u_int64_t obw_tbr = iflpr.iflpr_output_tbr_rate;
1962 u_int32_t obw_pct = iflpr.iflpr_output_tbr_percent;
1963 u_int64_t ilt_max = iflpr.iflpr_input_lt.max_lt;
1964 u_int64_t ilt_eff = iflpr.iflpr_input_lt.eff_lt;
1965 u_int64_t olt_max = iflpr.iflpr_output_lt.max_lt;
1966 u_int64_t olt_eff = iflpr.iflpr_output_lt.eff_lt;
1967
1968
1969 if (eflags & IFEF_TXSTART) {
1970 u_int32_t flags = iflpr.iflpr_flags;
1971 u_int32_t sched = iflpr.iflpr_output_sched;
1972 struct if_throttlereq iftr;
1973
1974 printf("\tscheduler: %s%s ",
1975 (flags & IFLPRF_ALTQ) ? "ALTQ_" : "",
1976 sched2str(sched));
1977 if (flags & IFLPRF_DRVMANAGED)
1978 printf("(driver managed)");
1979 printf("\n");
1980
1981 bzero(&iftr, sizeof (iftr));
1982 strlcpy(iftr.ifthr_name, name,
1983 sizeof (iftr.ifthr_name));
1984 if (ioctl(s, SIOCGIFTHROTTLE, &iftr) != -1 &&
1985 iftr.ifthr_level != IFNET_THROTTLE_OFF)
1986 printf("\tthrottling: level %d (%s)\n",
1987 iftr.ifthr_level, tl2str(iftr.ifthr_level));
1988 }
1989
1990 if (obw_tbr != 0 && obw_eff > obw_tbr)
1991 obw_eff = obw_tbr;
1992
1993 if (ibw_max != 0 || obw_max != 0) {
1994 if (ibw_max == obw_max && ibw_eff == obw_eff &&
1995 ibw_max == ibw_eff && obw_tbr == 0) {
1996 printf("\tlink rate: %s\n",
1997 bps_to_str(ibw_max));
1998 } else {
1999 printf("\tuplink rate: %s [eff] / ",
2000 bps_to_str(obw_eff));
2001 if (obw_tbr != 0) {
2002 if (obw_pct == 0)
2003 printf("%s [tbr] / ",
2004 bps_to_str(obw_tbr));
2005 else
2006 printf("%s [tbr %u%%] / ",
2007 bps_to_str(obw_tbr),
2008 obw_pct);
2009 }
2010 printf("%s", bps_to_str(obw_max));
2011 if (obw_tbr != 0)
2012 printf(" [max]");
2013 printf("\n");
2014 if (ibw_eff == ibw_max) {
2015 printf("\tdownlink rate: %s\n",
2016 bps_to_str(ibw_max));
2017 } else {
2018 printf("\tdownlink rate: "
2019 "%s [eff] / ", bps_to_str(ibw_eff));
2020 printf("%s [max]\n",
2021 bps_to_str(ibw_max));
2022 }
2023 }
2024 } else if (obw_tbr != 0) {
2025 printf("\tuplink rate: %s [tbr]\n",
2026 bps_to_str(obw_tbr));
2027 }
2028
2029 if (ilt_max != 0 || olt_max != 0) {
2030 if (ilt_max == olt_max && ilt_eff == olt_eff &&
2031 ilt_max == ilt_eff) {
2032 printf("\tlink latency: %s\n",
2033 ns_to_str(ilt_max));
2034 } else {
2035 if (olt_max != 0 && olt_eff == olt_max) {
2036 printf("\tuplink latency: %s\n",
2037 ns_to_str(olt_max));
2038 } else if (olt_max != 0) {
2039 printf("\tuplink latency: "
2040 "%s [eff] / ", ns_to_str(olt_eff));
2041 printf("%s [max]\n",
2042 ns_to_str(olt_max));
2043 }
2044 if (ilt_max != 0 && ilt_eff == ilt_max) {
2045 printf("\tdownlink latency: %s\n",
2046 ns_to_str(ilt_max));
2047 } else if (ilt_max != 0) {
2048 printf("\tdownlink latency: "
2049 "%s [eff] / ", ns_to_str(ilt_eff));
2050 printf("%s [max]\n",
2051 ns_to_str(ilt_max));
2052 }
2053 }
2054 }
2055 }
2056
2057 /* Common OID prefix */
2058 mib[0] = CTL_NET;
2059 mib[1] = PF_LINK;
2060 mib[2] = NETLINK_GENERIC;
2061 mib[3] = IFMIB_IFDATA;
2062 mib[4] = if_nametoindex(name);
2063 mib[5] = IFDATA_SUPPLEMENTAL;
2064 if (sysctl(mib, 6, &ifmsupp, &miblen, (void *)0, 0) == -1)
2065 err(1, "sysctl IFDATA_SUPPLEMENTAL");
2066
2067 if (ifmsupp.ifmd_data_extended.ifi_alignerrs != 0) {
2068 printf("\tunaligned pkts: %llu\n",
2069 ifmsupp.ifmd_data_extended.ifi_alignerrs);
2070 }
2071 if (ifmsupp.ifmd_data_extended.ifi_dt_bytes != 0) {
2072 printf("\tdata milestone interval: %s\n",
2073 bytes_to_str(ifmsupp.ifmd_data_extended.ifi_dt_bytes));
2074 }
2075
2076 bzero(&ifdr, sizeof (ifdr));
2077 strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
2078 if (ioctl(s, SIOCGIFDESC, &ifdr) != -1 && ifdr.ifdr_len) {
2079 printf("\tdesc: %s\n", ifdr.ifdr_desc);
2080 }
2081
2082 if (ioctl(s, SIOCGIFLOG, &ifr) != -1 && ifr.ifr_log.ifl_level) {
2083 printf("\tlogging: level %d ", ifr.ifr_log.ifl_level);
2084 printb("facilities", ifr.ifr_log.ifl_flags, IFRLOGF_BITS);
2085 putchar('\n');
2086 }
2087
2088 if (ioctl(s, SIOCGIFDELEGATE, &ifr) != -1 && ifr.ifr_delegated) {
2089 char delegatedif[IFNAMSIZ+1];
2090 if (if_indextoname(ifr.ifr_delegated, delegatedif) != NULL)
2091 printf("\teffective interface: %s\n", delegatedif);
2092 }
2093
2094 if (ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) {
2095 if (ifr.ifr_start_delay_qlen > 0 &&
2096 ifr.ifr_start_delay_timeout > 0) {
2097 printf("\ttxstart qlen: %u packets "
2098 "timeout: %u microseconds\n",
2099 ifr.ifr_start_delay_qlen,
2100 ifr.ifr_start_delay_timeout/1000);
2101 }
2102 }
2103#if defined(IFCAP_HW_TIMESTAMP) && defined(IFCAP_SW_TIMESTAMP)
2104 if ((curcap & (IFCAP_HW_TIMESTAMP | IFCAP_SW_TIMESTAMP)) &&
2105 ioctl(s, SIOCGIFTIMESTAMPENABLED, &ifr) != -1) {
2106 printf("\ttimestamp: %s\n",
2107 (ifr.ifr_intval != 0) ? "enabled" : "disabled");
2108 }
2109#endif
2110#if defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE)
2111 if (ioctl(s, SIOCGQOSMARKINGENABLED, &ifr) != -1) {
2112 printf("\tqosmarking enabled: %s mode: ",
2113 ifr.ifr_qosmarking_enabled ? "yes" : "no");
2114 if (ioctl(s, SIOCGQOSMARKINGMODE, &ifr) != -1) {
2115 switch (ifr.ifr_qosmarking_mode) {
2116 case IFRTYPE_QOSMARKING_FASTLANE:
2117 printf("fastlane\n");
2118 break;
2119 case IFRTYPE_QOSMARKING_RFC4594:
2120 printf("RFC4594\n");
2121 break;
2122 case IFRTYPE_QOSMARKING_MODE_NONE:
2123 printf("none\n");
2124 break;
2125 default:
2126 printf("unknown (%u)\n", ifr.ifr_qosmarking_mode);
2127 break;
2128 }
2129 }
2130 }
2131#endif /* defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) */
2132
2133 if (ioctl(s, SIOCGIFLOWPOWER, &ifr) != -1) {
2134 printf("\tlow power mode: %s\n",
2135 (ifr.ifr_low_power_mode != 0) ? "enabled" : "disabled");
2136 }
2137 if (ioctl(s, SIOCGIFMPKLOG, &ifr) != -1) {
2138 printf("\tmulti layer packet logging (mpklog): %s\n",
2139 (ifr.ifr_mpk_log != 0) ? "enabled" : "disabled");
2140 }
2141 show_routermode(s);
2142 show_routermode6();
2143
2144done:
2145 close(s);
2146 return;
2147}
2148
2149#define KILOBYTES 1024
2150#define MEGABYTES (KILOBYTES * KILOBYTES)
2151#define GIGABYTES (KILOBYTES * KILOBYTES * KILOBYTES)
2152
2153static char *
2154bytes_to_str(unsigned long long bytes)
2155{
2156 static char buf[32];
2157 const char *u;
2158 long double n = bytes, t;
2159
2160 if (bytes >= GIGABYTES) {
2161 t = n / GIGABYTES;
2162 u = "GB";
2163 } else if (n >= MEGABYTES) {
2164 t = n / MEGABYTES;
2165 u = "MB";
2166 } else if (n >= KILOBYTES) {
2167 t = n / KILOBYTES;
2168 u = "KB";
2169 } else {
2170 t = n;
2171 u = "bytes";
2172 }
2173
2174 snprintf(buf, sizeof (buf), "%-4.2Lf %s", t, u);
2175 return (buf);
2176}
2177
2178#define GIGABIT_PER_SEC 1000000000 /* gigabit per second */
2179#define MEGABIT_PER_SEC 1000000 /* megabit per second */
2180#define KILOBIT_PER_SEC 1000 /* kilobit per second */
2181
2182static char *
2183bps_to_str(unsigned long long rate)
2184{
2185 static char buf[32];
2186 const char *u;
2187 long double n = rate, t;
2188
2189 if (rate >= GIGABIT_PER_SEC) {
2190 t = n / GIGABIT_PER_SEC;
2191 u = "Gbps";
2192 } else if (n >= MEGABIT_PER_SEC) {
2193 t = n / MEGABIT_PER_SEC;
2194 u = "Mbps";
2195 } else if (n >= KILOBIT_PER_SEC) {
2196 t = n / KILOBIT_PER_SEC;
2197 u = "Kbps";
2198 } else {
2199 t = n;
2200 u = "bps ";
2201 }
2202
2203 snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
2204 return (buf);
2205}
2206
2207#define NSEC_PER_SEC 1000000000 /* nanosecond per second */
2208#define USEC_PER_SEC 1000000 /* microsecond per second */
2209#define MSEC_PER_SEC 1000 /* millisecond per second */
2210
2211static char *
2212ns_to_str(unsigned long long nsec)
2213{
2214 static char buf[32];
2215 const char *u;
2216 long double n = nsec, t;
2217
2218 if (nsec >= NSEC_PER_SEC) {
2219 t = n / NSEC_PER_SEC;
2220 u = "sec ";
2221 } else if (n >= USEC_PER_SEC) {
2222 t = n / USEC_PER_SEC;
2223 u = "msec";
2224 } else if (n >= MSEC_PER_SEC) {
2225 t = n / MSEC_PER_SEC;
2226 u = "usec";
2227 } else {
2228 t = n;
2229 u = "nsec";
2230 }
2231
2232 snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
2233 return (buf);
2234}
2235
2236static void
2237tunnel_status(int s)
2238{
2239 af_all_tunnel_status(s);
2240}
2241
2242static void
2243clat46_addr(int s, char * if_name)
2244{
2245 struct if_clat46req ifr;
2246 char buf[MAXHOSTNAMELEN];
2247
2248 bzero(&ifr, sizeof (ifr));
2249 strlcpy(ifr.ifclat46_name, if_name, sizeof(ifr.ifclat46_name));
2250
2251 if (ioctl(s, SIOCGIFCLAT46ADDR, &ifr) < 0) {
2252 if (errno != ENOENT)
2253 syslog(LOG_WARNING, "ioctl (SIOCGIFCLAT46ADDR): %d", errno);
2254 return;
2255 }
2256
2257 if (inet_ntop(AF_INET6, &ifr.ifclat46_addr.v6_address, buf, sizeof(buf)) != NULL)
2258 printf("\tinet6 %s prefixlen %d clat46\n",
2259 buf, ifr.ifclat46_addr.v6_prefixlen);
2260}
2261
2262static void
2263nat64_status(int s, char * if_name)
2264{
2265 int i;
2266 struct if_nat64req ifr;
2267 char buf[MAXHOSTNAMELEN];
2268
2269 bzero(&ifr, sizeof(ifr));
2270 strlcpy(ifr.ifnat64_name, if_name, sizeof(ifr.ifnat64_name));
2271
2272 if (ioctl(s, SIOCGIFNAT64PREFIX, &ifr) < 0) {
2273 if (errno != ENOENT)
2274 syslog(LOG_WARNING, "ioctl(SIOCGIFNAT64PREFIX): %d", errno);
2275 return;
2276 }
2277
2278 for (i = 0; i < NAT64_MAX_NUM_PREFIXES; i++) {
2279 if (ifr.ifnat64_prefixes[i].prefix_len > 0) {
2280 inet_ntop(AF_INET6, &ifr.ifnat64_prefixes[i].ipv6_prefix, buf, sizeof(buf));
2281 printf("\tnat64 prefix %s prefixlen %d\n",
2282 buf, ifr.ifnat64_prefixes[i].prefix_len << 3);
2283 }
2284 }
2285}
2286
2287void
2288Perror(const char *cmd)
2289{
2290 switch (errno) {
2291
2292 case ENXIO:
2293 errx(1, "%s: no such interface", cmd);
2294 break;
2295
2296 case EPERM:
2297 errx(1, "%s: permission denied", cmd);
2298 break;
2299
2300 default:
2301 err(1, "%s", cmd);
2302 }
2303}
2304
2305/*
2306 * Print a value a la the %b format of the kernel's printf
2307 */
2308void
2309printb(const char *s, unsigned v, const char *bits)
2310{
2311 int i, any = 0;
2312 char c;
2313
2314 if (bits && *bits == 8)
2315 printf("%s=%o", s, v);
2316 else
2317 printf("%s=%x", s, v);
2318 bits++;
2319 if (bits) {
2320 putchar('<');
2321 while ((i = *bits++) != '\0') {
2322 if (v & (1 << (i-1))) {
2323 if (any)
2324 putchar(',');
2325 any = 1;
2326 for (; (c = *bits) > 32; bits++)
2327 putchar(c);
2328 } else
2329 for (; *bits > 32; bits++)
2330 ;
2331 }
2332 putchar('>');
2333 }
2334}
2335
2336#ifndef __APPLE__
2337void
2338ifmaybeload(const char *name)
2339{
2340#define MOD_PREFIX_LEN 3 /* "if_" */
2341 struct module_stat mstat;
2342 int fileid, modid;
2343 char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
2344 const char *cp;
2345
2346 /* loading suppressed by the user */
2347 if (noload)
2348 return;
2349
2350 /* trim the interface number off the end */
2351 strlcpy(ifname, name, sizeof(ifname));
2352 for (dp = ifname; *dp != 0; dp++)
2353 if (isdigit(*dp)) {
2354 *dp = 0;
2355 break;
2356 }
2357
2358 /* turn interface and unit into module name */
2359 strlcpy(ifkind, "if_", sizeof(ifkind));
2360 strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
2361 sizeof(ifkind) - MOD_PREFIX_LEN);
2362
2363 /* scan files in kernel */
2364 mstat.version = sizeof(struct module_stat);
2365 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
2366 /* scan modules in file */
2367 for (modid = kldfirstmod(fileid); modid > 0;
2368 modid = modfnext(modid)) {
2369 if (modstat(modid, &mstat) < 0)
2370 continue;
2371 /* strip bus name if present */
2372 if ((cp = strchr(mstat.name, '/')) != NULL) {
2373 cp++;
2374 } else {
2375 cp = mstat.name;
2376 }
2377 /* already loaded? */
2378 if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
2379 strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
2380 return;
2381 }
2382 }
2383
2384 /* not present, we should try to load it */
2385 kldload(ifkind);
2386}
2387#endif
2388
2389static struct cmd basic_cmds[] = {
2390 DEF_CMD("up", IFF_UP, setifflags),
2391 DEF_CMD("down", -IFF_UP, setifflags),
2392 DEF_CMD("arp", -IFF_NOARP, setifflags),
2393 DEF_CMD("-arp", IFF_NOARP, setifflags),
2394 DEF_CMD("debug", IFF_DEBUG, setifflags),
2395 DEF_CMD("-debug", -IFF_DEBUG, setifflags),
2396#ifdef IFF_PPROMISC
2397 DEF_CMD("promisc", IFF_PPROMISC, setifflags),
2398 DEF_CMD("-promisc", -IFF_PPROMISC, setifflags),
2399#endif /* IFF_PPROMISC */
2400 DEF_CMD("add", IFF_UP, notealias),
2401 DEF_CMD("alias", IFF_UP, notealias),
2402 DEF_CMD("-alias", -IFF_UP, notealias),
2403 DEF_CMD("delete", -IFF_UP, notealias),
2404 DEF_CMD("remove", -IFF_UP, notealias),
2405#ifdef notdef
2406#define EN_SWABIPS 0x1000
2407 DEF_CMD("swabips", EN_SWABIPS, setifflags),
2408 DEF_CMD("-swabips", -EN_SWABIPS, setifflags),
2409#endif
2410 DEF_CMD_ARG("netmask", setifnetmask),
2411 DEF_CMD_ARG("metric", setifmetric),
2412 DEF_CMD_ARG("broadcast", setifbroadaddr),
2413 DEF_CMD_ARG("ipdst", setifipdst),
2414 DEF_CMD_ARG2("tunnel", settunnel),
2415 DEF_CMD("-tunnel", 0, deletetunnel),
2416 DEF_CMD("deletetunnel", 0, deletetunnel),
2417 DEF_CMD("link0", IFF_LINK0, setifflags),
2418 DEF_CMD("-link0", -IFF_LINK0, setifflags),
2419 DEF_CMD("link1", IFF_LINK1, setifflags),
2420 DEF_CMD("-link1", -IFF_LINK1, setifflags),
2421 DEF_CMD("link2", IFF_LINK2, setifflags),
2422 DEF_CMD("-link2", -IFF_LINK2, setifflags),
2423#ifdef IFF_MONITOR
2424 DEF_CMD("monitor", IFF_MONITOR:, setifflags),
2425 DEF_CMD("-monitor", -IFF_MONITOR, setifflags),
2426#endif /* IFF_MONITOR */
2427 DEF_CMD("mpklog", 1, setifmpklog),
2428 DEF_CMD("-mpklog", 0, setifmpklog),
2429#ifdef IFF_STATICARP
2430 DEF_CMD("staticarp", IFF_STATICARP, setifflags),
2431 DEF_CMD("-staticarp", -IFF_STATICARP, setifflags),
2432#endif /* IFF_STATICARP */
2433#ifdef IFCAP_RXCSUM
2434 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
2435 DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap),
2436#endif /* IFCAP_RXCSUM */
2437#ifdef IFCAP_TXCSUM
2438 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
2439 DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap),
2440#endif /* IFCAP_TXCSUM */
2441#ifdef IFCAP_NETCONS
2442 DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
2443 DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap),
2444#endif /* IFCAP_NETCONS */
2445#ifdef IFCAP_POLLING
2446 DEF_CMD("polling", IFCAP_POLLING, setifcap),
2447 DEF_CMD("-polling", -IFCAP_POLLING, setifcap),
2448#endif /* IFCAP_POLLING */
2449#ifdef IFCAP_TSO
2450 DEF_CMD("tso", IFCAP_TSO, setifcap),
2451 DEF_CMD("-tso", -IFCAP_TSO, setifcap),
2452#endif /* IFCAP_TSO */
2453#ifdef IFCAP_LRO
2454 DEF_CMD("lro", IFCAP_LRO, setifcap),
2455 DEF_CMD("-lro", -IFCAP_LRO, setifcap),
2456#endif /* IFCAP_LRO */
2457#ifdef IFCAP_WOL
2458 DEF_CMD("wol", IFCAP_WOL, setifcap),
2459 DEF_CMD("-wol", -IFCAP_WOL, setifcap),
2460#endif /* IFCAP_WOL */
2461#ifdef IFCAP_WOL_UCAST
2462 DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap),
2463 DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap),
2464#endif /* IFCAP_WOL_UCAST */
2465#ifdef IFCAP_WOL_MCAST
2466 DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap),
2467 DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap),
2468#endif /* IFCAP_WOL_MCAST */
2469#ifdef IFCAP_WOL_MAGIC
2470 DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap),
2471 DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap),
2472#endif /* IFCAP_WOL_MAGIC */
2473 DEF_CMD("normal", -IFF_LINK0, setifflags),
2474 DEF_CMD("compress", IFF_LINK0, setifflags),
2475 DEF_CMD("noicmp", IFF_LINK1, setifflags),
2476 DEF_CMD_ARG("mtu", setifmtu),
2477#ifdef notdef
2478 DEF_CMD_ARG("name", setifname),
2479#endif /* notdef */
2480#ifdef IFCAP_AV
2481 DEF_CMD("av", IFCAP_AV, setifcap),
2482 DEF_CMD("-av", -IFCAP_AV, setifcap),
2483#endif /* IFCAP_AV */
2484 DEF_CMD("router", 1, setrouter),
2485 DEF_CMD("-router", 0, setrouter),
2486 DEF_CMD_VA("routermode", routermode),
2487 DEF_CMD_ARG("desc", setifdesc),
2488 DEF_CMD_ARG("tbr", settbr),
2489 DEF_CMD_VA("netem", setnetem),
2490 DEF_CMD_ARG("throttle", setthrottle),
2491 DEF_CMD_ARG("log", setlog),
2492 DEF_CMD("cl2k", 1, setcl2k),
2493 DEF_CMD("-cl2k", 0, setcl2k),
2494 DEF_CMD("expensive", 1, setexpensive),
2495 DEF_CMD("-expensive", 0, setexpensive),
2496#ifdef SIOCSIFCONSTRAINED
2497 DEF_CMD("constrained", 1, setconstrained),
2498 DEF_CMD("-constrained", 0, setconstrained),
2499#endif
2500 DEF_CMD("timestamp", 1, settimestamp),
2501 DEF_CMD("-timestamp", 0, settimestamp),
2502 DEF_CMD_ARG("ecn", setecnmode),
2503 DEF_CMD_ARG2("fastlane", setfastlane),
2504 DEF_CMD_ARG2("qosmarking", setqosmarking),
2505 DEF_CMD_ARG("disable_output", setdisableoutput),
2506 DEF_CMD("probe_connectivity", 1, setprobeconnectivity),
2507 DEF_CMD("-probe_connectivity", 0, setprobeconnectivity),
2508 DEF_CMD("lowpowermode", 1, setlowpowermode),
2509 DEF_CMD("-lowpowermode", 0, setlowpowermode),
2510 DEF_CMD_ARG("subfamily", setifsubfamily),
2511 DEF_CMD("available", 1, setifavailability),
2512 DEF_CMD("-available", 0, setifavailability),
2513 DEF_CMD("unavailable", 0, setifavailability),
2514};
2515
2516static __constructor void
2517ifconfig_ctor(void)
2518{
2519#define N(a) (sizeof(a) / sizeof(a[0]))
2520 int i;
2521
2522 for (i = 0; i < N(basic_cmds); i++)
2523 cmd_register(&basic_cmds[i]);
2524#undef N
2525}
2526
2527static char *
2528sched2str(unsigned int s)
2529{
2530 char *c;
2531
2532 switch (s) {
2533 case PKTSCHEDT_NONE:
2534 c = "NONE";
2535 break;
2536 case PKTSCHEDT_FQ_CODEL:
2537 c = "FQ_CODEL";
2538 break;
2539 default:
2540 c = "UNKNOWN";
2541 break;
2542 }
2543
2544 return (c);
2545}
2546
2547static char *
2548tl2str(unsigned int s)
2549{
2550 char *c;
2551
2552 switch (s) {
2553 case IFNET_THROTTLE_OFF:
2554 c = "off";
2555 break;
2556 case IFNET_THROTTLE_OPPORTUNISTIC:
2557 c = "opportunistic";
2558 break;
2559 default:
2560 c = "unknown";
2561 break;
2562 }
2563
2564 return (c);
2565}
2566
2567static char *
2568ift2str(unsigned int t, unsigned int f, unsigned int sf)
2569{
2570 static char buf[256];
2571 char *c = NULL;
2572
2573 switch (t) {
2574 case IFT_ETHER:
2575 switch (sf) {
2576 case IFRTYPE_SUBFAMILY_USB:
2577 c = "USB Ethernet";
2578 break;
2579 case IFRTYPE_SUBFAMILY_BLUETOOTH:
2580 c = "Bluetooth PAN";
2581 break;
2582 case IFRTYPE_SUBFAMILY_WIFI:
2583 c = "Wi-Fi";
2584 break;
2585 case IFRTYPE_SUBFAMILY_THUNDERBOLT:
2586 c = "IP over Thunderbolt";
2587 break;
2588 case IFRTYPE_SUBFAMILY_ANY:
2589 default:
2590 c = "Ethernet";
2591 break;
2592 }
2593 break;
2594
2595 case IFT_IEEE1394:
2596 c = "IP over FireWire";
2597 break;
2598
2599 case IFT_PKTAP:
2600 c = "Packet capture";
2601 break;
2602
2603 case IFT_CELLULAR:
2604 c = "Cellular";
2605 break;
2606
2607 case IFT_OTHER:
2608 if (ifr.ifr_type.ift_family == APPLE_IF_FAM_IPSEC) {
2609 if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_BLUETOOTH) {
2610 c = "Companion Link Bluetooth";
2611 } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_QUICKRELAY) {
2612 c = "Companion Link QuickRelay";
2613 } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_WIFI) {
2614 c = "Companion Link Wi-Fi";
2615 } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_DEFAULT) {
2616 c = "Companion Link Default";
2617 }
2618 }
2619 break;
2620
2621 case IFT_BRIDGE:
2622 case IFT_PFLOG:
2623 case IFT_PFSYNC:
2624 case IFT_PPP:
2625 case IFT_LOOP:
2626 case IFT_GIF:
2627 case IFT_STF:
2628 case IFT_L2VLAN:
2629 case IFT_IEEE8023ADLAG:
2630 default:
2631 break;
2632 }
2633
2634 if (verbose > 1) {
2635 if (c == NULL) {
2636 (void) snprintf(buf, sizeof (buf),
2637 "0x%x family: %u subfamily: %u",
2638 ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
2639 ifr.ifr_type.ift_subfamily);
2640 } else {
2641 (void) snprintf(buf, sizeof (buf),
2642 "%s (0x%x) family: %u subfamily: %u", c,
2643 ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
2644 ifr.ifr_type.ift_subfamily);
2645 }
2646 c = buf;
2647 }
2648
2649 return (c);
2650}
2651
2652static char *
2653iffunct2str(u_int32_t functional_type)
2654{
2655 char *str = NULL;
2656
2657 switch (functional_type) {
2658 case IFRTYPE_FUNCTIONAL_UNKNOWN:
2659 break;
2660
2661 case IFRTYPE_FUNCTIONAL_LOOPBACK:
2662 str = "loopback";
2663 break;
2664
2665 case IFRTYPE_FUNCTIONAL_WIRED:
2666 str = "wired";
2667 break;
2668
2669 case IFRTYPE_FUNCTIONAL_WIFI_INFRA:
2670 str = "wifi";
2671 break;
2672
2673 case IFRTYPE_FUNCTIONAL_WIFI_AWDL:
2674 str = "awdl";
2675 break;
2676
2677 case IFRTYPE_FUNCTIONAL_CELLULAR:
2678 str = "cellular";
2679 break;
2680
2681 case IFRTYPE_FUNCTIONAL_INTCOPROC:
2682 break;
2683
2684 case IFRTYPE_FUNCTIONAL_COMPANIONLINK:
2685 str = "companionlink";
2686 break;
2687
2688 default:
2689 break;
2690 }
2691 return str;
2692}