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