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