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