]> git.saurik.com Git - apple/network_cmds.git/blob - ifconfig.tproj/ifconfig.c
network_cmds-596.100.2.tar.gz
[apple/network_cmds.git] / ifconfig.tproj / ifconfig.c
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 */
117 struct ifreq ifr;
118
119 char name[IFNAMSIZ];
120 int setaddr;
121 int setmask;
122 int doalias;
123 int clearaddr;
124 int newaddr = 1;
125 int noload;
126 int all;
127
128 int bond_details = 0;
129 int supmedia = 0;
130 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
131 int verbose = 1;
132 int showrtref = 1;
133 #else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
134 int verbose = 0;
135 int showrtref = 0;
136 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
137 int printkeys = 0; /* Print keying material for interfaces. */
138
139 static int ifconfig(int argc, char *const *argv, int iscreate,
140 const struct afswtch *afp);
141 static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
142 struct ifaddrs *ifa);
143 static char *bytes_to_str(unsigned long long bytes);
144 static char *bps_to_str(unsigned long long rate);
145 static char *ns_to_str(unsigned long long nsec);
146 static void tunnel_status(int s);
147 static void clat46_addr(int s, char *name);
148 static void nat64_status(int s, char *name);
149 static void usage(void);
150 static char *sched2str(unsigned int s);
151 static char *tl2str(unsigned int s);
152 static char *ift2str(unsigned int t, unsigned int f, unsigned int sf);
153 static char *iffunct2str(u_int32_t functional_type);
154
155 static struct afswtch *af_getbyname(const char *name);
156 static struct afswtch *af_getbyfamily(int af);
157 static void af_other_status(int);
158
159 static struct option *opts = NULL;
160
161 void
162 opt_register(struct option *p)
163 {
164 p->next = opts;
165 opts = p;
166 }
167
168 static void
169 usage(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
192 int
193 main(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
387 static struct afswtch *afs = NULL;
388
389 void
390 af_register(struct afswtch *p)
391 {
392 p->af_next = afs;
393 afs = p;
394 }
395
396 static struct afswtch *
397 af_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
407 static struct afswtch *
408 af_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
418 static void
419 af_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
435 static void
436 af_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
452 static struct cmd *cmds = NULL;
453
454 void
455 cmd_register(struct cmd *p)
456 {
457 p->c_next = cmds;
458 cmds = p;
459 }
460
461 static const struct cmd *
462 cmd_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
474 struct callback {
475 callback_func *cb_func;
476 void *cb_arg;
477 struct callback *cb_next;
478 };
479 static struct callback *callbacks = NULL;
480
481 void
482 callback_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 */
496 static void setifaddr(const char *, int, int, const struct afswtch *);
497 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
498
499 static void setifdstaddr(const char *, int, int, const struct afswtch *);
500 static const struct cmd setifdstaddr_cmd =
501 DEF_CMD("ifdstaddr", 0, setifdstaddr);
502
503 static int
504 ifconfig(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);
511 top:
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*/
638 static void
639 setifaddr(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
654 static void
655 settunnel(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 */
685 static void
686 deletetunnel(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
693 static void
694 setifnetmask(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
703 static void
704 setifbroadaddr(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
711 static void
712 setifipdst(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
725 static void
726 notealias(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*/
744 static void
745 setifdstaddr(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 */
757 static void
758 setifflags(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
782 void
783 setifcap(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
803 static void
804 setifmetric(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
813 static void
814 setifmtu(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__
824 static void
825 setifname(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
846 static void
847 setrouter(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
858 static void
859 setifdesc(const char *val, int dummy __unused, int s, const struct afswtch *afp)
860 {
861 struct if_descreq ifdr;
862
863 bzero(&ifdr, sizeof (ifdr));
864 strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
865 ifdr.ifdr_len = strlen(val);
866 strlcpy((char *)ifdr.ifdr_desc, val, sizeof (ifdr.ifdr_desc));
867
868 if (ioctl(s, SIOCSIFDESC, (caddr_t)&ifdr) < 0) {
869 warn("ioctl (set desc)");
870 }
871 }
872
873 static void
874 settbr(const char *val, int dummy __unused, int s, const struct afswtch *afp)
875 {
876 struct if_linkparamsreq iflpr;
877 long double bps;
878 u_int64_t rate;
879 u_int32_t percent = 0;
880 char *cp;
881
882 errno = 0;
883 bzero(&iflpr, sizeof (iflpr));
884 strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
885
886 bps = strtold(val, &cp);
887 if (val == cp || errno != 0) {
888 warn("Invalid value '%s'", val);
889 return;
890 }
891 rate = (u_int64_t)bps;
892 if (cp != NULL) {
893 if (!strcmp(cp, "b") || !strcmp(cp, "bps")) {
894 ; /* nothing */
895 } else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbps")) {
896 rate *= 1000;
897 } else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbps")) {
898 rate *= 1000 * 1000;
899 } else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbps")) {
900 rate *= 1000 * 1000 * 1000;
901 } else if (!strcmp(cp, "%")) {
902 percent = rate;
903 if (percent == 0 || percent > 100) {
904 printf("Value out of range '%s'", val);
905 return;
906 }
907 } else if (*cp != '\0') {
908 printf("Unknown unit '%s'", cp);
909 return;
910 }
911 }
912 iflpr.iflpr_output_tbr_rate = rate;
913 iflpr.iflpr_output_tbr_percent = percent;
914 if (ioctl(s, SIOCSIFLINKPARAMS, &iflpr) < 0 &&
915 errno != ENOENT && errno != ENXIO && errno != ENODEV) {
916 warn("ioctl (set link params)");
917 } else if (errno == ENXIO) {
918 printf("TBR cannot be set on %s\n", name);
919 } else if (errno == 0 && rate == 0) {
920 printf("%s: TBR is now disabled\n", name);
921 } else if (errno == ENODEV) {
922 printf("%s: requires absolute TBR rate\n", name);
923 } else if (percent != 0) {
924 printf("%s: TBR rate set to %u%% of effective link rate\n",
925 name, percent);
926 } else {
927 printf("%s: TBR rate set to %s\n", name, bps_to_str(rate));
928 }
929 }
930
931 static int
932 get_int64(uint64_t *i, char const *s)
933 {
934 char *cp;
935 *i = strtol(s, &cp, 10);
936 if (cp == s || errno != 0) {
937 return (-1);
938 }
939 return (0);
940 }
941
942 static int
943 get_int32(uint32_t *i, char const *s)
944 {
945 char *cp;
946 *i = strtol(s, &cp, 10);
947 if (cp == s || errno != 0) {
948 return (-1);
949 }
950 return (0);
951 }
952
953 static int
954 get_percent(double *d, const char *s)
955 {
956 char *cp;
957 *d = strtod(s, &cp) / (double)100;
958 if (*d == HUGE_VALF || *d == HUGE_VALL) {
959 return (-1);
960 }
961 if (*d == 0.0 || (*cp != '\0' && strcmp(cp, "%") != 0)) {
962 return (-1);
963 }
964 return (0);
965 }
966
967 static int
968 get_percent_fixed_point(uint32_t *i, const char *s)
969 {
970 double p;
971
972 if (get_percent(&p, s) != 0){
973 return (-1);
974 }
975
976 *i = p * IF_NETEM_PARAMS_PSCALE;
977 return (0);
978 }
979
980 static int
981 netem_parse_args(struct if_netem_params *p, int argc, char *const *argv)
982 {
983 int argc_saved = argc;
984 uint64_t bandwitdh = 0;
985 uint32_t latency = 0, jitter = 0;
986 uint32_t corruption = 0;
987 uint32_t duplication = 0;
988 uint32_t loss_p_gr_gl = 0, loss_p_gr_bl = 0, loss_p_bl_br = 0,
989 loss_p_bl_gr = 0, loss_p_br_bl = 0;
990 uint32_t reordering = 0;
991
992 bzero(p, sizeof (*p));
993
994 /* take out "input"/"output" */
995 argc--, argv++;
996
997 for ( ; argc > 0; ) {
998 if (strcmp(*argv, "bandwidth") == 0) {
999 argc--, argv++;
1000 if (argc <= 0 || get_int64(&bandwitdh, *argv) != 0) {
1001 err(1, "Invalid value '%s'", *argv);
1002 }
1003 argc--, argv++;
1004 } else if (strcmp(*argv, "corruption") == 0) {
1005 argc--, argv++;
1006 if (argc <= 0 ||
1007 get_percent_fixed_point(&corruption, *argv) != 0) {
1008 err(1, "Invalid value '%s'", *argv);
1009 }
1010 argc--, argv++;
1011 } else if (strcmp(*argv, "delay") == 0) {
1012 argc--, argv++;
1013 if (argc <= 0 || get_int32(&latency, *argv) != 0) {
1014 err(1, "Invalid value '%s'", *argv);
1015 }
1016 argc--, argv++;
1017 if (argc > 0 && get_int32(&jitter, *argv) == 0) {
1018 argc--, argv++;
1019 }
1020 } else if (strcmp(*argv, "duplication") == 0) {
1021 argc--, argv++;
1022 if (argc <= 0 ||
1023 get_percent_fixed_point(&duplication, *argv) != 0) {
1024 err(1, "Invalid value '%s'", *argv);
1025 return (-1);
1026 }
1027 argc--, argv++;
1028 } else if (strcmp(*argv, "loss") == 0) {
1029 argc--, argv++;
1030 if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_gl, *argv) != 0) {
1031 err(1, "Invalid value '%s'", *argv);
1032 }
1033 /* we may have all 5 probs, use naive model if not */
1034 argc--, argv++;
1035 if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_bl, *argv) != 0) {
1036 continue;
1037 }
1038 /* if more than p_gr_gl, then should have all probs */
1039 argc--, argv++;
1040 if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_br, *argv) != 0) {
1041 err(1, "Invalid value '%s' for p_bl_br", *argv);
1042 }
1043 argc--, argv++;
1044 if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_gr, *argv) != 0) {
1045 err(1, "Invalid value '%s' for p_bl_gr", *argv);
1046 }
1047 argc--, argv++;
1048 if (argc <= 0 || get_percent_fixed_point(&loss_p_br_bl, *argv) != 0) {
1049 err(1, "Invalid value '%s' for p_br_bl", *argv);
1050 }
1051 argc--, argv++;
1052 } else if (strcmp(*argv, "reordering") == 0) {
1053 argc--, argv++;
1054 if (argc <= 0 || get_percent_fixed_point(&reordering, *argv) != 0) {
1055 err(1, "Invalid value '%s'", *argv);
1056 }
1057 argc--, argv++;
1058 } else {
1059 return (-1);
1060 }
1061 }
1062
1063 if (corruption > IF_NETEM_PARAMS_PSCALE) {
1064 err(1, "corruption percentage > 100%%");
1065 }
1066
1067 if (duplication > IF_NETEM_PARAMS_PSCALE) {
1068 err(1, "duplication percentage > 100%%");
1069 }
1070
1071 if (duplication > 0 && latency == 0) {
1072 /* we need to insert dup'ed packet with latency */
1073 err(1, "duplication needs latency param");
1074 }
1075
1076 if (latency > 1000) {
1077 err(1, "latency %dms too big (> 1 sec)", latency);
1078 }
1079
1080 if (jitter * 3 > latency) {
1081 err(1, "jitter %dms too big (latency %dms)", jitter, latency);
1082 }
1083
1084 /* if gr_gl == 0 (no loss), other prob should all be zero */
1085 if (loss_p_gr_gl == 0 &&
1086 (loss_p_gr_bl != 0 || loss_p_bl_br != 0 || loss_p_bl_gr != 0 ||
1087 loss_p_br_bl != 0)) {
1088 err(1, "loss params not all zero when gr_gl is zero");
1089 }
1090
1091 /* check state machine transition prob integrity */
1092 if (loss_p_gr_gl > IF_NETEM_PARAMS_PSCALE ||
1093 /* gr_gl = IF_NETEM_PARAMS_PSCALE for total loss */
1094 loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
1095 loss_p_bl_br > IF_NETEM_PARAMS_PSCALE ||
1096 loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE ||
1097 loss_p_br_bl > IF_NETEM_PARAMS_PSCALE ||
1098 loss_p_gr_gl + loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
1099 loss_p_bl_br + loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE) {
1100 err(1, "loss params too big");
1101 }
1102
1103 if (reordering > IF_NETEM_PARAMS_PSCALE) {
1104 err(1, "reordering percentage > 100%%");
1105 }
1106
1107 p->ifnetem_bandwidth_bps = bandwitdh;
1108 p->ifnetem_latency_ms = latency;
1109 p->ifnetem_jitter_ms = jitter;
1110 p->ifnetem_corruption_p = corruption;
1111 p->ifnetem_duplication_p = duplication;
1112 p->ifnetem_loss_p_gr_gl = loss_p_gr_gl;
1113 p->ifnetem_loss_p_gr_bl = loss_p_gr_bl;
1114 p->ifnetem_loss_p_bl_br = loss_p_bl_br;
1115 p->ifnetem_loss_p_bl_gr = loss_p_bl_gr;
1116 p->ifnetem_loss_p_br_bl = loss_p_br_bl;
1117 p->ifnetem_reordering_p = reordering;
1118
1119 return (argc_saved - argc);
1120 }
1121
1122 void
1123 print_netem_params(struct if_netem_params *p, const char *desc)
1124 {
1125 struct if_netem_params zero_params;
1126 double pscale = IF_NETEM_PARAMS_PSCALE / 100;
1127 bzero(&zero_params, sizeof (zero_params));
1128
1129 if (memcmp(p, &zero_params, sizeof (zero_params)) == 0) {
1130 printf("%s NetEm Disabled\n\n", desc);
1131 } else {
1132 printf(
1133 "%s NetEm Parameters\n"
1134 "\tbandwidth rate %llubps\n"
1135 "\tdelay latency %dms\n"
1136 "\t jitter %dms\n",
1137 desc, p->ifnetem_bandwidth_bps,
1138 p->ifnetem_latency_ms, p->ifnetem_jitter_ms);
1139 if (p->ifnetem_loss_p_gr_bl == 0 &&
1140 p->ifnetem_loss_p_bl_br == 0 &&
1141 p->ifnetem_loss_p_bl_gr == 0 &&
1142 p->ifnetem_loss_p_br_bl == 0) {
1143 printf(
1144 "\tloss %.3f%%\n",
1145 (double) p->ifnetem_loss_p_gr_gl / pscale);
1146 } else {
1147 printf(
1148 "\tloss GAP_RECV -> GAP_LOSS %.3f%%\n"
1149 "\t GAP_RECV -> BURST_LOSS %.3f%%\n"
1150 "\t BURST_LOSS -> BURST_RECV %.3f%%\n"
1151 "\t BURST_LOSS -> GAP_RECV %.3f%%\n"
1152 "\t BURST_RECV -> BURST_LOSS %.3f%%\n",
1153 (double) p->ifnetem_loss_p_gr_gl / pscale,
1154 (double) p->ifnetem_loss_p_gr_bl / pscale,
1155 (double) p->ifnetem_loss_p_bl_br / pscale,
1156 (double) p->ifnetem_loss_p_bl_gr / pscale,
1157 (double) p->ifnetem_loss_p_br_bl / pscale);
1158 }
1159 printf(
1160 "\tcorruption %.3f%%\n"
1161 "\treordering %.3f%%\n\n",
1162 (double) p->ifnetem_corruption_p / pscale,
1163 (double) p->ifnetem_reordering_p / pscale);
1164 }
1165 }
1166
1167 static int
1168 setnetem(int argc, char *const *argv, int s, const struct afswtch *afp)
1169 {
1170 struct if_linkparamsreq iflpr;
1171 struct if_netem_params input_params, output_params;
1172 int ret = 0, error = 0;
1173
1174 bzero(&iflpr, sizeof (iflpr));
1175 bzero(&input_params, sizeof (input_params));
1176 bzero(&output_params, sizeof (output_params));
1177
1178 if (argc > 1) {
1179 if (strcmp(argv[0], "input") == 0) {
1180 ret = netem_parse_args(&input_params, argc, argv);
1181 } else if (strcmp(argv[0], "output") == 0) {
1182 ret = netem_parse_args(&output_params, argc, argv);
1183 } else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
1184 goto bad_args;
1185 } else {
1186 fprintf(stderr, "uknown option %s\n", argv[0]);
1187 goto bad_args;
1188 }
1189 if (ret < 0) {
1190 goto bad_args;
1191 }
1192 }
1193
1194 errno = 0;
1195 strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
1196 error = ioctl(s, SIOCGIFLINKPARAMS, &iflpr);
1197 if (error < 0) {
1198 warn("ioctl (get link params)");
1199 }
1200
1201 if (argc == 0) {
1202 print_netem_params(&iflpr.iflpr_input_netem, "Input");
1203 print_netem_params(&iflpr.iflpr_output_netem, "Output");
1204 return (0);
1205 } else if (argc == 1) {
1206 if (strcmp(argv[0], "input") == 0) {
1207 bzero(&iflpr.iflpr_input_netem,
1208 sizeof (iflpr.iflpr_input_netem));
1209 } else if (strcmp(argv[0], "output") == 0) {
1210 bzero(&iflpr.iflpr_output_netem,
1211 sizeof (iflpr.iflpr_output_netem));
1212 } else {
1213 fprintf(stderr, "uknown option %s\n", argv[0]);
1214 goto bad_args;
1215 }
1216 printf("%s: netem is now disabled for %s\n", name, argv[0]);
1217 ret = 1;
1218 } else {
1219 if (strcmp(argv[0], "input") == 0) {
1220 iflpr.iflpr_input_netem = input_params;
1221 } else if (strcmp(argv[0], "output") == 0) {
1222 iflpr.iflpr_output_netem = output_params;
1223 }
1224 }
1225
1226 error = ioctl(s, SIOCSIFLINKPARAMS, &iflpr);
1227 if (error < 0 && errno != ENOENT && errno != ENXIO && errno != ENODEV) {
1228 warn("ioctl (set link params)");
1229 } else if (errno == ENXIO) {
1230 printf("netem cannot be set on %s\n", name);
1231 } else {
1232 printf("%s: netem configured\n", name);
1233 }
1234
1235 return (ret);
1236 bad_args:
1237 fprintf(stderr, "Usage:\n"
1238 "\tTo enable/set netem params\n"
1239 "\t\tnetem <input|output>\n"
1240 "\t\t [ bandwidth BIT_PER_SEC ]\n"
1241 "\t\t [ delay DELAY_MSEC [ JITTER_MSEC ] ]\n"
1242 "\t\t [ loss PERCENTAGE ]\n"
1243 "\t\t [ duplication PERCENTAGE ]\n"
1244 "\t\t [ reordering PERCENTAGE ]\n\n"
1245 "\tTo disable <input|output> netem\n"
1246 "\t\tnetem <input|output>\n\n"
1247 "\tTo show current settings\n"
1248 "\t\tnetem\n\n");
1249 return (-1);
1250 }
1251
1252 static void
1253 setthrottle(const char *val, int dummy __unused, int s,
1254 const struct afswtch *afp)
1255 {
1256 struct if_throttlereq iftr;
1257 char *cp;
1258
1259 errno = 0;
1260 bzero(&iftr, sizeof (iftr));
1261 strlcpy(iftr.ifthr_name, name, sizeof (iftr.ifthr_name));
1262
1263 iftr.ifthr_level = strtold(val, &cp);
1264 if (val == cp || errno != 0) {
1265 warn("Invalid value '%s'", val);
1266 return;
1267 }
1268
1269 if (ioctl(s, SIOCSIFTHROTTLE, &iftr) < 0 && errno != ENXIO) {
1270 warn("ioctl (set throttling level)");
1271 } else if (errno == ENXIO) {
1272 printf("throttling level cannot be set on %s\n", name);
1273 } else {
1274 printf("%s: throttling level set to %d\n", name,
1275 iftr.ifthr_level);
1276 }
1277 }
1278
1279 static void
1280 setdisableoutput(const char *val, int dummy __unused, int s,
1281 const struct afswtch *afp)
1282 {
1283 struct ifreq ifr;
1284 char *cp;
1285 errno = 0;
1286 bzero(&ifr, sizeof (ifr));
1287 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1288
1289 ifr.ifr_ifru.ifru_disable_output = strtold(val, &cp);
1290 if (val == cp || errno != 0) {
1291 warn("Invalid value '%s'", val);
1292 return;
1293 }
1294
1295 if (ioctl(s, SIOCSIFDISABLEOUTPUT, &ifr) < 0 && errno != ENXIO) {
1296 warn("ioctl set disable output");
1297 } else if (errno == ENXIO) {
1298 printf("output thread can not be disabled on %s\n", name);
1299 } else {
1300 printf("output %s on %s\n",
1301 ((ifr.ifr_ifru.ifru_disable_output == 0) ? "enabled" : "disabled"),
1302 name);
1303 }
1304 }
1305
1306 static void
1307 setlog(const char *val, int dummy __unused, int s,
1308 const struct afswtch *afp)
1309 {
1310 char *cp;
1311
1312 errno = 0;
1313 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1314
1315 ifr.ifr_log.ifl_level = strtold(val, &cp);
1316 if (val == cp || errno != 0) {
1317 warn("Invalid value '%s'", val);
1318 return;
1319 }
1320 ifr.ifr_log.ifl_flags = (IFRLOGF_DLIL|IFRLOGF_FAMILY|IFRLOGF_DRIVER|
1321 IFRLOGF_FIRMWARE);
1322
1323 if (ioctl(s, SIOCSIFLOG, &ifr) < 0)
1324 warn("ioctl (set logging parameters)");
1325 }
1326
1327 void
1328 setcl2k(const char *vname, int value, int s, const struct afswtch *afp)
1329 {
1330 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1331 ifr.ifr_ifru.ifru_2kcl = value;
1332
1333 if (ioctl(s, SIOCSIF2KCL, (caddr_t)&ifr) < 0)
1334 Perror(vname);
1335 }
1336
1337 void
1338 setexpensive(const char *vname, int value, int s, const struct afswtch *afp)
1339 {
1340 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1341 ifr.ifr_ifru.ifru_expensive = value;
1342
1343 if (ioctl(s, SIOCSIFEXPENSIVE, (caddr_t)&ifr) < 0)
1344 Perror(vname);
1345 }
1346
1347 #ifdef SIOCSIFCONSTRAINED
1348 void
1349 setconstrained(const char *vname, int value, int s, const struct afswtch *afp)
1350 {
1351 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1352 ifr.ifr_ifru.ifru_constrained = value;
1353
1354 if (ioctl(s, SIOCSIFCONSTRAINED, (caddr_t)&ifr) < 0)
1355 Perror(vname);
1356 }
1357 #endif
1358
1359 static void
1360 setifmpklog(const char *vname, int value, int s, const struct afswtch *afp)
1361 {
1362 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1363 ifr.ifr_ifru.ifru_mpk_log = value;
1364
1365 if (ioctl(s, SIOCSIFMPKLOG, (caddr_t)&ifr) < 0)
1366 Perror(vname);
1367 }
1368
1369 void
1370 settimestamp(const char *vname, int value, int s, const struct afswtch *afp)
1371 {
1372 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1373
1374 if (value == 0) {
1375 if (ioctl(s, SIOCSIFTIMESTAMPDISABLE, (caddr_t)&ifr) < 0)
1376 Perror(vname);
1377 } else {
1378 if (ioctl(s, SIOCSIFTIMESTAMPENABLE, (caddr_t)&ifr) < 0)
1379 Perror(vname);
1380 }
1381 }
1382
1383 void
1384 setecnmode(const char *val, int dummy __unused, int s,
1385 const struct afswtch *afp)
1386 {
1387 char *cp;
1388
1389 if (strcmp(val, "default") == 0)
1390 ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DEFAULT;
1391 else if (strcmp(val, "enable") == 0)
1392 ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_ENABLE;
1393 else if (strcmp(val, "disable") == 0)
1394 ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DISABLE;
1395 else {
1396 ifr.ifr_ifru.ifru_ecn_mode = strtold(val, &cp);
1397 if (val == cp || errno != 0) {
1398 warn("Invalid ECN mode value '%s'", val);
1399 return;
1400 }
1401 }
1402
1403 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1404
1405 if (ioctl(s, SIOCSECNMODE, (caddr_t)&ifr) < 0)
1406 Perror("ioctl(SIOCSECNMODE)");
1407 }
1408
1409 void
1410 setprobeconnectivity(const char *vname, int value, int s, const struct afswtch *afp)
1411 {
1412 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1413 ifr.ifr_ifru.ifru_probe_connectivity = value;
1414
1415 if (ioctl(s, SIOCSIFPROBECONNECTIVITY, (caddr_t)&ifr) < 0)
1416 Perror(vname);
1417 }
1418
1419 #if defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED)
1420
1421 void
1422 setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1423 {
1424 u_long ioc;
1425
1426 #if (DEBUG | DEVELOPMENT)
1427 printf("%s(%s, %s)\n", __func__, cmd, arg);
1428 #endif /* (DEBUG | DEVELOPMENT) */
1429
1430 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1431
1432 if (strcmp(cmd, "mode") == 0) {
1433 ioc = SIOCSQOSMARKINGMODE;
1434
1435 if (strcmp(arg, "fastlane") == 0)
1436 ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE;
1437 else if (strcmp(arg, "rfc4594") == 0)
1438 ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_RFC4594;
1439 else if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "off") == 0)
1440 ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
1441 else
1442 err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
1443 } else if (strcmp(cmd, "enabled") == 0) {
1444 ioc = SIOCSQOSMARKINGENABLED;
1445 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1446 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1447 ifr.ifr_qosmarking_enabled = 1;
1448 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1449 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1450 ifr.ifr_qosmarking_enabled = 0;
1451 else
1452 err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
1453 } else {
1454 err(EX_USAGE, "qosmarking takes mode or enabled");
1455 }
1456
1457 if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
1458 err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
1459 }
1460
1461 void
1462 setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1463 {
1464 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1465
1466 warnx("### fastlane is obsolete, use qosmarking ###");
1467
1468 if (strcmp(cmd, "capable") == 0) {
1469 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1470 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1471 setqosmarking("mode", "fastlane", s, afp);
1472 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1473 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1474 setqosmarking("mode", "off", s, afp);
1475 else
1476 err(EX_USAGE, "bad value for fastlane %s", cmd);
1477 } else if (strcmp(cmd, "enable") == 0) {
1478 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1479 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1480 setqosmarking("enabled", "1", s, afp);
1481 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1482 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1483 setqosmarking("enabled", "0", s, afp);
1484 else
1485 err(EX_USAGE, "bad value for fastlane %s", cmd);
1486 } else {
1487 err(EX_USAGE, "fastlane takes capable or enable");
1488 }
1489 }
1490
1491 #else /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
1492
1493 void
1494 setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1495 {
1496 int value;
1497 u_long ioc;
1498
1499 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1500
1501 if (strcmp(cmd, "capable") == 0)
1502 ioc = SIOCSFASTLANECAPABLE;
1503 else if (strcmp(cmd, "enable") == 0)
1504 ioc = SIOCSFASTLEENABLED;
1505 else
1506 err(EX_USAGE, "fastlane takes capable or enabled");
1507
1508 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1509 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1510 value = 1;
1511 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1512 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1513 value = 0;
1514 else
1515 err(EX_USAGE, "bad value for fastlane %s", cmd);
1516
1517 if (ioc == SIOCSFASTLANECAPABLE)
1518 ifr.ifr_fastlane_capable = value;
1519 else
1520 ifr.ifr_fastlane_enabled = value;
1521
1522 if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
1523 err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
1524 }
1525
1526
1527 void
1528 setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
1529 {
1530 if (strcmp(cmd, "mode") == 0) {
1531 if (strcmp(arg, "fastlane") == 0)
1532 setfastlane("capable", "on", s, afp);
1533 else if (strcmp(arg, "none") == 0)
1534 setfastlane("capable", "off", s, afp);
1535 else
1536 err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
1537 } else if (strcmp(cmd, "enabled") == 0) {
1538 if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
1539 strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
1540 setfastlane("enable", "on", s, afp);
1541 else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
1542 strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
1543 setfastlane("enable", "off", s, afp);
1544 else
1545 err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
1546 } else {
1547 err(EX_USAGE, "qosmarking takes mode or enabled");
1548 }
1549 }
1550
1551 #endif /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
1552
1553 void
1554 setlowpowermode(const char *vname, int value, int s, const struct afswtch *afp)
1555 {
1556 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1557 ifr.ifr_low_power_mode = !!value;
1558
1559 if (ioctl(s, SIOCSIFLOWPOWER, (caddr_t)&ifr) < 0)
1560 Perror(vname);
1561 }
1562
1563 struct str2num {
1564 const char *str;
1565 uint32_t num;
1566 };
1567
1568 static struct str2num subfamily_str2num[] = {
1569 { .str = "any", .num = IFRTYPE_SUBFAMILY_ANY },
1570 { .str = "USB", .num = IFRTYPE_SUBFAMILY_USB },
1571 { .str = "Bluetooth", .num = IFRTYPE_SUBFAMILY_BLUETOOTH },
1572 { .str = "Wi-Fi", .num = IFRTYPE_SUBFAMILY_WIFI },
1573 { .str = "wifi", .num = IFRTYPE_SUBFAMILY_WIFI },
1574 { .str = "Thunderbolt", .num = IFRTYPE_SUBFAMILY_THUNDERBOLT },
1575 { .str = "reserverd", .num = IFRTYPE_SUBFAMILY_RESERVED },
1576 { .str = "intcoproc", .num = IFRTYPE_SUBFAMILY_INTCOPROC },
1577 { .str = "QuickRelay", .num = IFRTYPE_SUBFAMILY_QUICKRELAY },
1578 { .str = "Default", .num = IFRTYPE_SUBFAMILY_DEFAULT },
1579 { .str = NULL, .num = 0 },
1580 };
1581
1582 static uint32_t
1583 get_num_from_str(struct str2num* str2nums, const char *str)
1584 {
1585 struct str2num *str2num = str2nums;
1586
1587 while (str2num != NULL && str2num->str != NULL) {
1588 if (strcasecmp(str2num->str, str) == 0) {
1589 return str2num->num;
1590 }
1591 str2num++;
1592 }
1593 return 0;
1594 }
1595
1596 static void
1597 setifsubfamily(const char *val, int dummy __unused, int s,
1598 const struct afswtch *afp)
1599 {
1600 strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1601
1602 char *endptr;
1603 uint32_t subfamily = strtoul(val, &endptr, 0);
1604 if (*endptr != 0) {
1605 subfamily = get_num_from_str(subfamily_str2num, val);
1606 if (subfamily == 0) {
1607 return;
1608 }
1609 }
1610
1611 ifr.ifr_type.ift_subfamily = subfamily;
1612 if (ioctl(s, SIOCSIFSUBFAMILY, (caddr_t)&ifr) < 0)
1613 warn("ioctl(SIOCSIFSUBFAMILY)");
1614 }
1615
1616 void
1617 setifavailability(const char *vname, int value, int s, const struct afswtch *afp)
1618 {
1619 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1620 ifr.ifr_interface_state.valid_bitmask = IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID;
1621 if (value == 0) {
1622 ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE;
1623 } else {
1624 ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_AVAILABLE;
1625 }
1626 if (ioctl(s, SIOCSIFINTERFACESTATE, (caddr_t)&ifr) < 0)
1627 warn("ioctl(SIOCSIFINTERFACESTATE)");
1628 }
1629
1630
1631 #define IFFBITS \
1632 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
1633 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
1634 "\20MULTICAST"
1635
1636 #define IFEFBITS \
1637 "\020\1AUTOCONFIGURING\4PROBE_CONNECTIVITY\5FASTLN_CAP\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \
1638 "\12VLAN\13BOND\14ARPLL\15CLAT46\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \
1639 "\21ROUTER6\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \
1640 "\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\33CHANNEL_DRV\34CA" \
1641 "\35SENDLIST\36DIRECTLINK\37FASTLN_ON\40UPDOWNCHANGE"
1642
1643 #define IFXFBITS \
1644 "\020\1WOL\2TIMESTAMP\3NOAUTONX\4LEGACY\5TXLOWINET\6RXLOWINET\7ALLOCKPI" \
1645 "\10LOWPOWER\11MPKLOG\12CONSTRAINED"
1646
1647 #define IFCAPBITS \
1648 "\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \
1649 "\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS\13CHANNEL_IO\14HW_TIMESTAMP\15SW_TIMESTAMP" \
1650 "\16PARTIAL_CSUM\17ZEROINVERT_CSUM"
1651
1652 #define IFRLOGF_BITS \
1653 "\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE"
1654
1655 /*
1656 * Print the status of the interface. If an address family was
1657 * specified, show only it; otherwise, show them all.
1658 */
1659 static void
1660 status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
1661 struct ifaddrs *ifa)
1662 {
1663 struct ifaddrs *ift;
1664 int allfamilies, s;
1665 struct ifstat ifs;
1666 struct if_descreq ifdr;
1667 struct if_linkparamsreq iflpr;
1668 int mib[6];
1669 struct ifmibdata_supplemental ifmsupp;
1670 size_t miblen = sizeof(struct ifmibdata_supplemental);
1671 u_int64_t eflags = 0;
1672 u_int64_t xflags = 0;
1673 int curcap = 0;
1674
1675 if (afp == NULL) {
1676 allfamilies = 1;
1677 afp = af_getbyname("inet");
1678 } else
1679 allfamilies = 0;
1680
1681 ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
1682 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1683
1684 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
1685 if (s < 0)
1686 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
1687
1688 printf("%s: ", name);
1689 printb("flags", ifa->ifa_flags, IFFBITS);
1690 if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
1691 if (ifr.ifr_metric)
1692 printf(" metric %d", ifr.ifr_metric);
1693 if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
1694 printf(" mtu %d", ifr.ifr_mtu);
1695 if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1)
1696 printf(" rtref %d", ifr.ifr_route_refcnt);
1697 if (verbose) {
1698 unsigned int ifindex = if_nametoindex(ifa->ifa_name);
1699 if (ifindex != 0)
1700 printf(" index %u", ifindex);
1701 }
1702 #ifdef SIOCGIFCONSTRAINED
1703 // Constrained is stored in if_xflags which isn't exposed directly
1704 if (ioctl(s, SIOCGIFCONSTRAINED, (caddr_t)&ifr) == 0 &&
1705 ifr.ifr_constrained != 0) {
1706 printf(" constrained");
1707 }
1708 #endif
1709 putchar('\n');
1710
1711 if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 &&
1712 (eflags = ifr.ifr_eflags) != 0) {
1713 printb("\teflags", eflags, IFEFBITS);
1714 putchar('\n');
1715 }
1716
1717 if (verbose && ioctl(s, SIOCGIFXFLAGS, (caddr_t)&ifr) != -1 &&
1718 (xflags = ifr.ifr_xflags) != 0) {
1719 printb("\txflags", xflags, IFXFBITS);
1720 putchar('\n');
1721 }
1722
1723 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
1724 if (ifr.ifr_curcap != 0) {
1725 curcap = ifr.ifr_curcap;
1726 printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
1727 putchar('\n');
1728 }
1729 if (supmedia && ifr.ifr_reqcap != 0) {
1730 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
1731 putchar('\n');
1732 }
1733 }
1734
1735 tunnel_status(s);
1736
1737 for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
1738 if (ift->ifa_addr == NULL)
1739 continue;
1740 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
1741 continue;
1742 if (allfamilies) {
1743 const struct afswtch *p;
1744 p = af_getbyfamily(ift->ifa_addr->sa_family);
1745 if (p != NULL && p->af_status != NULL)
1746 p->af_status(s, ift);
1747 } else if (afp->af_af == ift->ifa_addr->sa_family)
1748 afp->af_status(s, ift);
1749 }
1750
1751 /* Print CLAT46 address */
1752 clat46_addr(s, name);
1753
1754 /* Print NAT64 prefix */
1755 nat64_status(s, name);
1756
1757 #if 0
1758 if (allfamilies || afp->af_af == AF_LINK) {
1759 const struct afswtch *lafp;
1760
1761 /*
1762 * Hack; the link level address is received separately
1763 * from the routing information so any address is not
1764 * handled above. Cobble together an entry and invoke
1765 * the status method specially.
1766 */
1767 lafp = af_getbyname("lladdr");
1768 if (lafp != NULL) {
1769 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
1770 lafp->af_status(s, &info);
1771 }
1772 }
1773 #endif
1774 if (allfamilies)
1775 af_other_status(s);
1776 else if (afp->af_other_status != NULL)
1777 afp->af_other_status(s);
1778
1779 strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
1780 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
1781 printf("%s", ifs.ascii);
1782
1783 /* The rest is for when verbose is set; if not set, we're done */
1784 if (!verbose)
1785 goto done;
1786
1787 if (ioctl(s, SIOCGIFTYPE, &ifr) != -1) {
1788 char *c = ift2str(ifr.ifr_type.ift_type,
1789 ifr.ifr_type.ift_family, ifr.ifr_type.ift_subfamily);
1790 if (c != NULL)
1791 printf("\ttype: %s\n", c);
1792 }
1793
1794 if (verbose > 1) {
1795 if (ioctl(s, SIOCGIFFUNCTIONALTYPE, &ifr) != -1) {
1796 char *c = iffunct2str(ifr.ifr_functional_type);
1797 if (c != NULL)
1798 printf("\tfunctional type: %s\n", c);
1799 }
1800 }
1801
1802 if (verbose > 0) {
1803 struct if_agentidsreq ifar;
1804 memset(&ifar, 0, sizeof(ifar));
1805
1806 strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
1807
1808 if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != -1) {
1809 if (ifar.ifar_count != 0) {
1810 ifar.ifar_uuids = calloc(ifar.ifar_count, sizeof(uuid_t));
1811 if (ifar.ifar_uuids != NULL) {
1812 if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != 1) {
1813 for (int agent_i = 0; agent_i < ifar.ifar_count; agent_i++) {
1814 struct netagent_req nar;
1815 memset(&nar, 0, sizeof(nar));
1816
1817 uuid_copy(nar.netagent_uuid, ifar.ifar_uuids[agent_i]);
1818
1819 if (ioctl(s, SIOCGIFAGENTDATA, &nar) != 1) {
1820 printf("\tagent domain:%s type:%s flags:0x%x desc:\"%s\"\n",
1821 nar.netagent_domain, nar.netagent_type,
1822 nar.netagent_flags, nar.netagent_desc);
1823 }
1824 }
1825 }
1826 free(ifar.ifar_uuids);
1827 }
1828 }
1829 }
1830 }
1831
1832 if (ioctl(s, SIOCGIFLINKQUALITYMETRIC, &ifr) != -1) {
1833 int lqm = ifr.ifr_link_quality_metric;
1834 if (verbose > 1) {
1835 printf("\tlink quality: %d ", lqm);
1836 if (lqm == IFNET_LQM_THRESH_OFF)
1837 printf("(off)");
1838 else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
1839 printf("(unknown)");
1840 else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
1841 lqm <= IFNET_LQM_THRESH_BAD)
1842 printf("(bad)");
1843 else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
1844 lqm <= IFNET_LQM_THRESH_POOR)
1845 printf("(poor)");
1846 else if (lqm > IFNET_LQM_THRESH_POOR &&
1847 lqm <= IFNET_LQM_THRESH_GOOD)
1848 printf("(good)");
1849 else
1850 printf("(?)");
1851 printf("\n");
1852 } else if (lqm > IFNET_LQM_THRESH_UNKNOWN) {
1853 printf("\tlink quality: %d ", lqm);
1854 if (lqm <= IFNET_LQM_THRESH_BAD)
1855 printf("(bad)");
1856 else if (lqm <= IFNET_LQM_THRESH_POOR)
1857 printf("(poor)");
1858 else if (lqm <= IFNET_LQM_THRESH_GOOD)
1859 printf("(good)");
1860 else
1861 printf("(?)");
1862 printf("\n");
1863 }
1864 }
1865
1866 if (verbose > 0) {
1867 if (ioctl(s, SIOCGIFINTERFACESTATE, &ifr) != -1) {
1868 printf("\tstate");
1869 if (ifr.ifr_interface_state.valid_bitmask &
1870 IF_INTERFACE_STATE_RRC_STATE_VALID) {
1871 uint8_t rrc_state = ifr.ifr_interface_state.rrc_state;
1872
1873 printf(" rrc: %u ", rrc_state);
1874 if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
1875 printf("(connected)");
1876 else if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_IDLE)
1877 printf("(idle)");
1878 else
1879 printf("(?)");
1880 }
1881 if (ifr.ifr_interface_state.valid_bitmask &
1882 IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
1883 uint8_t ifavail = ifr.ifr_interface_state.interface_availability;
1884
1885 printf(" availability: %u ", ifavail);
1886 if (ifavail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
1887 printf("(true)");
1888 else if (ifavail == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
1889 printf("(false)");
1890 else
1891 printf("(?)");
1892 } else {
1893 printf(" availability: (not valid)");
1894 }
1895 if (verbose > 1 &&
1896 ifr.ifr_interface_state.valid_bitmask &
1897 IF_INTERFACE_STATE_LQM_STATE_VALID) {
1898 int8_t lqm = ifr.ifr_interface_state.lqm_state;
1899
1900 printf(" lqm: %d", lqm);
1901
1902 if (lqm == IFNET_LQM_THRESH_OFF)
1903 printf("(off)");
1904 else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
1905 printf("(unknown)");
1906 else if (lqm == IFNET_LQM_THRESH_BAD)
1907 printf("(bad)");
1908 else if (lqm == IFNET_LQM_THRESH_POOR)
1909 printf("(poor)");
1910 else if (lqm == IFNET_LQM_THRESH_GOOD)
1911 printf("(good)");
1912 else
1913 printf("(?)");
1914 }
1915 }
1916 printf("\n");
1917 }
1918
1919 bzero(&iflpr, sizeof (iflpr));
1920 strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
1921 if (ioctl(s, SIOCGIFLINKPARAMS, &iflpr) != -1) {
1922 u_int64_t ibw_max = iflpr.iflpr_input_bw.max_bw;
1923 u_int64_t ibw_eff = iflpr.iflpr_input_bw.eff_bw;
1924 u_int64_t obw_max = iflpr.iflpr_output_bw.max_bw;
1925 u_int64_t obw_eff = iflpr.iflpr_output_bw.eff_bw;
1926 u_int64_t obw_tbr = iflpr.iflpr_output_tbr_rate;
1927 u_int32_t obw_pct = iflpr.iflpr_output_tbr_percent;
1928 u_int64_t ilt_max = iflpr.iflpr_input_lt.max_lt;
1929 u_int64_t ilt_eff = iflpr.iflpr_input_lt.eff_lt;
1930 u_int64_t olt_max = iflpr.iflpr_output_lt.max_lt;
1931 u_int64_t olt_eff = iflpr.iflpr_output_lt.eff_lt;
1932
1933
1934 if (eflags & IFEF_TXSTART) {
1935 u_int32_t flags = iflpr.iflpr_flags;
1936 u_int32_t sched = iflpr.iflpr_output_sched;
1937 struct if_throttlereq iftr;
1938
1939 printf("\tscheduler: %s%s ",
1940 (flags & IFLPRF_ALTQ) ? "ALTQ_" : "",
1941 sched2str(sched));
1942 if (flags & IFLPRF_DRVMANAGED)
1943 printf("(driver managed)");
1944 printf("\n");
1945
1946 bzero(&iftr, sizeof (iftr));
1947 strlcpy(iftr.ifthr_name, name,
1948 sizeof (iftr.ifthr_name));
1949 if (ioctl(s, SIOCGIFTHROTTLE, &iftr) != -1 &&
1950 iftr.ifthr_level != IFNET_THROTTLE_OFF)
1951 printf("\tthrottling: level %d (%s)\n",
1952 iftr.ifthr_level, tl2str(iftr.ifthr_level));
1953 }
1954
1955 if (obw_tbr != 0 && obw_eff > obw_tbr)
1956 obw_eff = obw_tbr;
1957
1958 if (ibw_max != 0 || obw_max != 0) {
1959 if (ibw_max == obw_max && ibw_eff == obw_eff &&
1960 ibw_max == ibw_eff && obw_tbr == 0) {
1961 printf("\tlink rate: %s\n",
1962 bps_to_str(ibw_max));
1963 } else {
1964 printf("\tuplink rate: %s [eff] / ",
1965 bps_to_str(obw_eff));
1966 if (obw_tbr != 0) {
1967 if (obw_pct == 0)
1968 printf("%s [tbr] / ",
1969 bps_to_str(obw_tbr));
1970 else
1971 printf("%s [tbr %u%%] / ",
1972 bps_to_str(obw_tbr),
1973 obw_pct);
1974 }
1975 printf("%s", bps_to_str(obw_max));
1976 if (obw_tbr != 0)
1977 printf(" [max]");
1978 printf("\n");
1979 if (ibw_eff == ibw_max) {
1980 printf("\tdownlink rate: %s\n",
1981 bps_to_str(ibw_max));
1982 } else {
1983 printf("\tdownlink rate: "
1984 "%s [eff] / ", bps_to_str(ibw_eff));
1985 printf("%s [max]\n",
1986 bps_to_str(ibw_max));
1987 }
1988 }
1989 } else if (obw_tbr != 0) {
1990 printf("\tuplink rate: %s [tbr]\n",
1991 bps_to_str(obw_tbr));
1992 }
1993
1994 if (ilt_max != 0 || olt_max != 0) {
1995 if (ilt_max == olt_max && ilt_eff == olt_eff &&
1996 ilt_max == ilt_eff) {
1997 printf("\tlink latency: %s\n",
1998 ns_to_str(ilt_max));
1999 } else {
2000 if (olt_max != 0 && olt_eff == olt_max) {
2001 printf("\tuplink latency: %s\n",
2002 ns_to_str(olt_max));
2003 } else if (olt_max != 0) {
2004 printf("\tuplink latency: "
2005 "%s [eff] / ", ns_to_str(olt_eff));
2006 printf("%s [max]\n",
2007 ns_to_str(olt_max));
2008 }
2009 if (ilt_max != 0 && ilt_eff == ilt_max) {
2010 printf("\tdownlink latency: %s\n",
2011 ns_to_str(ilt_max));
2012 } else if (ilt_max != 0) {
2013 printf("\tdownlink latency: "
2014 "%s [eff] / ", ns_to_str(ilt_eff));
2015 printf("%s [max]\n",
2016 ns_to_str(ilt_max));
2017 }
2018 }
2019 }
2020 }
2021
2022 /* Common OID prefix */
2023 mib[0] = CTL_NET;
2024 mib[1] = PF_LINK;
2025 mib[2] = NETLINK_GENERIC;
2026 mib[3] = IFMIB_IFDATA;
2027 mib[4] = if_nametoindex(name);
2028 mib[5] = IFDATA_SUPPLEMENTAL;
2029 if (sysctl(mib, 6, &ifmsupp, &miblen, (void *)0, 0) == -1)
2030 err(1, "sysctl IFDATA_SUPPLEMENTAL");
2031
2032 if (ifmsupp.ifmd_data_extended.ifi_alignerrs != 0) {
2033 printf("\tunaligned pkts: %llu\n",
2034 ifmsupp.ifmd_data_extended.ifi_alignerrs);
2035 }
2036 if (ifmsupp.ifmd_data_extended.ifi_dt_bytes != 0) {
2037 printf("\tdata milestone interval: %s\n",
2038 bytes_to_str(ifmsupp.ifmd_data_extended.ifi_dt_bytes));
2039 }
2040
2041 bzero(&ifdr, sizeof (ifdr));
2042 strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
2043 if (ioctl(s, SIOCGIFDESC, &ifdr) != -1 && ifdr.ifdr_len) {
2044 printf("\tdesc: %s\n", ifdr.ifdr_desc);
2045 }
2046
2047 if (ioctl(s, SIOCGIFLOG, &ifr) != -1 && ifr.ifr_log.ifl_level) {
2048 printf("\tlogging: level %d ", ifr.ifr_log.ifl_level);
2049 printb("facilities", ifr.ifr_log.ifl_flags, IFRLOGF_BITS);
2050 putchar('\n');
2051 }
2052
2053 if (ioctl(s, SIOCGIFDELEGATE, &ifr) != -1 && ifr.ifr_delegated) {
2054 char delegatedif[IFNAMSIZ+1];
2055 if (if_indextoname(ifr.ifr_delegated, delegatedif) != NULL)
2056 printf("\teffective interface: %s\n", delegatedif);
2057 }
2058
2059 if (ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) {
2060 if (ifr.ifr_start_delay_qlen > 0 &&
2061 ifr.ifr_start_delay_timeout > 0) {
2062 printf("\ttxstart qlen: %u packets "
2063 "timeout: %u microseconds\n",
2064 ifr.ifr_start_delay_qlen,
2065 ifr.ifr_start_delay_timeout/1000);
2066 }
2067 }
2068 #if defined(IFCAP_HW_TIMESTAMP) && defined(IFCAP_SW_TIMESTAMP)
2069 if ((curcap & (IFCAP_HW_TIMESTAMP | IFCAP_SW_TIMESTAMP)) &&
2070 ioctl(s, SIOCGIFTIMESTAMPENABLED, &ifr) != -1) {
2071 printf("\ttimestamp: %s\n",
2072 (ifr.ifr_intval != 0) ? "enabled" : "disabled");
2073 }
2074 #endif
2075 #if defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE)
2076 if (ioctl(s, SIOCGQOSMARKINGENABLED, &ifr) != -1) {
2077 printf("\tqosmarking enabled: %s mode: ",
2078 ifr.ifr_qosmarking_enabled ? "yes" : "no");
2079 if (ioctl(s, SIOCGQOSMARKINGMODE, &ifr) != -1) {
2080 switch (ifr.ifr_qosmarking_mode) {
2081 case IFRTYPE_QOSMARKING_FASTLANE:
2082 printf("fastlane\n");
2083 break;
2084 case IFRTYPE_QOSMARKING_RFC4594:
2085 printf("RFC4594\n");
2086 break;
2087 case IFRTYPE_QOSMARKING_MODE_NONE:
2088 printf("none\n");
2089 break;
2090 default:
2091 printf("unknown (%u)\n", ifr.ifr_qosmarking_mode);
2092 break;
2093 }
2094 }
2095 }
2096 #endif /* defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) */
2097
2098 if (verbose > 0 && ioctl(s, SIOCGIFLOWPOWER, &ifr) != -1) {
2099 printf("\tlow power mode: %s\n",
2100 (ifr.ifr_low_power_mode != 0) ? "enabled" : "disabled");
2101 }
2102 if (verbose > 0 && ioctl(s, SIOCGIFMPKLOG, &ifr) != -1) {
2103 printf("\tmulti layer packet logging (mpklog): %s\n",
2104 (ifr.ifr_mpk_log != 0) ? "enabled" : "disabled");
2105 }
2106 done:
2107 close(s);
2108 return;
2109 }
2110
2111 #define KILOBYTES 1024
2112 #define MEGABYTES (KILOBYTES * KILOBYTES)
2113 #define GIGABYTES (KILOBYTES * KILOBYTES * KILOBYTES)
2114
2115 static char *
2116 bytes_to_str(unsigned long long bytes)
2117 {
2118 static char buf[32];
2119 const char *u;
2120 long double n = bytes, t;
2121
2122 if (bytes >= GIGABYTES) {
2123 t = n / GIGABYTES;
2124 u = "GB";
2125 } else if (n >= MEGABYTES) {
2126 t = n / MEGABYTES;
2127 u = "MB";
2128 } else if (n >= KILOBYTES) {
2129 t = n / KILOBYTES;
2130 u = "KB";
2131 } else {
2132 t = n;
2133 u = "bytes";
2134 }
2135
2136 snprintf(buf, sizeof (buf), "%-4.2Lf %s", t, u);
2137 return (buf);
2138 }
2139
2140 #define GIGABIT_PER_SEC 1000000000 /* gigabit per second */
2141 #define MEGABIT_PER_SEC 1000000 /* megabit per second */
2142 #define KILOBIT_PER_SEC 1000 /* kilobit per second */
2143
2144 static char *
2145 bps_to_str(unsigned long long rate)
2146 {
2147 static char buf[32];
2148 const char *u;
2149 long double n = rate, t;
2150
2151 if (rate >= GIGABIT_PER_SEC) {
2152 t = n / GIGABIT_PER_SEC;
2153 u = "Gbps";
2154 } else if (n >= MEGABIT_PER_SEC) {
2155 t = n / MEGABIT_PER_SEC;
2156 u = "Mbps";
2157 } else if (n >= KILOBIT_PER_SEC) {
2158 t = n / KILOBIT_PER_SEC;
2159 u = "Kbps";
2160 } else {
2161 t = n;
2162 u = "bps ";
2163 }
2164
2165 snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
2166 return (buf);
2167 }
2168
2169 #define NSEC_PER_SEC 1000000000 /* nanosecond per second */
2170 #define USEC_PER_SEC 1000000 /* microsecond per second */
2171 #define MSEC_PER_SEC 1000 /* millisecond per second */
2172
2173 static char *
2174 ns_to_str(unsigned long long nsec)
2175 {
2176 static char buf[32];
2177 const char *u;
2178 long double n = nsec, t;
2179
2180 if (nsec >= NSEC_PER_SEC) {
2181 t = n / NSEC_PER_SEC;
2182 u = "sec ";
2183 } else if (n >= USEC_PER_SEC) {
2184 t = n / USEC_PER_SEC;
2185 u = "msec";
2186 } else if (n >= MSEC_PER_SEC) {
2187 t = n / MSEC_PER_SEC;
2188 u = "usec";
2189 } else {
2190 t = n;
2191 u = "nsec";
2192 }
2193
2194 snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
2195 return (buf);
2196 }
2197
2198 static void
2199 tunnel_status(int s)
2200 {
2201 af_all_tunnel_status(s);
2202 }
2203
2204 static void
2205 clat46_addr(int s, char * if_name)
2206 {
2207 struct if_clat46req ifr;
2208 char buf[MAXHOSTNAMELEN];
2209
2210 bzero(&ifr, sizeof (ifr));
2211 strlcpy(ifr.ifclat46_name, if_name, sizeof(ifr.ifclat46_name));
2212
2213 if (ioctl(s, SIOCGIFCLAT46ADDR, &ifr) < 0) {
2214 if (errno != ENOENT)
2215 syslog(LOG_WARNING, "ioctl (SIOCGIFCLAT46ADDR): %d", errno);
2216 return;
2217 }
2218
2219 if (inet_ntop(AF_INET6, &ifr.ifclat46_addr.v6_address, buf, sizeof(buf)) != NULL)
2220 printf("\tinet6 %s prefixlen %d clat46\n",
2221 buf, ifr.ifclat46_addr.v6_prefixlen);
2222 }
2223
2224 static void
2225 nat64_status(int s, char * if_name)
2226 {
2227 int i;
2228 struct if_nat64req ifr;
2229 char buf[MAXHOSTNAMELEN];
2230
2231 bzero(&ifr, sizeof(ifr));
2232 strlcpy(ifr.ifnat64_name, if_name, sizeof(ifr.ifnat64_name));
2233
2234 if (ioctl(s, SIOCGIFNAT64PREFIX, &ifr) < 0) {
2235 if (errno != ENOENT)
2236 syslog(LOG_WARNING, "ioctl(SIOCGIFNAT64PREFIX): %d", errno);
2237 return;
2238 }
2239
2240 for (i = 0; i < NAT64_MAX_NUM_PREFIXES; i++) {
2241 if (ifr.ifnat64_prefixes[i].prefix_len > 0) {
2242 inet_ntop(AF_INET6, &ifr.ifnat64_prefixes[i].ipv6_prefix, buf, sizeof(buf));
2243 printf("\tnat64 prefix %s prefixlen %d\n",
2244 buf, ifr.ifnat64_prefixes[i].prefix_len << 3);
2245 }
2246 }
2247 }
2248
2249 void
2250 Perror(const char *cmd)
2251 {
2252 switch (errno) {
2253
2254 case ENXIO:
2255 errx(1, "%s: no such interface", cmd);
2256 break;
2257
2258 case EPERM:
2259 errx(1, "%s: permission denied", cmd);
2260 break;
2261
2262 default:
2263 err(1, "%s", cmd);
2264 }
2265 }
2266
2267 /*
2268 * Print a value a la the %b format of the kernel's printf
2269 */
2270 void
2271 printb(const char *s, unsigned v, const char *bits)
2272 {
2273 int i, any = 0;
2274 char c;
2275
2276 if (bits && *bits == 8)
2277 printf("%s=%o", s, v);
2278 else
2279 printf("%s=%x", s, v);
2280 bits++;
2281 if (bits) {
2282 putchar('<');
2283 while ((i = *bits++) != '\0') {
2284 if (v & (1 << (i-1))) {
2285 if (any)
2286 putchar(',');
2287 any = 1;
2288 for (; (c = *bits) > 32; bits++)
2289 putchar(c);
2290 } else
2291 for (; *bits > 32; bits++)
2292 ;
2293 }
2294 putchar('>');
2295 }
2296 }
2297
2298 #ifndef __APPLE__
2299 void
2300 ifmaybeload(const char *name)
2301 {
2302 #define MOD_PREFIX_LEN 3 /* "if_" */
2303 struct module_stat mstat;
2304 int fileid, modid;
2305 char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
2306 const char *cp;
2307
2308 /* loading suppressed by the user */
2309 if (noload)
2310 return;
2311
2312 /* trim the interface number off the end */
2313 strlcpy(ifname, name, sizeof(ifname));
2314 for (dp = ifname; *dp != 0; dp++)
2315 if (isdigit(*dp)) {
2316 *dp = 0;
2317 break;
2318 }
2319
2320 /* turn interface and unit into module name */
2321 strlcpy(ifkind, "if_", sizeof(ifkind));
2322 strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
2323 sizeof(ifkind) - MOD_PREFIX_LEN);
2324
2325 /* scan files in kernel */
2326 mstat.version = sizeof(struct module_stat);
2327 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
2328 /* scan modules in file */
2329 for (modid = kldfirstmod(fileid); modid > 0;
2330 modid = modfnext(modid)) {
2331 if (modstat(modid, &mstat) < 0)
2332 continue;
2333 /* strip bus name if present */
2334 if ((cp = strchr(mstat.name, '/')) != NULL) {
2335 cp++;
2336 } else {
2337 cp = mstat.name;
2338 }
2339 /* already loaded? */
2340 if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
2341 strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
2342 return;
2343 }
2344 }
2345
2346 /* not present, we should try to load it */
2347 kldload(ifkind);
2348 }
2349 #endif
2350
2351 static struct cmd basic_cmds[] = {
2352 DEF_CMD("up", IFF_UP, setifflags),
2353 DEF_CMD("down", -IFF_UP, setifflags),
2354 DEF_CMD("arp", -IFF_NOARP, setifflags),
2355 DEF_CMD("-arp", IFF_NOARP, setifflags),
2356 DEF_CMD("debug", IFF_DEBUG, setifflags),
2357 DEF_CMD("-debug", -IFF_DEBUG, setifflags),
2358 #ifdef IFF_PPROMISC
2359 DEF_CMD("promisc", IFF_PPROMISC, setifflags),
2360 DEF_CMD("-promisc", -IFF_PPROMISC, setifflags),
2361 #endif /* IFF_PPROMISC */
2362 DEF_CMD("add", IFF_UP, notealias),
2363 DEF_CMD("alias", IFF_UP, notealias),
2364 DEF_CMD("-alias", -IFF_UP, notealias),
2365 DEF_CMD("delete", -IFF_UP, notealias),
2366 DEF_CMD("remove", -IFF_UP, notealias),
2367 #ifdef notdef
2368 #define EN_SWABIPS 0x1000
2369 DEF_CMD("swabips", EN_SWABIPS, setifflags),
2370 DEF_CMD("-swabips", -EN_SWABIPS, setifflags),
2371 #endif
2372 DEF_CMD_ARG("netmask", setifnetmask),
2373 DEF_CMD_ARG("metric", setifmetric),
2374 DEF_CMD_ARG("broadcast", setifbroadaddr),
2375 DEF_CMD_ARG("ipdst", setifipdst),
2376 DEF_CMD_ARG2("tunnel", settunnel),
2377 DEF_CMD("-tunnel", 0, deletetunnel),
2378 DEF_CMD("deletetunnel", 0, deletetunnel),
2379 DEF_CMD("link0", IFF_LINK0, setifflags),
2380 DEF_CMD("-link0", -IFF_LINK0, setifflags),
2381 DEF_CMD("link1", IFF_LINK1, setifflags),
2382 DEF_CMD("-link1", -IFF_LINK1, setifflags),
2383 DEF_CMD("link2", IFF_LINK2, setifflags),
2384 DEF_CMD("-link2", -IFF_LINK2, setifflags),
2385 #ifdef IFF_MONITOR
2386 DEF_CMD("monitor", IFF_MONITOR:, setifflags),
2387 DEF_CMD("-monitor", -IFF_MONITOR, setifflags),
2388 #endif /* IFF_MONITOR */
2389 DEF_CMD("mpklog", 1, setifmpklog),
2390 DEF_CMD("-mpklog", 0, setifmpklog),
2391 #ifdef IFF_STATICARP
2392 DEF_CMD("staticarp", IFF_STATICARP, setifflags),
2393 DEF_CMD("-staticarp", -IFF_STATICARP, setifflags),
2394 #endif /* IFF_STATICARP */
2395 #ifdef IFCAP_RXCSUM
2396 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
2397 DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap),
2398 #endif /* IFCAP_RXCSUM */
2399 #ifdef IFCAP_TXCSUM
2400 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
2401 DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap),
2402 #endif /* IFCAP_TXCSUM */
2403 #ifdef IFCAP_NETCONS
2404 DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
2405 DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap),
2406 #endif /* IFCAP_NETCONS */
2407 #ifdef IFCAP_POLLING
2408 DEF_CMD("polling", IFCAP_POLLING, setifcap),
2409 DEF_CMD("-polling", -IFCAP_POLLING, setifcap),
2410 #endif /* IFCAP_POLLING */
2411 #ifdef IFCAP_TSO
2412 DEF_CMD("tso", IFCAP_TSO, setifcap),
2413 DEF_CMD("-tso", -IFCAP_TSO, setifcap),
2414 #endif /* IFCAP_TSO */
2415 #ifdef IFCAP_LRO
2416 DEF_CMD("lro", IFCAP_LRO, setifcap),
2417 DEF_CMD("-lro", -IFCAP_LRO, setifcap),
2418 #endif /* IFCAP_LRO */
2419 #ifdef IFCAP_WOL
2420 DEF_CMD("wol", IFCAP_WOL, setifcap),
2421 DEF_CMD("-wol", -IFCAP_WOL, setifcap),
2422 #endif /* IFCAP_WOL */
2423 #ifdef IFCAP_WOL_UCAST
2424 DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap),
2425 DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap),
2426 #endif /* IFCAP_WOL_UCAST */
2427 #ifdef IFCAP_WOL_MCAST
2428 DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap),
2429 DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap),
2430 #endif /* IFCAP_WOL_MCAST */
2431 #ifdef IFCAP_WOL_MAGIC
2432 DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap),
2433 DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap),
2434 #endif /* IFCAP_WOL_MAGIC */
2435 DEF_CMD("normal", -IFF_LINK0, setifflags),
2436 DEF_CMD("compress", IFF_LINK0, setifflags),
2437 DEF_CMD("noicmp", IFF_LINK1, setifflags),
2438 DEF_CMD_ARG("mtu", setifmtu),
2439 #ifdef notdef
2440 DEF_CMD_ARG("name", setifname),
2441 #endif /* notdef */
2442 #ifdef IFCAP_AV
2443 DEF_CMD("av", IFCAP_AV, setifcap),
2444 DEF_CMD("-av", -IFCAP_AV, setifcap),
2445 #endif /* IFCAP_AV */
2446 DEF_CMD("router", 1, setrouter),
2447 DEF_CMD("-router", 0, setrouter),
2448 DEF_CMD_ARG("desc", setifdesc),
2449 DEF_CMD_ARG("tbr", settbr),
2450 DEF_CMD_VA("netem", setnetem),
2451 DEF_CMD_ARG("throttle", setthrottle),
2452 DEF_CMD_ARG("log", setlog),
2453 DEF_CMD("cl2k", 1, setcl2k),
2454 DEF_CMD("-cl2k", 0, setcl2k),
2455 DEF_CMD("expensive", 1, setexpensive),
2456 DEF_CMD("-expensive", 0, setexpensive),
2457 #ifdef SIOCSIFCONSTRAINED
2458 DEF_CMD("constrained", 1, setconstrained),
2459 DEF_CMD("-constrained", 0, setconstrained),
2460 #endif
2461 DEF_CMD("timestamp", 1, settimestamp),
2462 DEF_CMD("-timestamp", 0, settimestamp),
2463 DEF_CMD_ARG("ecn", setecnmode),
2464 DEF_CMD_ARG2("fastlane", setfastlane),
2465 DEF_CMD_ARG2("qosmarking", setqosmarking),
2466 DEF_CMD_ARG("disable_output", setdisableoutput),
2467 DEF_CMD("probe_connectivity", 1, setprobeconnectivity),
2468 DEF_CMD("-probe_connectivity", 0, setprobeconnectivity),
2469 DEF_CMD("lowpowermode", 1, setlowpowermode),
2470 DEF_CMD("-lowpowermode", 0, setlowpowermode),
2471 DEF_CMD_ARG("subfamily", setifsubfamily),
2472 DEF_CMD("available", 1, setifavailability),
2473 DEF_CMD("-available", 0, setifavailability),
2474 DEF_CMD("unavailable", 0, setifavailability),
2475 };
2476
2477 static __constructor void
2478 ifconfig_ctor(void)
2479 {
2480 #define N(a) (sizeof(a) / sizeof(a[0]))
2481 int i;
2482
2483 for (i = 0; i < N(basic_cmds); i++)
2484 cmd_register(&basic_cmds[i]);
2485 #undef N
2486 }
2487
2488 static char *
2489 sched2str(unsigned int s)
2490 {
2491 char *c;
2492
2493 switch (s) {
2494 case PKTSCHEDT_NONE:
2495 c = "NONE";
2496 break;
2497 case PKTSCHEDT_TCQ:
2498 c = "TCQ";
2499 break;
2500 case PKTSCHEDT_QFQ:
2501 c = "QFQ";
2502 break;
2503 case PKTSCHEDT_FQ_CODEL:
2504 c = "FQ_CODEL";
2505 break;
2506 default:
2507 c = "UNKNOWN";
2508 break;
2509 }
2510
2511 return (c);
2512 }
2513
2514 static char *
2515 tl2str(unsigned int s)
2516 {
2517 char *c;
2518
2519 switch (s) {
2520 case IFNET_THROTTLE_OFF:
2521 c = "off";
2522 break;
2523 case IFNET_THROTTLE_OPPORTUNISTIC:
2524 c = "opportunistic";
2525 break;
2526 default:
2527 c = "unknown";
2528 break;
2529 }
2530
2531 return (c);
2532 }
2533
2534 static char *
2535 ift2str(unsigned int t, unsigned int f, unsigned int sf)
2536 {
2537 static char buf[256];
2538 char *c = NULL;
2539
2540 switch (t) {
2541 case IFT_ETHER:
2542 switch (sf) {
2543 case IFRTYPE_SUBFAMILY_USB:
2544 c = "USB Ethernet";
2545 break;
2546 case IFRTYPE_SUBFAMILY_BLUETOOTH:
2547 c = "Bluetooth PAN";
2548 break;
2549 case IFRTYPE_SUBFAMILY_WIFI:
2550 c = "Wi-Fi";
2551 break;
2552 case IFRTYPE_SUBFAMILY_THUNDERBOLT:
2553 c = "IP over Thunderbolt";
2554 break;
2555 case IFRTYPE_SUBFAMILY_ANY:
2556 default:
2557 c = "Ethernet";
2558 break;
2559 }
2560 break;
2561
2562 case IFT_IEEE1394:
2563 c = "IP over FireWire";
2564 break;
2565
2566 case IFT_PKTAP:
2567 c = "Packet capture";
2568 break;
2569
2570 case IFT_CELLULAR:
2571 c = "Cellular";
2572 break;
2573
2574 case IFT_OTHER:
2575 if (ifr.ifr_type.ift_family == APPLE_IF_FAM_IPSEC) {
2576 if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_BLUETOOTH) {
2577 c = "Companion Link Bluetooth";
2578 } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_QUICKRELAY) {
2579 c = "Companion Link QuickRelay";
2580 } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_WIFI) {
2581 c = "Companion Link Wi-Fi";
2582 } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_DEFAULT) {
2583 c = "Companion Link Default";
2584 }
2585 }
2586 break;
2587
2588 case IFT_BRIDGE:
2589 case IFT_PFLOG:
2590 case IFT_PFSYNC:
2591 case IFT_PPP:
2592 case IFT_LOOP:
2593 case IFT_GIF:
2594 case IFT_STF:
2595 case IFT_L2VLAN:
2596 case IFT_IEEE8023ADLAG:
2597 default:
2598 break;
2599 }
2600
2601 if (verbose > 1) {
2602 if (c == NULL) {
2603 (void) snprintf(buf, sizeof (buf),
2604 "0x%x family: %u subfamily: %u",
2605 ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
2606 ifr.ifr_type.ift_subfamily);
2607 } else {
2608 (void) snprintf(buf, sizeof (buf),
2609 "%s (0x%x) family: %u subfamily: %u", c,
2610 ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
2611 ifr.ifr_type.ift_subfamily);
2612 }
2613 c = buf;
2614 }
2615
2616 return (c);
2617 }
2618
2619 static char *
2620 iffunct2str(u_int32_t functional_type)
2621 {
2622 char *str = NULL;
2623
2624 switch (functional_type) {
2625 case IFRTYPE_FUNCTIONAL_UNKNOWN:
2626 break;
2627
2628 case IFRTYPE_FUNCTIONAL_LOOPBACK:
2629 str = "loopback";
2630 break;
2631
2632 case IFRTYPE_FUNCTIONAL_WIRED:
2633 str = "wired";
2634 break;
2635
2636 case IFRTYPE_FUNCTIONAL_WIFI_INFRA:
2637 str = "wifi";
2638 break;
2639
2640 case IFRTYPE_FUNCTIONAL_WIFI_AWDL:
2641 str = "awdl";
2642 break;
2643
2644 case IFRTYPE_FUNCTIONAL_CELLULAR:
2645 str = "cellular";
2646 break;
2647
2648 case IFRTYPE_FUNCTIONAL_INTCOPROC:
2649 break;
2650
2651 case IFRTYPE_FUNCTIONAL_COMPANIONLINK:
2652 str = "companionlink";
2653 break;
2654
2655 default:
2656 break;
2657 }
2658 return str;
2659 }