]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/ifconfig.c
- MFC
[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 int     setaddr;
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
97 static  int ifconfig(int argc, char *const *argv, int iscreate,
98                 const struct afswtch *afp);
99 static  void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
100                 struct ifaddrs *ifa);
101 static  void tunnel_status(int s);
102 static  void usage(void);
103
104 static struct afswtch *af_getbyname(const char *name);
105 static struct afswtch *af_getbyfamily(int af);
106 static void af_other_status(int);
107
108 static struct option *opts = NULL;
109
110 void
111 opt_register(struct option *p)
112 {
113         p->next = opts;
114         opts = p;
115 }
116
117 static void
118 usage(void)
119 {
120         char options[1024];
121         struct option *p;
122
123         /* XXX not right but close enough for now */
124         options[0] = '\0';
125         for (p = opts; p != NULL; p = p->next) {
126                 strlcat(options, p->opt_usage, sizeof(options));
127                 strlcat(options, " ", sizeof(options));
128         }
129
130         fprintf(stderr,
131         "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
132         "                [parameters]\n"
133         "       ifconfig interface create\n"
134         "       ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
135         "       ifconfig -l [-d] [-u] [address_family]\n"
136         "       ifconfig %s[-d] [-m] [-u] [-v]\n",
137                 options, options, options);
138         exit(1);
139 }
140
141 int
142 main(int argc, char *argv[])
143 {
144         int c, all, namesonly, downonly, uponly;
145         const struct afswtch *afp = NULL;
146         int ifindex;
147         struct ifaddrs *ifap, *ifa;
148         struct ifreq paifr;
149         const struct sockaddr_dl *sdl;
150         char options[1024], *cp;
151         const char *ifname;
152         struct option *p;
153         size_t iflen;
154
155         all = downonly = uponly = namesonly = noload = verbose = 0;
156
157         /* Parse leading line options */
158         strlcpy(options, "adklmnuv", sizeof(options));
159         for (p = opts; p != NULL; p = p->next)
160                 strlcat(options, p->opt, sizeof(options));
161         while ((c = getopt(argc, argv, options)) != -1) {
162                 switch (c) {
163                 case 'a':       /* scan all interfaces */
164                         all++;
165                         break;
166                 case 'd':       /* restrict scan to "down" interfaces */
167                         downonly++;
168                         break;
169                 case 'k':
170                         printkeys++;
171                         break;
172                 case 'l':       /* scan interface names only */
173                         namesonly++;
174                         break;
175                 case 'm':       /* show media choices in status */
176                         supmedia = 1;
177                         break;
178                 case 'n':       /* suppress module loading */
179                         noload++;
180                         break;
181                 case 'u':       /* restrict scan to "up" interfaces */
182                         uponly++;
183                         break;
184                 case 'v':
185                         verbose++;
186                         break;
187                 default:
188                         for (p = opts; p != NULL; p = p->next)
189                                 if (p->opt[0] == c) {
190                                         p->cb(optarg);
191                                         break;
192                                 }
193                         if (p == NULL)
194                                 usage();
195                         break;
196                 }
197         }
198         argc -= optind;
199         argv += optind;
200
201         /* -l cannot be used with -a or -m */
202         if (namesonly && (all || supmedia))
203                 usage();
204
205         /* nonsense.. */
206         if (uponly && downonly)
207                 usage();
208
209         /* no arguments is equivalent to '-a' */
210         if (!namesonly && argc < 1)
211                 all = 1;
212
213         /* -a and -l allow an address family arg to limit the output */
214         if (all || namesonly) {
215                 if (argc > 1)
216                         usage();
217
218                 ifname = NULL;
219                 ifindex = 0;
220                 if (argc == 1) {
221                         afp = af_getbyname(*argv);
222                         if (afp == NULL)
223                                 usage();
224                         if (afp->af_name != NULL)
225                                 argc--, argv++;
226                         /* leave with afp non-zero */
227                 }
228         } else {
229                 /* not listing, need an argument */
230                 if (argc < 1)
231                         usage();
232
233                 ifname = *argv;
234                 argc--, argv++;
235
236                 /* check and maybe load support for this interface */
237                 ifmaybeload(ifname);
238
239                 ifindex = if_nametoindex(ifname);
240                 if (ifindex == 0) {
241                         /*
242                          * NOTE:  We must special-case the `create' command
243                          * right here as we would otherwise fail when trying
244                          * to find the interface.
245                          */
246                         if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
247                             strcmp(argv[0], "plumb") == 0)) {
248                                 iflen = strlcpy(name, ifname, sizeof(name));
249                                 if (iflen >= sizeof(name))
250                                         errx(1, "%s: cloning name too long",
251                                             ifname);
252                                 ifconfig(argc, argv, 1, NULL);
253                                 exit(0);
254                         }
255                         errx(1, "interface %s does not exist", ifname);
256                 }
257         }
258
259         /* Check for address family */
260         if (argc > 0) {
261                 afp = af_getbyname(*argv);
262                 if (afp != NULL)
263                         argc--, argv++;
264         }
265
266         if (getifaddrs(&ifap) != 0)
267                 err(EXIT_FAILURE, "getifaddrs");
268         cp = NULL;
269         ifindex = 0;
270         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
271                 memset(&paifr, 0, sizeof(paifr));
272                 strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
273                 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
274                         memcpy(&paifr.ifr_addr, ifa->ifa_addr,
275                             ifa->ifa_addr->sa_len);
276                 }
277
278                 if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
279                         continue;
280                 if (ifa->ifa_addr->sa_family == AF_LINK)
281                         sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
282                 else
283                         sdl = NULL;
284                 if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
285                         continue;
286                 iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
287                 if (iflen >= sizeof(name)) {
288                         warnx("%s: interface name too long, skipping",
289                             ifa->ifa_name);
290                         continue;
291                 }
292                 cp = ifa->ifa_name;
293
294                 if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
295                         continue;
296                 if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
297                         continue;
298                 ifindex++;
299                 /*
300                  * Are we just listing the interfaces?
301                  */
302                 if (namesonly) {
303                         if (ifindex > 1)
304                                 printf(" ");
305                         fputs(name, stdout);
306                         continue;
307                 }
308
309                 if (argc > 0)
310                         ifconfig(argc, argv, 0, afp);
311                 else
312                         status(afp, sdl, ifa);
313         }
314         if (namesonly)
315                 printf("\n");
316         freeifaddrs(ifap);
317
318         exit(0);
319 }
320
321 static struct afswtch *afs = NULL;
322
323 void
324 af_register(struct afswtch *p)
325 {
326         p->af_next = afs;
327         afs = p;
328 }
329
330 static struct afswtch *
331 af_getbyname(const char *name)
332 {
333         struct afswtch *afp;
334
335         for (afp = afs; afp !=  NULL; afp = afp->af_next)
336                 if (strcmp(afp->af_name, name) == 0)
337                         return afp;
338         return NULL;
339 }
340
341 static struct afswtch *
342 af_getbyfamily(int af)
343 {
344         struct afswtch *afp;
345
346         for (afp = afs; afp != NULL; afp = afp->af_next)
347                 if (afp->af_af == af)
348                         return afp;
349         return NULL;
350 }
351
352 static void
353 af_other_status(int s)
354 {
355         struct afswtch *afp;
356         uint8_t afmask[howmany(AF_MAX, NBBY)];
357
358         memset(afmask, 0, sizeof(afmask));
359         for (afp = afs; afp != NULL; afp = afp->af_next) {
360                 if (afp->af_other_status == NULL)
361                         continue;
362                 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
363                         continue;
364                 afp->af_other_status(s);
365                 setbit(afmask, afp->af_af);
366         }
367 }
368
369 static void
370 af_all_tunnel_status(int s)
371 {
372         struct afswtch *afp;
373         uint8_t afmask[howmany(AF_MAX, NBBY)];
374
375         memset(afmask, 0, sizeof(afmask));
376         for (afp = afs; afp != NULL; afp = afp->af_next) {
377                 if (afp->af_status_tunnel == NULL)
378                         continue;
379                 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
380                         continue;
381                 afp->af_status_tunnel(s);
382                 setbit(afmask, afp->af_af);
383         }
384 }
385
386 static struct cmd *cmds = NULL;
387
388 void
389 cmd_register(struct cmd *p)
390 {
391         p->c_next = cmds;
392         cmds = p;
393 }
394
395 static const struct cmd *
396 cmd_lookup(const char *name, int iscreate)
397 {
398 #define N(a)    (sizeof(a)/sizeof(a[0]))
399         const struct cmd *p;
400
401         for (p = cmds; p != NULL; p = p->c_next)
402                 if (strcmp(name, p->c_name) == 0) {
403                         if (iscreate) {
404                                 if (p->c_iscloneop)
405                                         return p;
406                         } else {
407                                 if (!p->c_iscloneop)
408                                         return p;
409                         }
410                 }
411         return NULL;
412 #undef N
413 }
414
415 struct callback {
416         callback_func *cb_func;
417         void    *cb_arg;
418         struct callback *cb_next;
419 };
420 static struct callback *callbacks = NULL;
421
422 void
423 callback_register(callback_func *func, void *arg)
424 {
425         struct callback *cb;
426
427         cb = malloc(sizeof(struct callback));
428         if (cb == NULL)
429                 errx(1, "unable to allocate memory for callback");
430         cb->cb_func = func;
431         cb->cb_arg = arg;
432         cb->cb_next = callbacks;
433         callbacks = cb;
434 }
435
436 /* specially-handled commands */
437 static void setifaddr(const char *, int, int, const struct afswtch *);
438 static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
439
440 static void setifdstaddr(const char *, int, int, const struct afswtch *);
441 static const struct cmd setifdstaddr_cmd =
442         DEF_CMD("ifdstaddr", 0, setifdstaddr);
443
444 static int
445 ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
446 {
447         const struct afswtch *afp, *nafp;
448         const struct cmd *p;
449         struct callback *cb;
450         int s;
451
452         strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
453         afp = uafp != NULL ? uafp : af_getbyname("inet");
454 top:
455         ifr.ifr_addr.sa_family =
456                 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
457                 AF_LOCAL : afp->af_af;
458
459         if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
460             (uafp != NULL || errno != EPROTONOSUPPORT ||
461              (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
462                 err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
463
464         while (argc > 0) {
465                 p = cmd_lookup(*argv, iscreate);
466                 if (iscreate && p == NULL) {
467                         /*
468                          * Push the clone create callback so the new
469                          * device is created and can be used for any
470                          * remaining arguments.
471                          */
472                         cb = callbacks;
473                         if (cb == NULL)
474                                 errx(1, "internal error, no callback");
475                         callbacks = cb->cb_next;
476                         cb->cb_func(s, cb->cb_arg);
477                         iscreate = 0;
478                         /*
479                          * Handle any address family spec that
480                          * immediately follows and potentially
481                          * recreate the socket.
482                          */
483                         nafp = af_getbyname(*argv);
484                         if (nafp != NULL) {
485                                 argc--, argv++;
486                                 if (nafp != afp) {
487                                         close(s);
488                                         afp = nafp;
489                                         goto top;
490                                 }
491                         }
492                         /*
493                          * Look for a normal parameter.
494                          */
495                         continue;
496                 }
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 setifvnet(const char *jname, int dummy __unused, int s,
634     const struct afswtch *afp)
635 {
636         struct ifreq my_ifr;
637
638         memcpy(&my_ifr, &ifr, sizeof(my_ifr));
639         ifr.ifr_jid = jail_getid(jname);
640         if (ifr.ifr_jid < 0)
641                 errx(1, "%s", jail_errmsg);
642         if (ioctl(s, SIOCSIFVNET, &ifr) < 0)
643                 err(1, "SIOCSIFVNET");
644 }
645
646 static void
647 setifrvnet(const char *jname, int dummy __unused, int s,
648     const struct afswtch *afp)
649 {
650         struct ifreq my_ifr;
651
652         memcpy(&my_ifr, &ifr, sizeof(my_ifr));
653         ifr.ifr_jid = jail_getid(jname);
654         if (ifr.ifr_jid < 0)
655                 errx(1, "%s", jail_errmsg);
656         if (ioctl(s, SIOCSIFRVNET, &ifr) < 0)
657                 err(1, "SIOCSIFRVNET");
658 }
659
660 static void
661 setifnetmask(const char *addr, int dummy __unused, int s,
662     const struct afswtch *afp)
663 {
664         if (afp->af_getaddr != NULL) {
665                 setmask++;
666                 afp->af_getaddr(addr, MASK);
667         }
668 }
669
670 static void
671 setifbroadaddr(const char *addr, int dummy __unused, int s,
672     const struct afswtch *afp)
673 {
674         if (afp->af_getaddr != NULL)
675                 afp->af_getaddr(addr, DSTADDR);
676 }
677
678 static void
679 setifipdst(const char *addr, int dummy __unused, int s,
680     const struct afswtch *afp)
681 {
682         const struct afswtch *inet;
683
684         inet = af_getbyname("inet");
685         if (inet == NULL)
686                 return;
687         inet->af_getaddr(addr, DSTADDR);
688         clearaddr = 0;
689         newaddr = 0;
690 }
691
692 static void
693 notealias(const char *addr, int param, int s, const struct afswtch *afp)
694 {
695 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
696         if (setaddr && doalias == 0 && param < 0)
697                 if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
698                         bcopy((caddr_t)rqtosa(af_addreq),
699                               (caddr_t)rqtosa(af_ridreq),
700                               rqtosa(af_addreq)->sa_len);
701         doalias = param;
702         if (param < 0) {
703                 clearaddr = 1;
704                 newaddr = 0;
705         } else
706                 clearaddr = 0;
707 #undef rqtosa
708 }
709
710 /*ARGSUSED*/
711 static void
712 setifdstaddr(const char *addr, int param __unused, int s, 
713     const struct afswtch *afp)
714 {
715         if (afp->af_getaddr != NULL)
716                 afp->af_getaddr(addr, DSTADDR);
717 }
718
719 /*
720  * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
721  * of the ifreq structure, which may confuse other parts of ifconfig.
722  * Make a private copy so we can avoid that.
723  */
724 static void
725 setifflags(const char *vname, int value, int s, const struct afswtch *afp)
726 {
727         struct ifreq            my_ifr;
728         int flags;
729
730         memset(&my_ifr, 0, sizeof(my_ifr));
731         (void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
732
733         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
734                 Perror("ioctl (SIOCGIFFLAGS)");
735                 exit(1);
736         }
737         flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16);
738
739         if (value < 0) {
740                 value = -value;
741                 flags &= ~value;
742         } else
743                 flags |= value;
744         my_ifr.ifr_flags = flags & 0xffff;
745         my_ifr.ifr_flagshigh = flags >> 16;
746         if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
747                 Perror(vname);
748 }
749
750 void
751 setifcap(const char *vname, int value, int s, const struct afswtch *afp)
752 {
753         int flags;
754
755         if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
756                 Perror("ioctl (SIOCGIFCAP)");
757                 exit(1);
758         }
759         flags = ifr.ifr_curcap;
760         if (value < 0) {
761                 value = -value;
762                 flags &= ~value;
763         } else
764                 flags |= value;
765         flags &= ifr.ifr_reqcap;
766         ifr.ifr_reqcap = flags;
767         if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
768                 Perror(vname);
769 }
770
771 static void
772 setifmetric(const char *val, int dummy __unused, int s, 
773     const struct afswtch *afp)
774 {
775         strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
776         ifr.ifr_metric = atoi(val);
777         if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
778                 warn("ioctl (set metric)");
779 }
780
781 static void
782 setifmtu(const char *val, int dummy __unused, int s, 
783     const struct afswtch *afp)
784 {
785         strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
786         ifr.ifr_mtu = atoi(val);
787         if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
788                 warn("ioctl (set mtu)");
789 }
790
791 static void
792 setifname(const char *val, int dummy __unused, int s, 
793     const struct afswtch *afp)
794 {
795         char *newname;
796
797         newname = strdup(val);
798         if (newname == NULL) {
799                 warn("no memory to set ifname");
800                 return;
801         }
802         ifr.ifr_data = newname;
803         if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
804                 warn("ioctl (set name)");
805                 free(newname);
806                 return;
807         }
808         strlcpy(name, newname, sizeof(name));
809         free(newname);
810 }
811
812 #define IFFBITS \
813 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
814 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
815 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
816
817 #define IFCAPBITS \
818 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
819 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
820 "\21VLAN_HWFILTER"
821
822 /*
823  * Print the status of the interface.  If an address family was
824  * specified, show only it; otherwise, show them all.
825  */
826 static void
827 status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
828         struct ifaddrs *ifa)
829 {
830         struct ifaddrs *ift;
831         int allfamilies, s;
832         struct ifstat ifs;
833
834         if (afp == NULL) {
835                 allfamilies = 1;
836                 ifr.ifr_addr.sa_family = AF_LOCAL;
837         } else {
838                 allfamilies = 0;
839                 ifr.ifr_addr.sa_family =
840                     afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
841         }
842         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
843
844         s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
845         if (s < 0)
846                 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
847
848         printf("%s: ", name);
849         printb("flags", ifa->ifa_flags, IFFBITS);
850         if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
851                 printf(" metric %d", ifr.ifr_metric);
852         if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
853                 printf(" mtu %d", ifr.ifr_mtu);
854         putchar('\n');
855
856         if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
857                 if (ifr.ifr_curcap != 0) {
858                         printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
859                         putchar('\n');
860                 }
861                 if (supmedia && ifr.ifr_reqcap != 0) {
862                         printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
863                         putchar('\n');
864                 }
865         }
866
867         tunnel_status(s);
868
869         for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
870                 if (ift->ifa_addr == NULL)
871                         continue;
872                 if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
873                         continue;
874                 if (allfamilies) {
875                         const struct afswtch *p;
876                         p = af_getbyfamily(ift->ifa_addr->sa_family);
877                         if (p != NULL && p->af_status != NULL)
878                                 p->af_status(s, ift);
879                 } else if (afp->af_af == ift->ifa_addr->sa_family)
880                         afp->af_status(s, ift);
881         }
882 #if 0
883         if (allfamilies || afp->af_af == AF_LINK) {
884                 const struct afswtch *lafp;
885
886                 /*
887                  * Hack; the link level address is received separately
888                  * from the routing information so any address is not
889                  * handled above.  Cobble together an entry and invoke
890                  * the status method specially.
891                  */
892                 lafp = af_getbyname("lladdr");
893                 if (lafp != NULL) {
894                         info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
895                         lafp->af_status(s, &info);
896                 }
897         }
898 #endif
899         if (allfamilies)
900                 af_other_status(s);
901         else if (afp->af_other_status != NULL)
902                 afp->af_other_status(s);
903
904         strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
905         if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
906                 printf("%s", ifs.ascii);
907
908         close(s);
909         return;
910 }
911
912 static void
913 tunnel_status(int s)
914 {
915         af_all_tunnel_status(s);
916 }
917
918 void
919 Perror(const char *cmd)
920 {
921         switch (errno) {
922
923         case ENXIO:
924                 errx(1, "%s: no such interface", cmd);
925                 break;
926
927         case EPERM:
928                 errx(1, "%s: permission denied", cmd);
929                 break;
930
931         default:
932                 err(1, "%s", cmd);
933         }
934 }
935
936 /*
937  * Print a value a la the %b format of the kernel's printf
938  */
939 void
940 printb(const char *s, unsigned v, const char *bits)
941 {
942         int i, any = 0;
943         char c;
944
945         if (bits && *bits == 8)
946                 printf("%s=%o", s, v);
947         else
948                 printf("%s=%x", s, v);
949         bits++;
950         if (bits) {
951                 putchar('<');
952                 while ((i = *bits++) != '\0') {
953                         if (v & (1 << (i-1))) {
954                                 if (any)
955                                         putchar(',');
956                                 any = 1;
957                                 for (; (c = *bits) > 32; bits++)
958                                         putchar(c);
959                         } else
960                                 for (; *bits > 32; bits++)
961                                         ;
962                 }
963                 putchar('>');
964         }
965 }
966
967 void
968 ifmaybeload(const char *name)
969 {
970 #define MOD_PREFIX_LEN          3       /* "if_" */
971         struct module_stat mstat;
972         int fileid, modid;
973         char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
974         const char *cp;
975
976         /* loading suppressed by the user */
977         if (noload)
978                 return;
979
980         /* trim the interface number off the end */
981         strlcpy(ifname, name, sizeof(ifname));
982         for (dp = ifname; *dp != 0; dp++)
983                 if (isdigit(*dp)) {
984                         *dp = 0;
985                         break;
986                 }
987
988         /* turn interface and unit into module name */
989         strcpy(ifkind, "if_");
990         strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
991             sizeof(ifkind) - MOD_PREFIX_LEN);
992
993         /* scan files in kernel */
994         mstat.version = sizeof(struct module_stat);
995         for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
996                 /* scan modules in file */
997                 for (modid = kldfirstmod(fileid); modid > 0;
998                      modid = modfnext(modid)) {
999                         if (modstat(modid, &mstat) < 0)
1000                                 continue;
1001                         /* strip bus name if present */
1002                         if ((cp = strchr(mstat.name, '/')) != NULL) {
1003                                 cp++;
1004                         } else {
1005                                 cp = mstat.name;
1006                         }
1007                         /* already loaded? */
1008                         if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
1009                             strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
1010                                 return;
1011                 }
1012         }
1013
1014         /* not present, we should try to load it */
1015         kldload(ifkind);
1016 }
1017
1018 static struct cmd basic_cmds[] = {
1019         DEF_CMD("up",           IFF_UP,         setifflags),
1020         DEF_CMD("down",         -IFF_UP,        setifflags),
1021         DEF_CMD("arp",          -IFF_NOARP,     setifflags),
1022         DEF_CMD("-arp",         IFF_NOARP,      setifflags),
1023         DEF_CMD("debug",        IFF_DEBUG,      setifflags),
1024         DEF_CMD("-debug",       -IFF_DEBUG,     setifflags),
1025         DEF_CMD("promisc",      IFF_PPROMISC,   setifflags),
1026         DEF_CMD("-promisc",     -IFF_PPROMISC,  setifflags),
1027         DEF_CMD("add",          IFF_UP,         notealias),
1028         DEF_CMD("alias",        IFF_UP,         notealias),
1029         DEF_CMD("-alias",       -IFF_UP,        notealias),
1030         DEF_CMD("delete",       -IFF_UP,        notealias),
1031         DEF_CMD("remove",       -IFF_UP,        notealias),
1032 #ifdef notdef
1033 #define EN_SWABIPS      0x1000
1034         DEF_CMD("swabips",      EN_SWABIPS,     setifflags),
1035         DEF_CMD("-swabips",     -EN_SWABIPS,    setifflags),
1036 #endif
1037         DEF_CMD_ARG("netmask",                  setifnetmask),
1038         DEF_CMD_ARG("metric",                   setifmetric),
1039         DEF_CMD_ARG("broadcast",                setifbroadaddr),
1040         DEF_CMD_ARG("ipdst",                    setifipdst),
1041         DEF_CMD_ARG2("tunnel",                  settunnel),
1042         DEF_CMD("-tunnel", 0,                   deletetunnel),
1043         DEF_CMD("deletetunnel", 0,              deletetunnel),
1044         DEF_CMD_ARG("vnet",                     setifvnet),
1045         DEF_CMD_ARG("-vnet",                    setifrvnet),
1046         DEF_CMD("link0",        IFF_LINK0,      setifflags),
1047         DEF_CMD("-link0",       -IFF_LINK0,     setifflags),
1048         DEF_CMD("link1",        IFF_LINK1,      setifflags),
1049         DEF_CMD("-link1",       -IFF_LINK1,     setifflags),
1050         DEF_CMD("link2",        IFF_LINK2,      setifflags),
1051         DEF_CMD("-link2",       -IFF_LINK2,     setifflags),
1052         DEF_CMD("monitor",      IFF_MONITOR,    setifflags),
1053         DEF_CMD("-monitor",     -IFF_MONITOR,   setifflags),
1054         DEF_CMD("staticarp",    IFF_STATICARP,  setifflags),
1055         DEF_CMD("-staticarp",   -IFF_STATICARP, setifflags),
1056         DEF_CMD("rxcsum",       IFCAP_RXCSUM,   setifcap),
1057         DEF_CMD("-rxcsum",      -IFCAP_RXCSUM,  setifcap),
1058         DEF_CMD("txcsum",       IFCAP_TXCSUM,   setifcap),
1059         DEF_CMD("-txcsum",      -IFCAP_TXCSUM,  setifcap),
1060         DEF_CMD("netcons",      IFCAP_NETCONS,  setifcap),
1061         DEF_CMD("-netcons",     -IFCAP_NETCONS, setifcap),
1062         DEF_CMD("polling",      IFCAP_POLLING,  setifcap),
1063         DEF_CMD("-polling",     -IFCAP_POLLING, setifcap),
1064         DEF_CMD("tso",          IFCAP_TSO,      setifcap),
1065         DEF_CMD("-tso",         -IFCAP_TSO,     setifcap),
1066         DEF_CMD("lro",          IFCAP_LRO,      setifcap),
1067         DEF_CMD("-lro",         -IFCAP_LRO,     setifcap),
1068         DEF_CMD("wol",          IFCAP_WOL,      setifcap),
1069         DEF_CMD("-wol",         -IFCAP_WOL,     setifcap),
1070         DEF_CMD("wol_ucast",    IFCAP_WOL_UCAST,        setifcap),
1071         DEF_CMD("-wol_ucast",   -IFCAP_WOL_UCAST,       setifcap),
1072         DEF_CMD("wol_mcast",    IFCAP_WOL_MCAST,        setifcap),
1073         DEF_CMD("-wol_mcast",   -IFCAP_WOL_MCAST,       setifcap),
1074         DEF_CMD("wol_magic",    IFCAP_WOL_MAGIC,        setifcap),
1075         DEF_CMD("-wol_magic",   -IFCAP_WOL_MAGIC,       setifcap),
1076         DEF_CMD("normal",       -IFF_LINK0,     setifflags),
1077         DEF_CMD("compress",     IFF_LINK0,      setifflags),
1078         DEF_CMD("noicmp",       IFF_LINK1,      setifflags),
1079         DEF_CMD_ARG("mtu",                      setifmtu),
1080         DEF_CMD_ARG("name",                     setifname),
1081 };
1082
1083 static __constructor void
1084 ifconfig_ctor(void)
1085 {
1086 #define N(a)    (sizeof(a) / sizeof(a[0]))
1087         size_t i;
1088
1089         for (i = 0; i < N(basic_cmds);  i++)
1090                 cmd_register(&basic_cmds[i]);
1091 #undef N
1092 }