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