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