Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ifconfig/ifconfig.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1983, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include <sys/param.h>
33
#include <sys/ioctl.h>
34
#ifdef JAIL
35
#include <sys/jail.h>
36
#endif
37
#include <sys/module.h>
38
#include <sys/linker.h>
39
#include <sys/nv.h>
40
#include <sys/queue.h>
41
#include <sys/socket.h>
42
#include <sys/time.h>
43
44
#include <net/ethernet.h>
45
#include <net/if.h>
46
#include <net/if_dl.h>
47
#include <net/if_strings.h>
48
#include <net/if_types.h>
49
#include <net/route.h>
50
51
/* IP */
52
#include <netinet/in.h>
53
#include <netinet/in_var.h>
54
#include <arpa/inet.h>
55
#include <netdb.h>
56
57
#include <fnmatch.h>
58
#include <ifaddrs.h>
59
#include <ctype.h>
60
#include <err.h>
61
#include <errno.h>
62
#include <fcntl.h>
63
#ifdef JAIL
64
#include <jail.h>
65
#endif
66
#include <stdbool.h>
67
#include <stdio.h>
68
#include <stdlib.h>
69
#include <string.h>
70
#include <unistd.h>
71
72
#include <libifconfig.h>
73
74
#include "ifconfig.h"
75
76
ifconfig_handle_t *lifh;
77
78
#ifdef WITHOUT_NETLINK
79
static char *descr = NULL;
80
static size_t descrlen = 64;
81
#endif
82
static int setaddr;
83
static int setmask;
84
static int doalias;
85
static int clearaddr;
86
static int newaddr = 1;
87
88
int exit_code = 0;
89
90
static char ifname_to_print[IFNAMSIZ]; /* Helper for printifnamemaybe() */
91
92
/* Formatter Strings */
93
char *f_inet, *f_inet6, *f_ether, *f_addr;
94
95
#ifdef WITHOUT_NETLINK
96
static void list_interfaces_ioctl(if_ctx *ctx);
97
static void status(if_ctx *ctx, const struct sockaddr_dl *sdl,
98
struct ifaddrs *ifa);
99
#endif
100
static _Noreturn void usage(void);
101
static void Perrorc(const char *cmd, int error);
102
103
static int getifflags(const char *ifname, int us, bool err_ok);
104
105
static struct afswtch *af_getbyname(const char *name);
106
107
static struct option *opts = NULL;
108
109
struct ifa_order_elt {
110
int if_order;
111
int af_orders[255];
112
struct ifaddrs *ifa;
113
TAILQ_ENTRY(ifa_order_elt) link;
114
};
115
116
TAILQ_HEAD(ifa_queue, ifa_order_elt);
117
118
static struct module_map_entry {
119
const char *ifname;
120
const char *kldname;
121
} module_map[] = {
122
{
123
.ifname = "tun",
124
.kldname = "if_tuntap",
125
},
126
{
127
.ifname = "tap",
128
.kldname = "if_tuntap",
129
},
130
{
131
.ifname = "vmnet",
132
.kldname = "if_tuntap",
133
},
134
{
135
.ifname = "ipsec",
136
.kldname = "ipsec",
137
},
138
{
139
/*
140
* This mapping exists because there is a conflicting enc module
141
* in CAM. ifconfig's guessing behavior will attempt to match
142
* the ifname to a module as well as if_${ifname} and clash with
143
* CAM enc. This is an assertion of the correct module to load.
144
*/
145
.ifname = "enc",
146
.kldname = "if_enc",
147
},
148
};
149
150
151
void
152
opt_register(struct option *p)
153
{
154
p->next = opts;
155
opts = p;
156
}
157
158
static void
159
usage(void)
160
{
161
char options[1024];
162
struct option *p;
163
164
/* XXX not right but close enough for now */
165
options[0] = '\0';
166
for (p = opts; p != NULL; p = p->next) {
167
strlcat(options, p->opt_usage, sizeof(options));
168
strlcat(options, " ", sizeof(options));
169
}
170
171
fprintf(stderr,
172
"usage: ifconfig [-j jail] [-f type:format] %sinterface address_family\n"
173
" [address [dest_address]] [parameters]\n"
174
" ifconfig [-j jail] interface create\n"
175
" ifconfig [-j jail] -a %s[-d] [-m] [-u] [-v] [address_family]\n"
176
" ifconfig [-j jail] -l [-d] [-u] [address_family]\n"
177
" ifconfig [-j jail] %s[-d] [-m] [-u] [-v]\n",
178
options, options, options);
179
exit(1);
180
}
181
182
static void
183
ifname_update(if_ctx *ctx, const char *name)
184
{
185
strlcpy(ctx->_ifname_storage_ioctl, name, sizeof(ctx->_ifname_storage_ioctl));
186
ctx->ifname = ctx->_ifname_storage_ioctl;
187
188
strlcpy(ifname_to_print, name, sizeof(ifname_to_print));
189
}
190
191
static void
192
ifr_set_name(struct ifreq *ifr, const char *name)
193
{
194
strlcpy(ifr->ifr_name, name, sizeof(ifr->ifr_name));
195
}
196
197
int
198
ioctl_ctx_ifr(if_ctx *ctx, unsigned long cmd, struct ifreq *ifr)
199
{
200
ifr_set_name(ifr, ctx->ifname);
201
return (ioctl_ctx(ctx, cmd, ifr));
202
}
203
204
void
205
ifcreate_ioctl(if_ctx *ctx, struct ifreq *ifr)
206
{
207
char ifname_orig[IFNAMSIZ];
208
209
strlcpy(ifname_orig, ifr->ifr_name, sizeof(ifname_orig));
210
211
if (ioctl(ctx->io_s, SIOCIFCREATE2, ifr) < 0) {
212
switch (errno) {
213
case EEXIST:
214
errx(1, "interface %s already exists", ifr->ifr_name);
215
default:
216
err(1, "SIOCIFCREATE2 (%s)", ifr->ifr_name);
217
}
218
}
219
220
if (strncmp(ifname_orig, ifr->ifr_name, sizeof(ifname_orig)) != 0)
221
ifname_update(ctx, ifr->ifr_name);
222
}
223
224
#ifdef WITHOUT_NETLINK
225
static int
226
calcorders(struct ifaddrs *ifa, struct ifa_queue *q)
227
{
228
struct ifaddrs *prev;
229
struct ifa_order_elt *cur;
230
unsigned int ord, af, ifa_ord;
231
232
prev = NULL;
233
cur = NULL;
234
ord = 0;
235
ifa_ord = 0;
236
237
while (ifa != NULL) {
238
if (prev == NULL ||
239
strcmp(ifa->ifa_name, prev->ifa_name) != 0) {
240
cur = calloc(1, sizeof(*cur));
241
242
if (cur == NULL)
243
return (-1);
244
245
TAILQ_INSERT_TAIL(q, cur, link);
246
cur->if_order = ifa_ord ++;
247
cur->ifa = ifa;
248
ord = 0;
249
}
250
251
if (ifa->ifa_addr) {
252
af = ifa->ifa_addr->sa_family;
253
254
if (af < nitems(cur->af_orders) &&
255
cur->af_orders[af] == 0)
256
cur->af_orders[af] = ++ord;
257
}
258
prev = ifa;
259
ifa = ifa->ifa_next;
260
}
261
262
return (0);
263
}
264
265
static int
266
cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q)
267
{
268
struct ifa_order_elt *cur, *e1, *e2;
269
unsigned int af1, af2;
270
int ret;
271
272
e1 = e2 = NULL;
273
274
ret = strcmp(a->ifa_name, b->ifa_name);
275
if (ret != 0) {
276
TAILQ_FOREACH(cur, q, link) {
277
if (e1 && e2)
278
break;
279
280
if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0)
281
e1 = cur;
282
else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0)
283
e2 = cur;
284
}
285
286
if (!e1 || !e2)
287
return (0);
288
else
289
return (e1->if_order - e2->if_order);
290
291
} else if (a->ifa_addr != NULL && b->ifa_addr != NULL) {
292
TAILQ_FOREACH(cur, q, link) {
293
if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) {
294
e1 = cur;
295
break;
296
}
297
}
298
299
if (!e1)
300
return (0);
301
302
af1 = a->ifa_addr->sa_family;
303
af2 = b->ifa_addr->sa_family;
304
305
if (af1 < nitems(e1->af_orders) && af2 < nitems(e1->af_orders))
306
return (e1->af_orders[af1] - e1->af_orders[af2]);
307
}
308
309
return (0);
310
}
311
#endif
312
313
static void freeformat(void)
314
{
315
316
free(f_inet);
317
free(f_inet6);
318
free(f_ether);
319
free(f_addr);
320
}
321
322
static void setformat(char *input)
323
{
324
char *formatstr, *category, *modifier;
325
326
formatstr = strdup(input);
327
while ((category = strsep(&formatstr, ",")) != NULL) {
328
modifier = strchr(category, ':');
329
if (modifier == NULL) {
330
if (strcmp(category, "default") == 0) {
331
freeformat();
332
} else if (strcmp(category, "cidr") == 0) {
333
free(f_inet);
334
f_inet = strdup(category);
335
free(f_inet6);
336
f_inet6 = strdup(category);
337
} else {
338
warnx("Skipping invalid format: %s\n",
339
category);
340
}
341
continue;
342
}
343
344
/* Split the string on the separator, then seek past it */
345
modifier[0] = '\0';
346
modifier++;
347
348
if (strcmp(category, "addr") == 0) {
349
free(f_addr);
350
f_addr = strdup(modifier);
351
} else if (strcmp(category, "ether") == 0) {
352
free(f_ether);
353
f_ether = strdup(modifier);
354
} else if (strcmp(category, "inet") == 0) {
355
free(f_inet);
356
f_inet = strdup(modifier);
357
} else if (strcmp(category, "inet6") == 0) {
358
free(f_inet6);
359
f_inet6 = strdup(modifier);
360
}
361
}
362
free(formatstr);
363
}
364
365
#ifdef WITHOUT_NETLINK
366
static struct ifaddrs *
367
sortifaddrs(struct ifaddrs *list,
368
int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *),
369
struct ifa_queue *q)
370
{
371
struct ifaddrs *right, *temp, *last, *result, *next, *tail;
372
373
right = list;
374
temp = list;
375
last = list;
376
result = NULL;
377
next = NULL;
378
tail = NULL;
379
380
if (!list || !list->ifa_next)
381
return (list);
382
383
while (temp && temp->ifa_next) {
384
last = right;
385
right = right->ifa_next;
386
temp = temp->ifa_next->ifa_next;
387
}
388
389
last->ifa_next = NULL;
390
391
list = sortifaddrs(list, compare, q);
392
right = sortifaddrs(right, compare, q);
393
394
while (list || right) {
395
396
if (!right) {
397
next = list;
398
list = list->ifa_next;
399
} else if (!list) {
400
next = right;
401
right = right->ifa_next;
402
} else if (compare(list, right, q) <= 0) {
403
next = list;
404
list = list->ifa_next;
405
} else {
406
next = right;
407
right = right->ifa_next;
408
}
409
410
if (!result)
411
result = next;
412
else
413
tail->ifa_next = next;
414
415
tail = next;
416
}
417
418
return (result);
419
}
420
#endif
421
422
static void
423
printifnamemaybe(void)
424
{
425
if (ifname_to_print[0] != '\0')
426
printf("%s\n", ifname_to_print);
427
}
428
429
static void
430
list_interfaces(if_ctx *ctx)
431
{
432
#ifdef WITHOUT_NETLINK
433
list_interfaces_ioctl(ctx);
434
#else
435
list_interfaces_nl(ctx->args);
436
#endif
437
}
438
439
static char *
440
args_peek(struct ifconfig_args *args)
441
{
442
if (args->argc > 0)
443
return (args->argv[0]);
444
return (NULL);
445
}
446
447
static char *
448
args_pop(struct ifconfig_args *args)
449
{
450
if (args->argc == 0)
451
return (NULL);
452
453
char *arg = args->argv[0];
454
455
args->argc--;
456
args->argv++;
457
458
return (arg);
459
}
460
461
static void
462
args_parse(struct ifconfig_args *args, int argc, char *argv[])
463
{
464
char options[1024];
465
struct option *p;
466
#ifdef JAIL
467
int jid;
468
#endif
469
int c;
470
471
/* Parse leading line options */
472
strlcpy(options, "G:adDf:j:klmnuv", sizeof(options));
473
for (p = opts; p != NULL; p = p->next)
474
strlcat(options, p->opt, sizeof(options));
475
while ((c = getopt(argc, argv, options)) != -1) {
476
switch (c) {
477
case 'a': /* scan all interfaces */
478
args->all = true;
479
break;
480
case 'd': /* restrict scan to "down" interfaces */
481
args->downonly = true;
482
break;
483
case 'D': /* Print driver name */
484
args->drivername = true;
485
break;
486
case 'f':
487
if (optarg == NULL)
488
usage();
489
setformat(optarg);
490
break;
491
case 'G':
492
if (optarg == NULL || args->all == 0)
493
usage();
494
args->nogroup = optarg;
495
break;
496
case 'j':
497
#ifdef JAIL
498
if (optarg == NULL)
499
usage();
500
jid = jail_getid(optarg);
501
if (jid == -1)
502
Perror("jail not found");
503
if (jail_attach(jid) != 0)
504
Perror("cannot attach to jail");
505
#else
506
Perror("not built with jail support");
507
#endif
508
break;
509
case 'k':
510
args->printkeys = true;
511
break;
512
case 'l': /* scan interface names only */
513
args->namesonly = true;
514
break;
515
case 'm': /* show media choices in status */
516
args->supmedia = true;
517
break;
518
case 'n': /* suppress module loading */
519
args->noload = true;
520
break;
521
case 'u': /* restrict scan to "up" interfaces */
522
args->uponly = true;
523
break;
524
case 'v':
525
args->verbose++;
526
break;
527
case 'g':
528
if (args->all) {
529
if (optarg == NULL)
530
usage();
531
args->matchgroup = optarg;
532
break;
533
}
534
/* FALLTHROUGH */
535
default:
536
for (p = opts; p != NULL; p = p->next)
537
if (p->opt[0] == c) {
538
p->cb(optarg);
539
break;
540
}
541
if (p == NULL)
542
usage();
543
break;
544
}
545
}
546
argc -= optind;
547
argv += optind;
548
549
/* -l cannot be used with -a or -m */
550
if (args->namesonly && (args->all || args->supmedia))
551
usage();
552
553
/* nonsense.. */
554
if (args->uponly && args->downonly)
555
usage();
556
557
/* no arguments is equivalent to '-a' */
558
if (!args->namesonly && argc < 1)
559
args->all = 1;
560
561
/* -a and -l allow an address family arg to limit the output */
562
if (args->all || args->namesonly) {
563
if (argc > 1)
564
usage();
565
566
if (argc == 1) {
567
const struct afswtch *afp = af_getbyname(*argv);
568
569
if (afp == NULL) {
570
warnx("Address family '%s' unknown.", *argv);
571
usage();
572
}
573
if (afp->af_name != NULL)
574
argc--, argv++;
575
/* leave with afp non-zero */
576
args->afp = afp;
577
}
578
} else {
579
/* not listing, need an argument */
580
if (argc < 1)
581
usage();
582
}
583
584
args->argc = argc;
585
args->argv = argv;
586
}
587
588
static int
589
ifconfig(if_ctx *ctx, int iscreate, const struct afswtch *uafp)
590
{
591
#ifdef WITHOUT_NETLINK
592
return (ifconfig_ioctl(ctx, iscreate, uafp));
593
#else
594
return (ifconfig_nl(ctx, iscreate, uafp));
595
#endif
596
}
597
598
static bool
599
isargcreate(const char *arg)
600
{
601
if (arg == NULL)
602
return (false);
603
604
if (strcmp(arg, "create") == 0 || strcmp(arg, "plumb") == 0)
605
return (true);
606
607
return (false);
608
}
609
610
static bool
611
isnametoolong(const char *ifname)
612
{
613
return (strlen(ifname) >= IFNAMSIZ);
614
}
615
616
int
617
main(int ac, char *av[])
618
{
619
char *envformat;
620
int flags;
621
struct ifconfig_args _args = {};
622
struct ifconfig_args *args = &_args;
623
624
struct ifconfig_context ctx = {
625
.args = args,
626
.io_s = -1,
627
};
628
629
lifh = ifconfig_open();
630
if (lifh == NULL)
631
err(EXIT_FAILURE, "ifconfig_open");
632
633
envformat = getenv("IFCONFIG_FORMAT");
634
if (envformat != NULL)
635
setformat(envformat);
636
637
/*
638
* Ensure we print interface name when expected to,
639
* even if we terminate early due to error.
640
*/
641
atexit(printifnamemaybe);
642
643
args_parse(args, ac, av);
644
645
if (!args->all && !args->namesonly) {
646
/* not listing, need an argument */
647
args->ifname = args_pop(args);
648
ctx.ifname = args->ifname;
649
650
/* check and maybe load support for this interface */
651
ifmaybeload(args, args->ifname);
652
653
char *arg = args_peek(args);
654
if (if_nametoindex(args->ifname) == 0) {
655
/*
656
* NOTE: We must special-case the `create' command
657
* right here as we would otherwise fail when trying
658
* to find the interface.
659
*/
660
if (isargcreate(arg)) {
661
if (isnametoolong(args->ifname))
662
errx(1, "%s: cloning name too long",
663
args->ifname);
664
ifconfig(&ctx, 1, NULL);
665
exit(exit_code);
666
}
667
#ifdef JAIL
668
/*
669
* NOTE: We have to special-case the `-vnet' command
670
* right here as we would otherwise fail when trying
671
* to find the interface as it lives in another vnet.
672
*/
673
if (arg != NULL && (strcmp(arg, "-vnet") == 0)) {
674
if (isnametoolong(args->ifname))
675
errx(1, "%s: interface name too long",
676
args->ifname);
677
ifconfig(&ctx, 0, NULL);
678
exit(exit_code);
679
}
680
#endif
681
errx(1, "interface %s does not exist", args->ifname);
682
} else {
683
/*
684
* Do not allow use `create` command as hostname if
685
* address family is not specified.
686
*/
687
if (isargcreate(arg)) {
688
if (args->argc == 1)
689
errx(1, "interface %s already exists",
690
args->ifname);
691
args_pop(args);
692
}
693
}
694
}
695
696
/* Check for address family */
697
if (args->argc > 0) {
698
args->afp = af_getbyname(args_peek(args));
699
if (args->afp != NULL)
700
args_pop(args);
701
}
702
703
/*
704
* Check for a requested configuration action on a single interface,
705
* which doesn't require building, sorting, and searching the entire
706
* system address list
707
*/
708
if ((args->argc > 0) && (args->ifname != NULL)) {
709
if (isnametoolong(args->ifname))
710
warnx("%s: interface name too long, skipping", args->ifname);
711
else {
712
flags = getifflags(args->ifname, -1, false);
713
if (!(((flags & IFF_CANTCONFIG) != 0) ||
714
(args->downonly && (flags & IFF_UP) != 0) ||
715
(args->uponly && (flags & IFF_UP) == 0)))
716
ifconfig(&ctx, 0, args->afp);
717
}
718
goto done;
719
}
720
721
args->allfamilies = args->afp == NULL;
722
723
list_interfaces(&ctx);
724
725
done:
726
freeformat();
727
ifconfig_close(lifh);
728
exit(exit_code);
729
}
730
731
bool
732
match_ether(const struct sockaddr_dl *sdl)
733
{
734
switch (sdl->sdl_type) {
735
case IFT_ETHER:
736
case IFT_L2VLAN:
737
case IFT_BRIDGE:
738
if (sdl->sdl_alen == ETHER_ADDR_LEN)
739
return (true);
740
default:
741
return (false);
742
}
743
}
744
745
bool
746
match_if_flags(struct ifconfig_args *args, int if_flags)
747
{
748
if ((if_flags & IFF_CANTCONFIG) != 0)
749
return (false);
750
if (args->downonly && (if_flags & IFF_UP) != 0)
751
return (false);
752
if (args->uponly && (if_flags & IFF_UP) == 0)
753
return (false);
754
return (true);
755
}
756
757
#ifdef WITHOUT_NETLINK
758
static bool
759
match_afp(const struct afswtch *afp, int sa_family, const struct sockaddr_dl *sdl)
760
{
761
if (afp == NULL)
762
return (true);
763
/* special case for "ether" address family */
764
if (!strcmp(afp->af_name, "ether")) {
765
if (sdl == NULL || !match_ether(sdl))
766
return (false);
767
return (true);
768
}
769
return (afp->af_af == sa_family);
770
}
771
772
static void
773
list_interfaces_ioctl(if_ctx *ctx)
774
{
775
struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q);
776
struct ifaddrs *ifap, *sifap, *ifa;
777
struct ifa_order_elt *cur, *tmp;
778
char *namecp = NULL;
779
int ifindex;
780
struct ifconfig_args *args = ctx->args;
781
782
if (getifaddrs(&ifap) != 0)
783
err(EXIT_FAILURE, "getifaddrs");
784
785
char *cp = NULL;
786
787
if (calcorders(ifap, &q) != 0)
788
err(EXIT_FAILURE, "calcorders");
789
790
sifap = sortifaddrs(ifap, cmpifaddrs, &q);
791
792
TAILQ_FOREACH_SAFE(cur, &q, link, tmp)
793
free(cur);
794
795
ifindex = 0;
796
for (ifa = sifap; ifa; ifa = ifa->ifa_next) {
797
struct ifreq paifr = {};
798
const struct sockaddr_dl *sdl;
799
800
strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
801
if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
802
memcpy(&paifr.ifr_addr, ifa->ifa_addr,
803
ifa->ifa_addr->sa_len);
804
}
805
806
if (args->ifname != NULL && strcmp(args->ifname, ifa->ifa_name) != 0)
807
continue;
808
if (ifa->ifa_addr->sa_family == AF_LINK)
809
sdl = satosdl_c(ifa->ifa_addr);
810
else
811
sdl = NULL;
812
if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !args->namesonly)
813
continue;
814
if (isnametoolong(ifa->ifa_name)) {
815
warnx("%s: interface name too long, skipping",
816
ifa->ifa_name);
817
continue;
818
}
819
cp = ifa->ifa_name;
820
821
if (!match_if_flags(args, ifa->ifa_flags))
822
continue;
823
if (!group_member(ifa->ifa_name, args->matchgroup, args->nogroup))
824
continue;
825
ctx->ifname = cp;
826
/*
827
* Are we just listing the interfaces?
828
*/
829
if (args->namesonly) {
830
if (namecp == cp)
831
continue;
832
if (!match_afp(args->afp, ifa->ifa_addr->sa_family, sdl))
833
continue;
834
namecp = cp;
835
ifindex++;
836
if (ifindex > 1)
837
printf(" ");
838
fputs(cp, stdout);
839
continue;
840
}
841
ifindex++;
842
843
if (args->argc > 0)
844
ifconfig(ctx, 0, args->afp);
845
else
846
status(ctx, sdl, ifa);
847
}
848
if (args->namesonly)
849
printf("\n");
850
freeifaddrs(ifap);
851
}
852
#endif
853
854
/*
855
* Returns true if an interface should be listed because any its groups
856
* matches shell pattern "match" and none of groups matches pattern "nomatch".
857
* If any pattern is NULL, corresponding condition is skipped.
858
*/
859
bool
860
group_member(const char *ifname, const char *match, const char *nomatch)
861
{
862
static int sock = -1;
863
864
struct ifgroupreq ifgr;
865
struct ifg_req *ifg;
866
unsigned int len;
867
bool matched, nomatched;
868
869
/* Sanity checks. */
870
if (match == NULL && nomatch == NULL)
871
return (true);
872
if (ifname == NULL)
873
return (false);
874
875
memset(&ifgr, 0, sizeof(ifgr));
876
strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
877
878
/* The socket is opened once. Let _exit() close it. */
879
if (sock == -1) {
880
sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
881
if (sock == -1)
882
errx(1, "%s: socket(AF_LOCAL,SOCK_DGRAM)", __func__);
883
}
884
885
/* Determine amount of memory for the list of groups. */
886
if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
887
if (errno == EINVAL || errno == ENOTTY)
888
return (false);
889
else
890
errx(1, "%s: SIOCGIFGROUP", __func__);
891
}
892
893
/* Obtain the list of groups. */
894
len = ifgr.ifgr_len;
895
ifgr.ifgr_groups =
896
(struct ifg_req *)calloc(len / sizeof(*ifg), sizeof(*ifg));
897
898
if (ifgr.ifgr_groups == NULL)
899
errx(1, "%s: no memory", __func__);
900
if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
901
errx(1, "%s: SIOCGIFGROUP", __func__);
902
903
/* Perform matching. */
904
matched = false;
905
nomatched = true;
906
for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(*ifg); ifg++) {
907
len -= sizeof(*ifg);
908
if (match && !matched)
909
matched = !fnmatch(match, ifg->ifgrq_group, 0);
910
if (nomatch && nomatched)
911
nomatched = fnmatch(nomatch, ifg->ifgrq_group, 0);
912
}
913
free(ifgr.ifgr_groups);
914
915
if (match && !nomatch)
916
return (matched);
917
if (!match && nomatch)
918
return (nomatched);
919
return (matched && nomatched);
920
}
921
922
static struct afswtch *afs = NULL;
923
924
void
925
af_register(struct afswtch *p)
926
{
927
p->af_next = afs;
928
afs = p;
929
}
930
931
static struct afswtch *
932
af_getbyname(const char *name)
933
{
934
struct afswtch *afp;
935
936
for (afp = afs; afp != NULL; afp = afp->af_next)
937
if (strcmp(afp->af_name, name) == 0)
938
return afp;
939
return NULL;
940
}
941
942
struct afswtch *
943
af_getbyfamily(int af)
944
{
945
struct afswtch *afp;
946
947
for (afp = afs; afp != NULL; afp = afp->af_next)
948
if (afp->af_af == af)
949
return afp;
950
return NULL;
951
}
952
953
void
954
af_other_status(if_ctx *ctx)
955
{
956
struct afswtch *afp;
957
uint8_t afmask[howmany(AF_MAX, NBBY)];
958
959
memset(afmask, 0, sizeof(afmask));
960
for (afp = afs; afp != NULL; afp = afp->af_next) {
961
if (afp->af_other_status == NULL)
962
continue;
963
if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
964
continue;
965
afp->af_other_status(ctx);
966
setbit(afmask, afp->af_af);
967
}
968
}
969
970
static void
971
af_all_tunnel_status(if_ctx *ctx)
972
{
973
struct afswtch *afp;
974
uint8_t afmask[howmany(AF_MAX, NBBY)];
975
976
memset(afmask, 0, sizeof(afmask));
977
for (afp = afs; afp != NULL; afp = afp->af_next) {
978
if (afp->af_status_tunnel == NULL)
979
continue;
980
if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
981
continue;
982
afp->af_status_tunnel(ctx);
983
setbit(afmask, afp->af_af);
984
}
985
}
986
987
static struct cmd *cmds = NULL;
988
989
void
990
cmd_register(struct cmd *p)
991
{
992
p->c_next = cmds;
993
cmds = p;
994
}
995
996
static const struct cmd *
997
cmd_lookup(const char *name, int iscreate)
998
{
999
const struct cmd *p;
1000
1001
for (p = cmds; p != NULL; p = p->c_next)
1002
if (strcmp(name, p->c_name) == 0) {
1003
if (iscreate) {
1004
if (p->c_iscloneop)
1005
return p;
1006
} else {
1007
if (!p->c_iscloneop)
1008
return p;
1009
}
1010
}
1011
return NULL;
1012
}
1013
1014
struct callback {
1015
callback_func *cb_func;
1016
void *cb_arg;
1017
struct callback *cb_next;
1018
};
1019
static struct callback *callbacks = NULL;
1020
1021
void
1022
callback_register(callback_func *func, void *arg)
1023
{
1024
struct callback *cb;
1025
1026
cb = malloc(sizeof(struct callback));
1027
if (cb == NULL)
1028
errx(1, "unable to allocate memory for callback");
1029
cb->cb_func = func;
1030
cb->cb_arg = arg;
1031
cb->cb_next = callbacks;
1032
callbacks = cb;
1033
}
1034
1035
/* specially-handled commands */
1036
static void setifaddr(if_ctx *ctx, const char *addr, int param);
1037
static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
1038
1039
static void setifdstaddr(if_ctx *ctx, const char *addr, int param __unused);
1040
static const struct cmd setifdstaddr_cmd =
1041
DEF_CMD("ifdstaddr", 0, setifdstaddr);
1042
1043
int
1044
af_exec_ioctl(if_ctx *ctx, unsigned long action, void *data)
1045
{
1046
struct ifreq *req = (struct ifreq *)data;
1047
1048
strlcpy(req->ifr_name, ctx->ifname, sizeof(req->ifr_name));
1049
if (ioctl_ctx(ctx, action, req) == 0)
1050
return (0);
1051
return (errno);
1052
}
1053
1054
static void
1055
delifaddr(if_ctx *ctx, const struct afswtch *afp)
1056
{
1057
int error;
1058
1059
if (afp->af_exec == NULL) {
1060
warnx("interface %s cannot change %s addresses!",
1061
ctx->ifname, afp->af_name);
1062
clearaddr = 0;
1063
return;
1064
}
1065
1066
error = afp->af_exec(ctx, afp->af_difaddr, afp->af_ridreq);
1067
if (error != 0) {
1068
if (error == EADDRNOTAVAIL && (doalias >= 0)) {
1069
/* means no previous address for interface */
1070
} else
1071
Perrorc("ioctl (SIOCDIFADDR)", error);
1072
}
1073
}
1074
1075
static void
1076
addifaddr(if_ctx *ctx, const struct afswtch *afp)
1077
{
1078
if (afp->af_exec == NULL) {
1079
warnx("interface %s cannot change %s addresses!",
1080
ctx->ifname, afp->af_name);
1081
newaddr = 0;
1082
return;
1083
}
1084
1085
if (setaddr || setmask) {
1086
int error = afp->af_exec(ctx, afp->af_aifaddr, afp->af_addreq);
1087
if (error != 0)
1088
Perrorc("ioctl (SIOCAIFADDR)", error);
1089
}
1090
}
1091
1092
int
1093
ifconfig_ioctl(if_ctx *orig_ctx, int iscreate, const struct afswtch *uafp)
1094
{
1095
const struct afswtch *afp, *nafp;
1096
const struct cmd *p;
1097
struct callback *cb;
1098
int s;
1099
int argc = orig_ctx->args->argc;
1100
char *const *argv = orig_ctx->args->argv;
1101
struct ifconfig_context _ctx = {
1102
.args = orig_ctx->args,
1103
.io_ss = orig_ctx->io_ss,
1104
.ifname = orig_ctx->ifname,
1105
};
1106
struct ifconfig_context *ctx = &_ctx;
1107
1108
struct ifreq ifr = {};
1109
strlcpy(ifr.ifr_name, ctx->ifname, sizeof ifr.ifr_name);
1110
afp = NULL;
1111
if (uafp != NULL)
1112
afp = uafp;
1113
/*
1114
* This is the historical "accident" allowing users to configure IPv4
1115
* addresses without the "inet" keyword which while a nice feature has
1116
* proven to complicate other things. We cannot remove this but only
1117
* make sure we will never have a similar implicit default for IPv6 or
1118
* any other address familiy. We need a fallback though for
1119
* ifconfig IF up/down etc. to work without INET support as people
1120
* never used ifconfig IF link up/down, etc. either.
1121
*/
1122
#ifndef RESCUE
1123
#ifdef INET
1124
if (afp == NULL && feature_present("inet"))
1125
afp = af_getbyname("inet");
1126
#endif
1127
#endif
1128
if (afp == NULL)
1129
afp = af_getbyname("link");
1130
if (afp == NULL) {
1131
warnx("Please specify an address_family.");
1132
usage();
1133
}
1134
1135
top:
1136
ifr.ifr_addr.sa_family =
1137
afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
1138
AF_LOCAL : afp->af_af;
1139
1140
if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
1141
(uafp != NULL || errno != EAFNOSUPPORT ||
1142
(s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
1143
err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
1144
1145
ctx->io_s = s;
1146
ctx->afp = afp;
1147
1148
while (argc > 0) {
1149
p = cmd_lookup(*argv, iscreate);
1150
if (iscreate && p == NULL) {
1151
/*
1152
* Push the clone create callback so the new
1153
* device is created and can be used for any
1154
* remaining arguments.
1155
*/
1156
cb = callbacks;
1157
if (cb == NULL)
1158
errx(1, "internal error, no callback");
1159
callbacks = cb->cb_next;
1160
cb->cb_func(ctx, cb->cb_arg);
1161
iscreate = 0;
1162
/*
1163
* Handle any address family spec that
1164
* immediately follows and potentially
1165
* recreate the socket.
1166
*/
1167
nafp = af_getbyname(*argv);
1168
if (nafp != NULL) {
1169
argc--, argv++;
1170
if (nafp != afp) {
1171
close(s);
1172
afp = nafp;
1173
goto top;
1174
}
1175
}
1176
/*
1177
* Look for a normal parameter.
1178
*/
1179
continue;
1180
}
1181
if (p == NULL) {
1182
/*
1183
* Not a recognized command, choose between setting
1184
* the interface address and the dst address.
1185
*/
1186
p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
1187
}
1188
if (p->c_parameter == NEXTARG && p->c_u.c_func) {
1189
if (argv[1] == NULL)
1190
errx(1, "'%s' requires argument",
1191
p->c_name);
1192
p->c_u.c_func(ctx, argv[1], 0);
1193
argc--, argv++;
1194
} else if (p->c_parameter == OPTARG && p->c_u.c_func) {
1195
p->c_u.c_func(ctx, argv[1], 0);
1196
if (argv[1] != NULL)
1197
argc--, argv++;
1198
} else if (p->c_parameter == NEXTARG2 && p->c_u.c_func2) {
1199
if (argc < 3)
1200
errx(1, "'%s' requires 2 arguments",
1201
p->c_name);
1202
p->c_u.c_func2(ctx, argv[1], argv[2]);
1203
argc -= 2, argv += 2;
1204
} else if (p->c_parameter == SPARAM && p->c_u.c_func3) {
1205
p->c_u.c_func3(ctx, *argv, p->c_sparameter);
1206
} else if (p->c_parameter == ARGVECTOR && p->c_u.c_funcv) {
1207
int argsdone;
1208
1209
argsdone = p->c_u.c_funcv(ctx, argc - 1,
1210
(const char *const *)argv + 1);
1211
argc -= argsdone;
1212
argv += argsdone;
1213
} else if (p->c_u.c_func)
1214
p->c_u.c_func(ctx, *argv, p->c_parameter);
1215
argc--, argv++;
1216
}
1217
1218
/*
1219
* Do any post argument processing required by the address family.
1220
*/
1221
if (afp->af_postproc != NULL)
1222
afp->af_postproc(ctx, newaddr, getifflags(ctx->ifname, s, true));
1223
/*
1224
* Do deferred callbacks registered while processing
1225
* command-line arguments.
1226
*/
1227
for (cb = callbacks; cb != NULL; cb = cb->cb_next)
1228
cb->cb_func(ctx, cb->cb_arg);
1229
/*
1230
* Do deferred operations.
1231
*/
1232
if (clearaddr)
1233
delifaddr(ctx, afp);
1234
if (newaddr)
1235
addifaddr(ctx, afp);
1236
1237
close(s);
1238
return(0);
1239
}
1240
1241
static void
1242
setifaddr(if_ctx *ctx, const char *addr, int param __unused)
1243
{
1244
const struct afswtch *afp = ctx->afp;
1245
1246
if (afp->af_getaddr == NULL)
1247
return;
1248
/*
1249
* Delay the ioctl to set the interface addr until flags are all set.
1250
* The address interpretation may depend on the flags,
1251
* and the flags may change when the address is set.
1252
*/
1253
setaddr++;
1254
if (doalias == 0 && afp->af_af != AF_LINK)
1255
clearaddr = 1;
1256
afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
1257
}
1258
1259
static void
1260
settunnel(if_ctx *ctx, const char *src, const char *dst)
1261
{
1262
const struct afswtch *afp = ctx->afp;
1263
struct addrinfo *srcres, *dstres;
1264
int ecode;
1265
1266
if (afp->af_settunnel == NULL) {
1267
warn("address family %s does not support tunnel setup",
1268
afp->af_name);
1269
return;
1270
}
1271
1272
if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
1273
errx(1, "error in parsing address string: %s",
1274
gai_strerror(ecode));
1275
1276
if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
1277
errx(1, "error in parsing address string: %s",
1278
gai_strerror(ecode));
1279
1280
if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
1281
errx(1,
1282
"source and destination address families do not match");
1283
1284
afp->af_settunnel(ctx, srcres, dstres);
1285
1286
freeaddrinfo(srcres);
1287
freeaddrinfo(dstres);
1288
}
1289
1290
static void
1291
deletetunnel(if_ctx *ctx, const char *vname __unused, int param __unused)
1292
{
1293
struct ifreq ifr = {};
1294
1295
if (ioctl_ctx_ifr(ctx, SIOCDIFPHYADDR, &ifr) < 0)
1296
err(1, "SIOCDIFPHYADDR");
1297
}
1298
1299
#ifdef JAIL
1300
static void
1301
setifvnet(if_ctx *ctx, const char *jname, int dummy __unused)
1302
{
1303
struct ifreq ifr = {};
1304
1305
ifr.ifr_jid = jail_getid(jname);
1306
if (ifr.ifr_jid < 0)
1307
errx(1, "%s", jail_errmsg);
1308
if (ioctl_ctx_ifr(ctx, SIOCSIFVNET, &ifr) < 0)
1309
err(1, "SIOCSIFVNET");
1310
}
1311
1312
static void
1313
setifrvnet(if_ctx *ctx, const char *jname, int dummy __unused)
1314
{
1315
struct ifreq ifr = {};
1316
1317
ifr.ifr_jid = jail_getid(jname);
1318
if (ifr.ifr_jid < 0)
1319
errx(1, "%s", jail_errmsg);
1320
if (ioctl_ctx_ifr(ctx, SIOCSIFRVNET, &ifr) < 0)
1321
err(1, "SIOCSIFRVNET(%d, %s)", ifr.ifr_jid, ifr.ifr_name);
1322
}
1323
#endif
1324
1325
static void
1326
setifnetmask(if_ctx *ctx, const char *addr, int dummy __unused)
1327
{
1328
const struct afswtch *afp = ctx->afp;
1329
1330
if (afp->af_getaddr != NULL) {
1331
setmask++;
1332
afp->af_getaddr(addr, MASK);
1333
}
1334
}
1335
1336
static void
1337
setifbroadaddr(if_ctx *ctx, const char *addr, int dummy __unused)
1338
{
1339
const struct afswtch *afp = ctx->afp;
1340
1341
if (afp->af_getaddr != NULL)
1342
afp->af_getaddr(addr, BRDADDR);
1343
}
1344
1345
static void
1346
notealias(if_ctx *ctx, const char *addr __unused, int param)
1347
{
1348
const struct afswtch *afp = ctx->afp;
1349
1350
if (setaddr && doalias == 0 && param < 0) {
1351
if (afp->af_copyaddr != NULL)
1352
afp->af_copyaddr(ctx, RIDADDR, ADDR);
1353
}
1354
doalias = param;
1355
if (param < 0) {
1356
clearaddr = 1;
1357
newaddr = 0;
1358
} else
1359
clearaddr = 0;
1360
}
1361
1362
static void
1363
setifdstaddr(if_ctx *ctx, const char *addr, int param __unused)
1364
{
1365
const struct afswtch *afp = ctx->afp;
1366
1367
if (afp->af_getaddr != NULL)
1368
afp->af_getaddr(addr, DSTADDR);
1369
}
1370
1371
static int
1372
getifflags(const char *ifname, int us, bool err_ok)
1373
{
1374
struct ifreq my_ifr;
1375
int s;
1376
1377
memset(&my_ifr, 0, sizeof(my_ifr));
1378
(void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name));
1379
if (us < 0) {
1380
if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)
1381
err(1, "socket(family AF_LOCAL,SOCK_DGRAM");
1382
} else
1383
s = us;
1384
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
1385
if (!err_ok) {
1386
Perror("ioctl (SIOCGIFFLAGS)");
1387
exit(1);
1388
}
1389
}
1390
if (us < 0)
1391
close(s);
1392
return ((my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16));
1393
}
1394
1395
/*
1396
* Note: doing an SIOCIGIFFLAGS scribbles on the union portion
1397
* of the ifreq structure, which may confuse other parts of ifconfig.
1398
* Make a private copy so we can avoid that.
1399
*/
1400
static void
1401
clearifflags(if_ctx *ctx, const char *vname, int value)
1402
{
1403
struct ifreq my_ifr;
1404
int flags;
1405
1406
flags = getifflags(ctx->ifname, ctx->io_s, false);
1407
flags &= ~value;
1408
memset(&my_ifr, 0, sizeof(my_ifr));
1409
strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name));
1410
my_ifr.ifr_flags = flags & 0xffff;
1411
my_ifr.ifr_flagshigh = flags >> 16;
1412
if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
1413
Perror(vname);
1414
}
1415
1416
static void
1417
setifflags(if_ctx *ctx, const char *vname, int value)
1418
{
1419
struct ifreq my_ifr;
1420
int flags;
1421
1422
flags = getifflags(ctx->ifname, ctx->io_s, false);
1423
flags |= value;
1424
memset(&my_ifr, 0, sizeof(my_ifr));
1425
strlcpy(my_ifr.ifr_name, ctx->ifname, sizeof(my_ifr.ifr_name));
1426
my_ifr.ifr_flags = flags & 0xffff;
1427
my_ifr.ifr_flagshigh = flags >> 16;
1428
if (ioctl(ctx->io_s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
1429
Perror(vname);
1430
}
1431
1432
void
1433
clearifcap(if_ctx *ctx, const char *vname, int value)
1434
{
1435
struct ifreq ifr = {};
1436
int flags;
1437
1438
if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) {
1439
Perror("ioctl (SIOCGIFCAP)");
1440
exit(1);
1441
}
1442
flags = ifr.ifr_curcap;
1443
flags &= ~value;
1444
flags &= ifr.ifr_reqcap;
1445
/* Check for no change in capabilities. */
1446
if (ifr.ifr_curcap == flags)
1447
return;
1448
ifr.ifr_reqcap = flags;
1449
if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0)
1450
Perror(vname);
1451
}
1452
1453
void
1454
setifcap(if_ctx *ctx, const char *vname, int value)
1455
{
1456
struct ifreq ifr = {};
1457
int flags;
1458
1459
if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0) {
1460
Perror("ioctl (SIOCGIFCAP)");
1461
exit(1);
1462
}
1463
flags = ifr.ifr_curcap;
1464
flags |= value;
1465
flags &= ifr.ifr_reqcap;
1466
/* Check for no change in capabilities. */
1467
if (ifr.ifr_curcap == flags)
1468
return;
1469
ifr.ifr_reqcap = flags;
1470
if (ioctl_ctx(ctx, SIOCSIFCAP, &ifr) < 0)
1471
Perror(vname);
1472
}
1473
1474
void
1475
setifcapnv(if_ctx *ctx, const char *vname, const char *arg)
1476
{
1477
nvlist_t *nvcap;
1478
void *buf;
1479
char *marg, *mopt;
1480
size_t nvbuflen;
1481
bool neg;
1482
struct ifreq ifr = {};
1483
1484
if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) < 0)
1485
Perror("ioctl (SIOCGIFCAP)");
1486
if ((ifr.ifr_curcap & IFCAP_NV) == 0) {
1487
warnx("IFCAP_NV not supported");
1488
return; /* Not exit() */
1489
}
1490
1491
marg = strdup(arg);
1492
if (marg == NULL)
1493
Perror("strdup");
1494
nvcap = nvlist_create(0);
1495
if (nvcap == NULL)
1496
Perror("nvlist_create");
1497
while ((mopt = strsep(&marg, ",")) != NULL) {
1498
neg = *mopt == '-';
1499
if (neg)
1500
mopt++;
1501
if (strcmp(mopt, "rxtls") == 0) {
1502
nvlist_add_bool(nvcap, "rxtls4", !neg);
1503
nvlist_add_bool(nvcap, "rxtls6", !neg);
1504
} else {
1505
nvlist_add_bool(nvcap, mopt, !neg);
1506
}
1507
}
1508
buf = nvlist_pack(nvcap, &nvbuflen);
1509
if (buf == NULL) {
1510
errx(1, "nvlist_pack error");
1511
exit(1);
1512
}
1513
ifr.ifr_cap_nv.buf_length = ifr.ifr_cap_nv.length = nvbuflen;
1514
ifr.ifr_cap_nv.buffer = buf;
1515
if (ioctl_ctx(ctx, SIOCSIFCAPNV, (caddr_t)&ifr) < 0)
1516
Perror(vname);
1517
free(buf);
1518
nvlist_destroy(nvcap);
1519
free(marg);
1520
}
1521
1522
static void
1523
setifmetric(if_ctx *ctx, const char *val, int dummy __unused)
1524
{
1525
struct ifreq ifr = {};
1526
1527
ifr.ifr_metric = atoi(val);
1528
if (ioctl_ctx_ifr(ctx, SIOCSIFMETRIC, &ifr) < 0)
1529
err(1, "ioctl SIOCSIFMETRIC (set metric)");
1530
}
1531
1532
static void
1533
setifmtu(if_ctx *ctx, const char *val, int dummy __unused)
1534
{
1535
struct ifreq ifr = {};
1536
1537
ifr.ifr_mtu = atoi(val);
1538
if (ioctl_ctx_ifr(ctx, SIOCSIFMTU, &ifr) < 0)
1539
err(1, "ioctl SIOCSIFMTU (set mtu)");
1540
}
1541
1542
static void
1543
setifpcp(if_ctx *ctx, const char *val, int arg __unused)
1544
{
1545
struct ifreq ifr = {};
1546
u_long ul;
1547
char *endp;
1548
1549
ul = strtoul(val, &endp, 0);
1550
if (*endp != '\0')
1551
errx(1, "invalid value for pcp");
1552
if (ul > 7)
1553
errx(1, "value for pcp out of range");
1554
ifr.ifr_lan_pcp = ul;
1555
if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1)
1556
err(1, "SIOCSLANPCP");
1557
}
1558
1559
static void
1560
disableifpcp(if_ctx *ctx, const char *val __unused, int arg __unused)
1561
{
1562
struct ifreq ifr = {};
1563
1564
ifr.ifr_lan_pcp = IFNET_PCP_NONE;
1565
if (ioctl_ctx_ifr(ctx, SIOCSLANPCP, &ifr) == -1)
1566
err(1, "SIOCSLANPCP");
1567
}
1568
1569
static void
1570
setifname(if_ctx *ctx, const char *val, int dummy __unused)
1571
{
1572
struct ifreq ifr = {};
1573
char *newname;
1574
1575
ifr_set_name(&ifr, ctx->ifname);
1576
newname = strdup(val);
1577
if (newname == NULL)
1578
err(1, "no memory to set ifname");
1579
ifr.ifr_data = newname;
1580
if (ioctl_ctx(ctx, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
1581
free(newname);
1582
err(1, "ioctl SIOCSIFNAME (set name)");
1583
}
1584
ifname_update(ctx, newname);
1585
free(newname);
1586
}
1587
1588
static void
1589
setifdescr(if_ctx *ctx, const char *val, int dummy __unused)
1590
{
1591
struct ifreq ifr = {};
1592
char *newdescr;
1593
1594
ifr.ifr_buffer.length = strlen(val) + 1;
1595
if (ifr.ifr_buffer.length == 1) {
1596
ifr.ifr_buffer.buffer = newdescr = NULL;
1597
ifr.ifr_buffer.length = 0;
1598
} else {
1599
newdescr = strdup(val);
1600
ifr.ifr_buffer.buffer = newdescr;
1601
if (newdescr == NULL) {
1602
warn("no memory to set ifdescr");
1603
return;
1604
}
1605
}
1606
1607
if (ioctl_ctx_ifr(ctx, SIOCSIFDESCR, &ifr) < 0)
1608
err(1, "ioctl SIOCSIFDESCR (set descr)");
1609
1610
free(newdescr);
1611
}
1612
1613
static void
1614
unsetifdescr(if_ctx *ctx, const char *val __unused, int value __unused)
1615
{
1616
setifdescr(ctx, "", 0);
1617
}
1618
1619
#ifdef WITHOUT_NETLINK
1620
1621
static const char *IFFBITS[] = {
1622
[0] = "UP",
1623
[1] = "BROADCAST",
1624
[2] = "DEBUG",
1625
[3] = "LOOPBACK",
1626
[4] = "POINTOPOINT",
1627
[6] = "RUNNING",
1628
[7] = "NOARP",
1629
[8] = "PROMISC",
1630
[9] = "ALLMULTI",
1631
[10] = "OACTIVE",
1632
[11] = "SIMPLEX",
1633
[12] = "LINK0",
1634
[13] = "LINK1",
1635
[14] = "LINK2",
1636
[15] = "MULTICAST",
1637
[17] = "PPROMISC",
1638
[18] = "MONITOR",
1639
[19] = "STATICARP",
1640
[20] = "STICKYARP",
1641
};
1642
1643
static const char *IFCAPBITS[] = {
1644
[0] = "RXCSUM",
1645
[1] = "TXCSUM",
1646
[2] = "NETCONS",
1647
[3] = "VLAN_MTU",
1648
[4] = "VLAN_HWTAGGING",
1649
[5] = "JUMBO_MTU",
1650
[6] = "POLLING",
1651
[7] = "VLAN_HWCSUM",
1652
[8] = "TSO4",
1653
[9] = "TSO6",
1654
[10] = "LRO",
1655
[11] = "WOL_UCAST",
1656
[12] = "WOL_MCAST",
1657
[13] = "WOL_MAGIC",
1658
[14] = "TOE4",
1659
[15] = "TOE6",
1660
[16] = "VLAN_HWFILTER",
1661
[18] = "VLAN_HWTSO",
1662
[19] = "LINKSTATE",
1663
[20] = "NETMAP",
1664
[21] = "RXCSUM_IPV6",
1665
[22] = "TXCSUM_IPV6",
1666
[23] = "HWSTATS",
1667
[24] = "TXRTLMT",
1668
[25] = "HWRXTSTMP",
1669
[26] = "MEXTPG",
1670
[27] = "TXTLS4",
1671
[28] = "TXTLS6",
1672
[29] = "VXLAN_HWCSUM",
1673
[30] = "VXLAN_HWTSO",
1674
[31] = "TXTLS_RTLMT",
1675
};
1676
1677
static void
1678
print_ifcap_nv(if_ctx *ctx)
1679
{
1680
struct ifreq ifr = {};
1681
nvlist_t *nvcap;
1682
const char *nvname;
1683
void *buf, *cookie;
1684
bool first, val;
1685
int type;
1686
1687
buf = malloc(IFR_CAP_NV_MAXBUFSIZE);
1688
if (buf == NULL)
1689
Perror("malloc");
1690
ifr.ifr_cap_nv.buffer = buf;
1691
ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE;
1692
if (ioctl_ctx_ifr(ctx, SIOCGIFCAPNV, &ifr) != 0)
1693
Perror("ioctl (SIOCGIFCAPNV)");
1694
nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer,
1695
ifr.ifr_cap_nv.length, 0);
1696
if (nvcap == NULL)
1697
Perror("nvlist_unpack");
1698
printf("\toptions");
1699
cookie = NULL;
1700
for (first = true;; first = false) {
1701
nvname = nvlist_next(nvcap, &type, &cookie);
1702
if (nvname == NULL) {
1703
printf("\n");
1704
break;
1705
}
1706
if (type == NV_TYPE_BOOL) {
1707
val = nvlist_get_bool(nvcap, nvname);
1708
if (val) {
1709
printf("%c%s",
1710
first ? ' ' : ',', nvname);
1711
}
1712
}
1713
}
1714
if (ctx->args->supmedia) {
1715
printf("\tcapabilities");
1716
cookie = NULL;
1717
for (first = true;; first = false) {
1718
nvname = nvlist_next(nvcap, &type,
1719
&cookie);
1720
if (nvname == NULL) {
1721
printf("\n");
1722
break;
1723
}
1724
if (type == NV_TYPE_BOOL)
1725
printf("%c%s", first ? ' ' :
1726
',', nvname);
1727
}
1728
}
1729
nvlist_destroy(nvcap);
1730
free(buf);
1731
1732
if (ioctl_ctx(ctx, SIOCGIFCAP, (caddr_t)&ifr) != 0)
1733
Perror("ioctl (SIOCGIFCAP)");
1734
}
1735
1736
static void
1737
print_ifcap(if_ctx *ctx)
1738
{
1739
struct ifreq ifr = {};
1740
1741
if (ioctl_ctx_ifr(ctx, SIOCGIFCAP, &ifr) != 0)
1742
return;
1743
1744
if ((ifr.ifr_curcap & IFCAP_NV) != 0)
1745
print_ifcap_nv(ctx);
1746
else {
1747
printf("\toptions=%x", ifr.ifr_curcap);
1748
print_bits("options", &ifr.ifr_curcap, 1, IFCAPBITS, nitems(IFCAPBITS));
1749
putchar('\n');
1750
if (ctx->args->supmedia && ifr.ifr_reqcap != 0) {
1751
printf("\tcapabilities=%x", ifr.ifr_reqcap);
1752
print_bits("capabilities", &ifr.ifr_reqcap, 1, IFCAPBITS, nitems(IFCAPBITS));
1753
putchar('\n');
1754
}
1755
}
1756
}
1757
#endif
1758
1759
void
1760
print_ifstatus(if_ctx *ctx)
1761
{
1762
struct ifstat ifs;
1763
1764
strlcpy(ifs.ifs_name, ctx->ifname, sizeof ifs.ifs_name);
1765
if (ioctl_ctx(ctx, SIOCGIFSTATUS, &ifs) == 0)
1766
printf("%s", ifs.ascii);
1767
}
1768
1769
void
1770
print_metric(if_ctx *ctx)
1771
{
1772
struct ifreq ifr = {};
1773
1774
if (ioctl_ctx_ifr(ctx, SIOCGIFMETRIC, &ifr) != -1)
1775
printf(" metric %d", ifr.ifr_metric);
1776
}
1777
1778
#ifdef WITHOUT_NETLINK
1779
static void
1780
print_mtu(if_ctx *ctx)
1781
{
1782
struct ifreq ifr = {};
1783
1784
if (ioctl_ctx_ifr(ctx, SIOCGIFMTU, &ifr) != -1)
1785
printf(" mtu %d", ifr.ifr_mtu);
1786
}
1787
1788
static void
1789
print_description(if_ctx *ctx)
1790
{
1791
struct ifreq ifr = {};
1792
1793
ifr_set_name(&ifr, ctx->ifname);
1794
for (;;) {
1795
if ((descr = reallocf(descr, descrlen)) != NULL) {
1796
ifr.ifr_buffer.buffer = descr;
1797
ifr.ifr_buffer.length = descrlen;
1798
if (ioctl_ctx(ctx, SIOCGIFDESCR, &ifr) == 0) {
1799
if (ifr.ifr_buffer.buffer == descr) {
1800
if (strlen(descr) > 0)
1801
printf("\tdescription: %s\n",
1802
descr);
1803
} else if (ifr.ifr_buffer.length > descrlen) {
1804
descrlen = ifr.ifr_buffer.length;
1805
continue;
1806
}
1807
}
1808
} else
1809
warn("unable to allocate memory for interface"
1810
"description");
1811
break;
1812
}
1813
}
1814
1815
/*
1816
* Print the status of the interface. If an address family was
1817
* specified, show only it; otherwise, show them all.
1818
*/
1819
static void
1820
status(if_ctx *ctx, const struct sockaddr_dl *sdl __unused, struct ifaddrs *ifa)
1821
{
1822
struct ifaddrs *ift;
1823
int s, old_s;
1824
struct ifconfig_args *args = ctx->args;
1825
bool allfamilies = args->afp == NULL;
1826
struct ifreq ifr = {};
1827
1828
if (args->afp == NULL)
1829
ifr.ifr_addr.sa_family = AF_LOCAL;
1830
else
1831
ifr.ifr_addr.sa_family =
1832
args->afp->af_af == AF_LINK ? AF_LOCAL : args->afp->af_af;
1833
1834
s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
1835
if (s < 0)
1836
err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
1837
old_s = ctx->io_s;
1838
ctx->io_s = s;
1839
1840
printf("%s: flags=%x", ctx->ifname, ifa->ifa_flags);
1841
print_bits("flags", &ifa->ifa_flags, 1, IFFBITS, nitems(IFFBITS));
1842
print_metric(ctx);
1843
print_mtu(ctx);
1844
putchar('\n');
1845
1846
print_description(ctx);
1847
1848
print_ifcap(ctx);
1849
1850
tunnel_status(ctx);
1851
1852
for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
1853
if (ift->ifa_addr == NULL)
1854
continue;
1855
if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
1856
continue;
1857
if (allfamilies) {
1858
const struct afswtch *p;
1859
p = af_getbyfamily(ift->ifa_addr->sa_family);
1860
if (p != NULL && p->af_status != NULL)
1861
p->af_status(ctx, ift);
1862
} else if (args->afp->af_af == ift->ifa_addr->sa_family)
1863
args->afp->af_status(ctx, ift);
1864
}
1865
#if 0
1866
if (allfamilies || afp->af_af == AF_LINK) {
1867
const struct afswtch *lafp;
1868
1869
/*
1870
* Hack; the link level address is received separately
1871
* from the routing information so any address is not
1872
* handled above. Cobble together an entry and invoke
1873
* the status method specially.
1874
*/
1875
lafp = af_getbyname("lladdr");
1876
if (lafp != NULL) {
1877
info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
1878
lafp->af_status(s, &info);
1879
}
1880
}
1881
#endif
1882
if (allfamilies)
1883
af_other_status(ctx);
1884
else if (args->afp->af_other_status != NULL)
1885
args->afp->af_other_status(ctx);
1886
1887
print_ifstatus(ctx);
1888
if (args->verbose > 0)
1889
sfp_status(ctx);
1890
1891
close(s);
1892
ctx->io_s = old_s;
1893
return;
1894
}
1895
#endif
1896
1897
void
1898
tunnel_status(if_ctx *ctx)
1899
{
1900
af_all_tunnel_status(ctx);
1901
}
1902
1903
static void
1904
Perrorc(const char *cmd, int error)
1905
{
1906
switch (errno) {
1907
1908
case ENXIO:
1909
errx(1, "%s: no such interface", cmd);
1910
break;
1911
1912
case EPERM:
1913
errx(1, "%s: permission denied", cmd);
1914
break;
1915
1916
default:
1917
errc(1, error, "%s", cmd);
1918
}
1919
}
1920
1921
void
1922
Perror(const char *cmd)
1923
{
1924
Perrorc(cmd, errno);
1925
}
1926
1927
void
1928
print_bits(const char *btype, uint32_t *v, const int v_count,
1929
const char **names, const int n_count)
1930
{
1931
int num = 0;
1932
1933
for (int i = 0; i < v_count * 32; i++) {
1934
bool is_set = v[i / 32] & (1U << (i % 32));
1935
if (is_set) {
1936
if (num++ == 0)
1937
printf("<");
1938
if (num != 1)
1939
printf(",");
1940
if (i < n_count)
1941
printf("%s", names[i]);
1942
else
1943
printf("%s_%d", btype, i);
1944
}
1945
}
1946
if (num > 0)
1947
printf(">");
1948
}
1949
1950
/*
1951
* Print a value a la the %b format of the kernel's printf
1952
*/
1953
void
1954
printb(const char *s, unsigned v, const char *bits)
1955
{
1956
int i, any = 0;
1957
char c;
1958
1959
if (bits && *bits == 8)
1960
printf("%s=%o", s, v);
1961
else
1962
printf("%s=%x", s, v);
1963
if (bits) {
1964
bits++;
1965
putchar('<');
1966
while ((i = *bits++) != '\0') {
1967
if (v & (1u << (i-1))) {
1968
if (any)
1969
putchar(',');
1970
any = 1;
1971
for (; (c = *bits) > 32; bits++)
1972
putchar(c);
1973
} else
1974
for (; *bits > 32; bits++)
1975
;
1976
}
1977
putchar('>');
1978
}
1979
}
1980
1981
void
1982
print_vhid(const struct ifaddrs *ifa)
1983
{
1984
struct if_data *ifd;
1985
1986
if (ifa->ifa_data == NULL)
1987
return;
1988
1989
ifd = ifa->ifa_data;
1990
if (ifd->ifi_vhid == 0)
1991
return;
1992
1993
printf(" vhid %d", ifd->ifi_vhid);
1994
}
1995
1996
void
1997
ifmaybeload(struct ifconfig_args *args, const char *name)
1998
{
1999
#define MOD_PREFIX_LEN 3 /* "if_" */
2000
struct module_stat mstat;
2001
int fileid, modid;
2002
char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
2003
const char *cp;
2004
struct module_map_entry *mme;
2005
bool found;
2006
2007
/* loading suppressed by the user */
2008
if (args->noload)
2009
return;
2010
2011
/* trim the interface number off the end */
2012
strlcpy(ifname, name, sizeof(ifname));
2013
dp = ifname + strlen(ifname) - 1;
2014
for (; dp > ifname; dp--) {
2015
if (isdigit(*dp))
2016
*dp = '\0';
2017
else
2018
break;
2019
}
2020
2021
/* Either derive it from the map or guess otherwise */
2022
*ifkind = '\0';
2023
found = false;
2024
for (unsigned i = 0; i < nitems(module_map); ++i) {
2025
mme = &module_map[i];
2026
if (strcmp(mme->ifname, ifname) == 0) {
2027
strlcpy(ifkind, mme->kldname, sizeof(ifkind));
2028
found = true;
2029
break;
2030
}
2031
}
2032
2033
/* We didn't have an alias for it... we'll guess. */
2034
if (!found) {
2035
/* turn interface and unit into module name */
2036
strlcpy(ifkind, "if_", sizeof(ifkind));
2037
strlcat(ifkind, ifname, sizeof(ifkind));
2038
}
2039
2040
/* scan files in kernel */
2041
mstat.version = sizeof(struct module_stat);
2042
for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
2043
/* scan modules in file */
2044
for (modid = kldfirstmod(fileid); modid > 0;
2045
modid = modfnext(modid)) {
2046
if (modstat(modid, &mstat) < 0)
2047
continue;
2048
/* strip bus name if present */
2049
if ((cp = strchr(mstat.name, '/')) != NULL) {
2050
cp++;
2051
} else {
2052
cp = mstat.name;
2053
}
2054
/*
2055
* Is it already loaded? Don't compare with ifname if
2056
* we were specifically told which kld to use. Doing
2057
* so could lead to conflicts not trivially solved.
2058
*/
2059
if ((!found && strcmp(ifname, cp) == 0) ||
2060
strcmp(ifkind, cp) == 0)
2061
return;
2062
}
2063
}
2064
2065
/*
2066
* Try to load the module. But ignore failures, because ifconfig can't
2067
* infer the names of all drivers (eg mlx4en(4)).
2068
*/
2069
(void) kldload(ifkind);
2070
}
2071
2072
static struct cmd basic_cmds[] = {
2073
DEF_CMD("up", IFF_UP, setifflags),
2074
DEF_CMD("down", IFF_UP, clearifflags),
2075
DEF_CMD("arp", IFF_NOARP, clearifflags),
2076
DEF_CMD("-arp", IFF_NOARP, setifflags),
2077
DEF_CMD("debug", IFF_DEBUG, setifflags),
2078
DEF_CMD("-debug", IFF_DEBUG, clearifflags),
2079
DEF_CMD_ARG("description", setifdescr),
2080
DEF_CMD_ARG("descr", setifdescr),
2081
DEF_CMD("-description", 0, unsetifdescr),
2082
DEF_CMD("-descr", 0, unsetifdescr),
2083
DEF_CMD("allmulti", IFF_PALLMULTI, setifflags),
2084
DEF_CMD("-allmulti", IFF_PALLMULTI, clearifflags),
2085
DEF_CMD("promisc", IFF_PPROMISC, setifflags),
2086
DEF_CMD("-promisc", IFF_PPROMISC, clearifflags),
2087
DEF_CMD("add", IFF_UP, notealias),
2088
DEF_CMD("alias", IFF_UP, notealias),
2089
DEF_CMD("-alias", -IFF_UP, notealias),
2090
DEF_CMD("delete", -IFF_UP, notealias),
2091
DEF_CMD("remove", -IFF_UP, notealias),
2092
DEF_CMD_ARG("netmask", setifnetmask),
2093
DEF_CMD_ARG("metric", setifmetric),
2094
DEF_CMD_ARG("broadcast", setifbroadaddr),
2095
DEF_CMD_ARG2("tunnel", settunnel),
2096
DEF_CMD("-tunnel", 0, deletetunnel),
2097
DEF_CMD("deletetunnel", 0, deletetunnel),
2098
#ifdef JAIL
2099
DEF_CMD_ARG("vnet", setifvnet),
2100
DEF_CMD_ARG("-vnet", setifrvnet),
2101
#endif
2102
DEF_CMD("link0", IFF_LINK0, setifflags),
2103
DEF_CMD("-link0", IFF_LINK0, clearifflags),
2104
DEF_CMD("link1", IFF_LINK1, setifflags),
2105
DEF_CMD("-link1", IFF_LINK1, clearifflags),
2106
DEF_CMD("link2", IFF_LINK2, setifflags),
2107
DEF_CMD("-link2", IFF_LINK2, clearifflags),
2108
DEF_CMD("monitor", IFF_MONITOR, setifflags),
2109
DEF_CMD("-monitor", IFF_MONITOR, clearifflags),
2110
DEF_CMD("mextpg", IFCAP_MEXTPG, setifcap),
2111
DEF_CMD("-mextpg", IFCAP_MEXTPG, clearifcap),
2112
DEF_CMD("staticarp", IFF_STATICARP, setifflags),
2113
DEF_CMD("-staticarp", IFF_STATICARP, clearifflags),
2114
DEF_CMD("stickyarp", IFF_STICKYARP, setifflags),
2115
DEF_CMD("-stickyarp", IFF_STICKYARP, clearifflags),
2116
DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap),
2117
DEF_CMD("-rxcsum6", IFCAP_RXCSUM_IPV6, clearifcap),
2118
DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap),
2119
DEF_CMD("-txcsum6", IFCAP_TXCSUM_IPV6, clearifcap),
2120
DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
2121
DEF_CMD("-rxcsum", IFCAP_RXCSUM, clearifcap),
2122
DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
2123
DEF_CMD("-txcsum", IFCAP_TXCSUM, clearifcap),
2124
DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
2125
DEF_CMD("-netcons", IFCAP_NETCONS, clearifcap),
2126
DEF_CMD_ARG("pcp", setifpcp),
2127
DEF_CMD("-pcp", 0, disableifpcp),
2128
DEF_CMD("polling", IFCAP_POLLING, setifcap),
2129
DEF_CMD("-polling", IFCAP_POLLING, clearifcap),
2130
DEF_CMD("tso6", IFCAP_TSO6, setifcap),
2131
DEF_CMD("-tso6", IFCAP_TSO6, clearifcap),
2132
DEF_CMD("tso4", IFCAP_TSO4, setifcap),
2133
DEF_CMD("-tso4", IFCAP_TSO4, clearifcap),
2134
DEF_CMD("tso", IFCAP_TSO, setifcap),
2135
DEF_CMD("-tso", IFCAP_TSO, clearifcap),
2136
DEF_CMD("toe", IFCAP_TOE, setifcap),
2137
DEF_CMD("-toe", IFCAP_TOE, clearifcap),
2138
DEF_CMD("lro", IFCAP_LRO, setifcap),
2139
DEF_CMD("-lro", IFCAP_LRO, clearifcap),
2140
DEF_CMD("txtls", IFCAP_TXTLS, setifcap),
2141
DEF_CMD("-txtls", IFCAP_TXTLS, clearifcap),
2142
DEF_CMD_SARG("rxtls", IFCAP2_RXTLS4_NAME "," IFCAP2_RXTLS6_NAME,
2143
setifcapnv),
2144
DEF_CMD_SARG("-rxtls", "-"IFCAP2_RXTLS4_NAME ",-" IFCAP2_RXTLS6_NAME,
2145
setifcapnv),
2146
DEF_CMD_SARG("ipsec", IFCAP2_IPSEC_OFFLOAD_NAME, setifcapnv),
2147
DEF_CMD_SARG("-ipsec", "-"IFCAP2_IPSEC_OFFLOAD_NAME, setifcapnv),
2148
DEF_CMD("wol", IFCAP_WOL, setifcap),
2149
DEF_CMD("-wol", IFCAP_WOL, clearifcap),
2150
DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap),
2151
DEF_CMD("-wol_ucast", IFCAP_WOL_UCAST, clearifcap),
2152
DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap),
2153
DEF_CMD("-wol_mcast", IFCAP_WOL_MCAST, clearifcap),
2154
DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap),
2155
DEF_CMD("-wol_magic", IFCAP_WOL_MAGIC, clearifcap),
2156
DEF_CMD("txrtlmt", IFCAP_TXRTLMT, setifcap),
2157
DEF_CMD("-txrtlmt", IFCAP_TXRTLMT, clearifcap),
2158
DEF_CMD("txtlsrtlmt", IFCAP_TXTLS_RTLMT, setifcap),
2159
DEF_CMD("-txtlsrtlmt", IFCAP_TXTLS_RTLMT, clearifcap),
2160
DEF_CMD("hwrxtstmp", IFCAP_HWRXTSTMP, setifcap),
2161
DEF_CMD("-hwrxtstmp", IFCAP_HWRXTSTMP, clearifcap),
2162
DEF_CMD("normal", IFF_LINK0, clearifflags),
2163
DEF_CMD("compress", IFF_LINK0, setifflags),
2164
DEF_CMD("noicmp", IFF_LINK1, setifflags),
2165
DEF_CMD_ARG("mtu", setifmtu),
2166
DEF_CMD_ARG("name", setifname),
2167
};
2168
2169
static __constructor void
2170
ifconfig_ctor(void)
2171
{
2172
size_t i;
2173
2174
for (i = 0; i < nitems(basic_cmds); i++)
2175
cmd_register(&basic_cmds[i]);
2176
}
2177
2178