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