ifconfig.c revision 1.31 1 /* $NetBSD: ifconfig.c,v 1.31 1997/03/27 22:50:12 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1997 Jason R. Thorpe.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by Jason R. Thorpe.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1983, 1993
37 * The Regents of the University of California. All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the University of
50 * California, Berkeley and its contributors.
51 * 4. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 */
67
68 #ifndef lint
69 static char copyright[] =
70 "@(#) Copyright (c) 1983, 1993\n\
71 The Regents of the University of California. All rights reserved.\n";
72 #endif /* not lint */
73
74 #ifndef lint
75 #if 0
76 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
77 #else
78 static char rcsid[] = "$NetBSD: ifconfig.c,v 1.31 1997/03/27 22:50:12 thorpej Exp $";
79 #endif
80 #endif /* not lint */
81
82 #include <sys/param.h>
83 #include <sys/socket.h>
84 #include <sys/ioctl.h>
85
86 #include <net/if.h>
87 #include <net/if_dl.h>
88 #include <net/if_media.h>
89 #include <netinet/in.h>
90 #include <arpa/inet.h>
91
92 #define NSIP
93 #include <netns/ns.h>
94 #include <netns/ns_if.h>
95 #include <netdb.h>
96
97 #define EON
98 #include <netiso/iso.h>
99 #include <netiso/iso_var.h>
100 #include <sys/protosw.h>
101
102 #include <ctype.h>
103 #include <err.h>
104 #include <errno.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <unistd.h>
109
110 struct ifreq ifr, ridreq;
111 struct ifaliasreq addreq;
112 struct iso_aliasreq iso_addreq;
113 struct sockaddr_in netmask;
114 char name[30];
115 int flags, metric, setaddr, setipdst, doalias;
116 int clearaddr, s;
117 int newaddr = 1;
118 int nsellength = 1;
119 int af;
120 int mflag, lflag;
121
122 void notealias __P((char *, int));
123 void notrailers __P((char *, int));
124 void setifaddr __P((char *, int));
125 void setifdstaddr __P((char *, int));
126 void setifflags __P((char *, int));
127 void setifbroadaddr __P((char *));
128 void setifipdst __P((char *));
129 void setifmetric __P((char *));
130 void setifnetmask __P((char *));
131 void setnsellength __P((char *));
132 void setsnpaoffset __P((char *));
133 void setmedia __P((char *));
134 void setmediaopt __P((char *));
135 void unsetmediaopt __P((char *));
136
137 #define NEXTARG 0xffffff
138
139 struct cmd {
140 char *c_name;
141 int c_parameter; /* NEXTARG means next argv */
142 void (*c_func)();
143 } cmds[] = {
144 { "up", IFF_UP, setifflags } ,
145 { "down", -IFF_UP, setifflags },
146 { "trailers", -1, notrailers },
147 { "-trailers", 1, notrailers },
148 { "arp", -IFF_NOARP, setifflags },
149 { "-arp", IFF_NOARP, setifflags },
150 { "debug", IFF_DEBUG, setifflags },
151 { "-debug", -IFF_DEBUG, setifflags },
152 { "alias", IFF_UP, notealias },
153 { "-alias", -IFF_UP, notealias },
154 { "delete", -IFF_UP, notealias },
155 #ifdef notdef
156 #define EN_SWABIPS 0x1000
157 { "swabips", EN_SWABIPS, setifflags },
158 { "-swabips", -EN_SWABIPS, setifflags },
159 #endif
160 { "netmask", NEXTARG, setifnetmask },
161 { "metric", NEXTARG, setifmetric },
162 { "broadcast", NEXTARG, setifbroadaddr },
163 { "ipdst", NEXTARG, setifipdst },
164 #ifndef INET_ONLY
165 { "snpaoffset", NEXTARG, setsnpaoffset },
166 { "nsellength", NEXTARG, setnsellength },
167 #endif /* INET_ONLY */
168 { "link0", IFF_LINK0, setifflags } ,
169 { "-link0", -IFF_LINK0, setifflags } ,
170 { "link1", IFF_LINK1, setifflags } ,
171 { "-link1", -IFF_LINK1, setifflags } ,
172 { "link2", IFF_LINK2, setifflags } ,
173 { "-link2", -IFF_LINK2, setifflags } ,
174 { "media", NEXTARG, setmedia },
175 { "mediaopt", NEXTARG, setmediaopt },
176 { "-mediaopt", NEXTARG, unsetmediaopt },
177 { 0, 0, setifaddr },
178 { 0, 0, setifdstaddr },
179 };
180
181 void adjust_nsellength();
182 int getinfo __P((struct ifreq *));
183 void getsock __P((int));
184 void printall __P((void));
185 void printb __P((char *, unsigned short, char *));
186 void status __P((const u_int8_t *, int));
187 void usage();
188
189 void domediaopt __P((char *, int));
190 int get_media_subtype __P((int, char *));
191 int get_media_options __P((int, char *));
192 int lookup_media_word __P((struct ifmedia_description *, char *));
193 void print_media_word __P((int));
194
195 /*
196 * XNS support liberally adapted from code written at the University of
197 * Maryland principally by James O'Toole and Chris Torek.
198 */
199 void in_status __P((int));
200 void in_getaddr __P((char *, int));
201 void xns_status __P((int));
202 void xns_getaddr __P((char *, int));
203 void iso_status __P((int));
204 void iso_getaddr __P((char *, int));
205
206 /* Known address families */
207 struct afswtch {
208 char *af_name;
209 short af_af;
210 void (*af_status)();
211 void (*af_getaddr)();
212 u_long af_difaddr;
213 u_long af_aifaddr;
214 caddr_t af_ridreq;
215 caddr_t af_addreq;
216 } afs[] = {
217 #define C(x) ((caddr_t) &x)
218 { "inet", AF_INET, in_status, in_getaddr,
219 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
220 #ifndef INET_ONLY /* small version, for boot media */
221 { "ns", AF_NS, xns_status, xns_getaddr,
222 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
223 { "iso", AF_ISO, iso_status, iso_getaddr,
224 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(iso_addreq) },
225 #endif /* INET_ONLY */
226 { 0, 0, 0, 0 }
227 };
228
229 struct afswtch *afp; /*the address family being set or asked about*/
230
231 struct afswtch *lookup_af __P((const char *));
232
233 int
234 main(argc, argv)
235 int argc;
236 char *argv[];
237 {
238 extern int optind;
239 int ch, aflag;
240
241 /* Parse command-line options */
242 aflag = mflag = 0;
243 while ((ch = getopt(argc, argv, "alm")) != -1) {
244 switch (ch) {
245 case 'a':
246 aflag = 1;
247 break;
248
249 case 'l':
250 lflag = 1;
251 break;
252
253 case 'm':
254 mflag = 1;
255 break;
256
257 default:
258 usage();
259 /* NOTREACHED */
260 }
261 }
262 argc -= optind;
263 argv += optind;
264
265 /*
266 * -l means "list all interfaces", and is mutally exclusive with
267 * all other flags/commands.
268 *
269 * -a means "print status of all interfaces".
270 */
271 if (lflag && (aflag || mflag || argc))
272 usage();
273 if (aflag || lflag) {
274 if (argc > 1)
275 usage();
276 else if (argc == 1) {
277 afp = lookup_af(argv[0]);
278 if (afp == NULL)
279 usage();
280 } else
281 afp = afs;
282 af = ifr.ifr_addr.sa_family = afp->af_af;
283
284 printall();
285 exit(0);
286 }
287
288 /* Make sure there's an interface name. */
289 if (argc < 1)
290 usage();
291 strncpy(name, argv[0], sizeof(name));
292 argc--; argv++;
293
294 /* Check for address family. */
295 afp = NULL;
296 if (argc > 0) {
297 afp = lookup_af(argv[0]);
298 if (afp != NULL) {
299 argv++;
300 argc--;
301 }
302 }
303
304 if (afp == NULL)
305 afp = afs;
306 af = ifr.ifr_addr.sa_family = afp->af_af;
307
308 /* Get information about the interface. */
309 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
310 if (getinfo(&ifr) < 0)
311 exit(1);
312
313 /* No more arguments means interface status. */
314 if (argc == 0) {
315 status(NULL, 0);
316 exit(0);
317 }
318
319 /* Process commands. */
320 while (argc > 0) {
321 register struct cmd *p;
322
323 for (p = cmds; p->c_name; p++)
324 if (strcmp(argv[0], p->c_name) == 0)
325 break;
326 if (p->c_name == 0 && setaddr)
327 p++; /* got src, do dst */
328 if (p->c_func) {
329 if (p->c_parameter == NEXTARG) {
330 if (argc < 2)
331 errx(1, "'%s' requires argument",
332 p->c_name);
333 (*p->c_func)(argv[1]);
334 argc--, argv++;
335 } else
336 (*p->c_func)(argv[0], p->c_parameter);
337 }
338 argc--, argv++;
339 }
340
341 #ifndef INET_ONLY
342
343 if (af == AF_ISO)
344 adjust_nsellength();
345 if (setipdst && af==AF_NS) {
346 struct nsip_req rq;
347 int size = sizeof(rq);
348
349 rq.rq_ns = addreq.ifra_addr;
350 rq.rq_ip = addreq.ifra_dstaddr;
351
352 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
353 warn("encapsulation routing");
354 }
355
356 #endif /* INET_ONLY */
357
358 if (clearaddr) {
359 int ret;
360 strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
361 if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
362 if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
363 /* means no previous address for interface */
364 } else
365 warn("SIOCDIFADDR");
366 }
367 }
368 if (newaddr) {
369 strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
370 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
371 warn("SIOCAIFADDR");
372 }
373 exit(0);
374 }
375
376 struct afswtch *
377 lookup_af(cp)
378 const char *cp;
379 {
380 struct afswtch *a;
381
382 for (a = afs; a->af_name != NULL; a++)
383 if (strcmp(a->af_name, cp) == 0)
384 return (a);
385 return (NULL);
386 }
387
388 void
389 getsock(naf)
390 int naf;
391 {
392 static int oaf = -1;
393
394 if (oaf == naf)
395 return;
396 if (oaf != -1)
397 close(s);
398 s = socket(naf, SOCK_DGRAM, 0);
399 if (s < 0)
400 oaf = -1;
401 else
402 oaf = naf;
403 }
404
405 int
406 getinfo(ifr)
407 struct ifreq *ifr;
408 {
409
410 getsock(af);
411 if (s < 0)
412 err(1, "socket");
413 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
414 warn("SIOCGIFFLAGS");
415 return (-1);
416 }
417 flags = ifr->ifr_flags;
418 if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
419 warn("SIOCGIFMETRIC");
420 metric = 0;
421 } else
422 metric = ifr->ifr_metric;
423 return (0);
424 }
425
426 void
427 printall()
428 {
429 char inbuf[8192];
430 const struct sockaddr_dl *sdl = NULL;
431 struct ifconf ifc;
432 struct ifreq ifreq, *ifr;
433 int i, idx;
434
435 ifc.ifc_len = sizeof(inbuf);
436 ifc.ifc_buf = inbuf;
437 getsock(af);
438 if (s < 0)
439 err(1, "socket");
440 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
441 err(1, "SIOCGIFCONF");
442 ifr = ifc.ifc_req;
443 ifreq.ifr_name[0] = '\0';
444 for (i = 0, idx = 0; i < ifc.ifc_len; idx++) {
445 ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
446 i += sizeof(ifr->ifr_name) +
447 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
448 ? ifr->ifr_addr.sa_len
449 : sizeof(struct sockaddr));
450 if (ifr->ifr_addr.sa_family == AF_LINK)
451 sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
452 if (!strncmp(ifreq.ifr_name, ifr->ifr_name,
453 sizeof(ifr->ifr_name)))
454 continue;
455 strncpy(name, ifr->ifr_name, sizeof(ifr->ifr_name));
456 ifreq = *ifr;
457
458 /*
459 * Are we just listing the interfaces?
460 */
461 if (lflag) {
462 if (idx)
463 putchar(' ');
464 printf(name);
465 continue;
466 }
467
468 if (getinfo(&ifreq) < 0)
469 continue;
470 if (sdl == NULL) {
471 status(NULL, 0);
472 } else {
473 status(LLADDR(sdl), sdl->sdl_alen);
474 sdl = NULL;
475 }
476 }
477 if (lflag)
478 putchar('\n');
479 }
480
481 #define RIDADDR 0
482 #define ADDR 1
483 #define MASK 2
484 #define DSTADDR 3
485
486 /*ARGSUSED*/
487 void
488 setifaddr(addr, param)
489 char *addr;
490 int param;
491 {
492 /*
493 * Delay the ioctl to set the interface addr until flags are all set.
494 * The address interpretation may depend on the flags,
495 * and the flags may change when the address is set.
496 */
497 setaddr++;
498 if (doalias == 0)
499 clearaddr = 1;
500 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
501 }
502
503 void
504 setifnetmask(addr)
505 char *addr;
506 {
507 (*afp->af_getaddr)(addr, MASK);
508 }
509
510 void
511 setifbroadaddr(addr)
512 char *addr;
513 {
514 (*afp->af_getaddr)(addr, DSTADDR);
515 }
516
517 void
518 setifipdst(addr)
519 char *addr;
520 {
521 in_getaddr(addr, DSTADDR);
522 setipdst++;
523 clearaddr = 0;
524 newaddr = 0;
525 }
526
527 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
528 /*ARGSUSED*/
529 void
530 notealias(addr, param)
531 char *addr;
532 int param;
533 {
534 if (setaddr && doalias == 0 && param < 0)
535 memcpy(rqtosa(af_ridreq),
536 rqtosa(af_addreq),
537 rqtosa(af_addreq)->sa_len);
538 doalias = param;
539 if (param < 0) {
540 clearaddr = 1;
541 newaddr = 0;
542 } else
543 clearaddr = 0;
544 }
545
546 /*ARGSUSED*/
547 void
548 notrailers(vname, value)
549 char *vname;
550 int value;
551 {
552 printf("Note: trailers are no longer sent, but always received\n");
553 }
554
555 /*ARGSUSED*/
556 void
557 setifdstaddr(addr, param)
558 char *addr;
559 int param;
560 {
561 (*afp->af_getaddr)(addr, DSTADDR);
562 }
563
564 void
565 setifflags(vname, value)
566 char *vname;
567 int value;
568 {
569 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
570 err(1, "SIOCGIFFLAGS");
571 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
572 flags = ifr.ifr_flags;
573
574 if (value < 0) {
575 value = -value;
576 flags &= ~value;
577 } else
578 flags |= value;
579 ifr.ifr_flags = flags;
580 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
581 err(1, "SIOCSIFFLAGS");
582 }
583
584 void
585 setifmetric(val)
586 char *val;
587 {
588 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
589 ifr.ifr_metric = atoi(val);
590 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
591 warn("SIOCSIFMETRIC");
592 }
593
594 void
595 setmedia(val)
596 char *val;
597 {
598 struct ifmediareq ifmr;
599 int first_type, subtype;
600
601 memset(&ifmr, 0, sizeof(ifmr));
602 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
603
604 ifmr.ifm_count = 1;
605 ifmr.ifm_ulist = &first_type;
606 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
607 /*
608 * If we get E2BIG, the kernel is telling us
609 * that there are more, so we can ignore it.
610 */
611 if (errno != E2BIG)
612 err(1, "SIOCGIFMEDIA");
613 }
614
615 if (ifmr.ifm_count == 0)
616 errx(1, "%s: no media types?", name);
617
618 /*
619 * We are primarily concerned with the top-level type.
620 * However, "current" may be only IFM_NONE, so we just look
621 * for the top-level type in the first "supported type"
622 * entry.
623 *
624 * (I'm assuming that all supported media types for a given
625 * interface will be the same top-level type..)
626 */
627 subtype = get_media_subtype(IFM_TYPE(first_type), val);
628
629 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
630 ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
631 IFM_TYPE(first_type) | subtype;
632
633 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
634 err(1, "SIOCSIFMEDIA");
635 }
636
637 void
638 setmediaopt(val)
639 char *val;
640 {
641
642 domediaopt(val, 0);
643 }
644
645 void
646 unsetmediaopt(val)
647 char *val;
648 {
649
650 domediaopt(val, 1);
651 }
652
653 void
654 domediaopt(val, clear)
655 char *val;
656 int clear;
657 {
658 struct ifmediareq ifmr;
659 int *mwords, options;
660
661 memset(&ifmr, 0, sizeof(ifmr));
662 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
663
664 /*
665 * We must go through the motions of reading all
666 * supported media because we need to know both
667 * the current media type and the top-level type.
668 */
669
670 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
671 err(1, "SIOCGIFMEDIA");
672
673 if (ifmr.ifm_count == 0)
674 errx(1, "%s: no media types?", name);
675
676 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
677 if (mwords == NULL)
678 err(1, "malloc");
679
680 ifmr.ifm_ulist = mwords;
681 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
682 err(1, "SIOCGIFMEDIA");
683
684 options = get_media_options(IFM_TYPE(mwords[0]), val);
685
686 free(mwords);
687
688 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
689 ifr.ifr_media = ifmr.ifm_current;
690 if (clear)
691 ifr.ifr_media &= ~options;
692 else
693 ifr.ifr_media |= options;
694
695 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
696 err(1, "SIOCSIFMEDIA");
697 }
698
699 /**********************************************************************
700 * A good chunk of this is duplicated from sys/net/ifmedia.c
701 **********************************************************************/
702
703 struct ifmedia_description ifm_type_descriptions[] =
704 IFM_TYPE_DESCRIPTIONS;
705
706 struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
707 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
708
709 struct ifmedia_description ifm_subtype_ethernet_aliases[] =
710 IFM_SUBTYPE_ETHERNET_ALIASES;
711
712 struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
713 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
714
715 struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
716 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
717
718 struct ifmedia_description ifm_subtype_tokenring_aliases[] =
719 IFM_SUBTYPE_TOKENRING_ALIASES;
720
721 struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
722 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
723
724 struct ifmedia_description ifm_subtype_fddi_descriptions[] =
725 IFM_SUBTYPE_FDDI_DESCRIPTIONS;
726
727 struct ifmedia_description ifm_subtype_fddi_aliases[] =
728 IFM_SUBTYPE_FDDI_ALIASES;
729
730 struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
731 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
732
733 struct ifmedia_description ifm_subtype_shared_descriptions[] =
734 IFM_SUBTYPE_SHARED_DESCRIPTIONS;
735
736 struct ifmedia_description ifm_subtype_shared_aliases[] =
737 IFM_SUBTYPE_SHARED_ALIASES;
738
739 struct ifmedia_description ifm_shared_option_descriptions[] =
740 IFM_SHARED_OPTION_DESCRIPTIONS;
741
742 struct ifmedia_type_to_subtype {
743 struct {
744 struct ifmedia_description *desc;
745 int alias;
746 } subtypes[5];
747 struct {
748 struct ifmedia_description *desc;
749 int alias;
750 } options[3];
751 };
752
753 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
754 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
755 {
756 {
757 { &ifm_subtype_shared_descriptions[0], 0 },
758 { &ifm_subtype_shared_aliases[0], 1 },
759 { &ifm_subtype_ethernet_descriptions[0], 0 },
760 { &ifm_subtype_ethernet_aliases[0], 1 },
761 { NULL, 0 },
762 },
763 {
764 { &ifm_shared_option_descriptions[0], 0 },
765 { &ifm_subtype_ethernet_option_descriptions[0], 1 },
766 { NULL, 0 },
767 },
768 },
769 {
770 {
771 { &ifm_subtype_shared_descriptions[0], 0 },
772 { &ifm_subtype_shared_aliases[0], 1 },
773 { &ifm_subtype_tokenring_descriptions[0], 0 },
774 { &ifm_subtype_tokenring_aliases[0], 1 },
775 { NULL, 0 },
776 },
777 {
778 { &ifm_shared_option_descriptions[0], 0 },
779 { &ifm_subtype_tokenring_option_descriptions[0], 1 },
780 { NULL, 0 },
781 },
782 },
783 {
784 {
785 { &ifm_subtype_shared_descriptions[0], 0 },
786 { &ifm_subtype_shared_aliases[0], 1 },
787 { &ifm_subtype_fddi_descriptions[0], 0 },
788 { &ifm_subtype_fddi_aliases[0], 1 },
789 { NULL, 0 },
790 },
791 {
792 { &ifm_shared_option_descriptions[0], 0 },
793 { &ifm_subtype_fddi_option_descriptions[0], 1 },
794 { NULL, 0 },
795 },
796 },
797 };
798
799 int
800 get_media_subtype(type, val)
801 int type;
802 char *val;
803 {
804 struct ifmedia_description *desc;
805 struct ifmedia_type_to_subtype *ttos;
806 int rval, i;
807
808 /* Find the top-level interface type. */
809 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
810 desc->ifmt_string != NULL; desc++, ttos++)
811 if (type == desc->ifmt_word)
812 break;
813 if (desc->ifmt_string == NULL)
814 errx(1, "unknown media type 0x%x", type);
815
816 for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
817 rval = lookup_media_word(ttos->subtypes[i].desc, val);
818 if (rval != -1)
819 return (rval);
820 }
821 errx(1, "unknown media subtype: %s", val);
822 /* NOTREACHED */
823 }
824
825 int
826 get_media_options(type, val)
827 int type;
828 char *val;
829 {
830 struct ifmedia_description *desc;
831 struct ifmedia_type_to_subtype *ttos;
832 char *optlist;
833 int option, i, rval = 0;
834
835 /* We muck with the string, so copy it. */
836 optlist = strdup(val);
837 if (optlist == NULL)
838 err(1, "strdup");
839 val = optlist;
840
841 /* Find the top-level interface type. */
842 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
843 desc->ifmt_string != NULL; desc++, ttos++)
844 if (type == desc->ifmt_word)
845 break;
846 if (desc->ifmt_string == NULL)
847 errx(1, "unknown media type 0x%x", type);
848
849 /*
850 * Look up the options in the user-provided comma-separated
851 * list.
852 */
853 for (; (val = strtok(val, ",")) != NULL; val = NULL) {
854 for (i = 0; ttos->options[i].desc != NULL; i++) {
855 option = lookup_media_word(ttos->options[i].desc, val);
856 if (option != -1)
857 break;
858 }
859 if (option == 0)
860 errx(1, "unknown option: %s", val);
861 rval |= option;
862 }
863
864 free(optlist);
865 return (rval);
866 }
867
868 int
869 lookup_media_word(desc, val)
870 struct ifmedia_description *desc;
871 char *val;
872 {
873
874 for (; desc->ifmt_string != NULL; desc++)
875 if (strcasecmp(desc->ifmt_string, val) == 0)
876 return (desc->ifmt_word);
877
878 return (-1);
879 }
880
881 void
882 print_media_word(ifmw)
883 int ifmw;
884 {
885 struct ifmedia_description *desc;
886 struct ifmedia_type_to_subtype *ttos;
887 int seen_option = 0, i;
888
889 /* Find the top-level interface type. */
890 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
891 desc->ifmt_string != NULL; desc++, ttos++)
892 if (IFM_TYPE(ifmw) == desc->ifmt_word)
893 break;
894 if (desc->ifmt_string == NULL) {
895 printf("<unknown type>");
896 return;
897 }
898
899 /*
900 * Don't print the top-level type; it's not like we can
901 * change it, or anything.
902 */
903
904 /* Find subtype. */
905 for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
906 if (ttos->subtypes[i].alias)
907 continue;
908 for (desc = ttos->subtypes[i].desc;
909 desc->ifmt_string != NULL; desc++) {
910 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
911 goto got_subtype;
912 }
913 }
914
915 /* Falling to here means unknown subtype. */
916 printf("<unknown subtype>");
917 return;
918
919 got_subtype:
920 printf("%s", desc->ifmt_string);
921
922 /* Find options. */
923 for (i = 0; ttos->options[i].desc != NULL; i++) {
924 if (ttos->options[i].alias)
925 continue;
926 for (desc = ttos->options[i].desc;
927 desc->ifmt_string != NULL; desc++) {
928 if (ifmw & desc->ifmt_word) {
929 if (seen_option == 0)
930 printf(" <");
931 printf("%s%s", seen_option++ ? "," : "",
932 desc->ifmt_string);
933 }
934 }
935 }
936 printf("%s", seen_option ? ">" : "");
937 }
938
939 /**********************************************************************
940 * ...until here.
941 **********************************************************************/
942
943 #define IFFBITS \
944 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
945 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
946
947 /*
948 * Print the status of the interface. If an address family was
949 * specified, show it and it only; otherwise, show them all.
950 */
951 void
952 status(ap, alen)
953 const u_int8_t *ap;
954 int alen;
955 {
956 register struct afswtch *p = afp;
957 struct ifmediareq ifmr;
958 int *media_list, i;
959
960 printf("%s: ", name);
961 printb("flags", flags, IFFBITS);
962 if (metric)
963 printf(" metric %d", metric);
964 putchar('\n');
965 if (ap && alen > 0) {
966 printf("\taddress:");
967 for (i = 0; i < alen; i++, ap++)
968 printf("%c%02x", i > 0 ? ':' : ' ', *ap);
969 putchar('\n');
970 }
971
972 memset(&ifmr, 0, sizeof(ifmr));
973 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
974
975 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
976 /*
977 * Interface doesn't support SIOC{G,S}IFMEDIA.
978 */
979 goto proto_status;
980 }
981
982 if (ifmr.ifm_count == 0) {
983 warnx("%s: no media types?", name);
984 goto proto_status;
985 }
986
987 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
988 if (media_list == NULL)
989 err(1, "malloc");
990 ifmr.ifm_ulist = media_list;
991
992 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
993 err(1, "SIOCGIFMEDIA");
994
995 printf("\tmedia: ");
996 print_media_word(ifmr.ifm_current);
997 if (ifmr.ifm_active != ifmr.ifm_current) {
998 putchar(' ');
999 putchar('(');
1000 print_media_word(ifmr.ifm_active);
1001 putchar(')');
1002 }
1003
1004 if (ifmr.ifm_status & IFM_AVALID) {
1005 printf(" status: ");
1006 switch (IFM_TYPE(ifmr.ifm_active)) {
1007 case IFM_ETHER:
1008 if (ifmr.ifm_status & IFM_ACTIVE)
1009 printf("active");
1010 else
1011 printf("no carrier");
1012 break;
1013
1014 case IFM_FDDI:
1015 case IFM_TOKEN:
1016 if (ifmr.ifm_status & IFM_ACTIVE)
1017 printf("inserted");
1018 else
1019 printf("no ring");
1020 break;
1021 }
1022 }
1023
1024 putchar('\n');
1025
1026 if (mflag) {
1027 printf("\tsupported media:");
1028 for (i = 0; i < ifmr.ifm_count; i++) {
1029 putchar(' ');
1030 print_media_word(media_list[i]);
1031 }
1032 putchar('\n');
1033 }
1034
1035 free(media_list);
1036
1037 proto_status:
1038 if ((p = afp) != NULL) {
1039 (*p->af_status)(1);
1040 } else for (p = afs; p->af_name; p++) {
1041 ifr.ifr_addr.sa_family = p->af_af;
1042 (*p->af_status)(0);
1043 }
1044 }
1045
1046 void
1047 in_status(force)
1048 int force;
1049 {
1050 struct sockaddr_in *sin;
1051 char *inet_ntoa();
1052
1053 getsock(AF_INET);
1054 if (s < 0) {
1055 if (errno == EPROTONOSUPPORT)
1056 return;
1057 err(1, "socket");
1058 }
1059 memset(&ifr, 0, sizeof(ifr));
1060 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1061 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1062 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1063 if (!force)
1064 return;
1065 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1066 } else
1067 warn("SIOCGIFADDR");
1068 }
1069 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1070 sin = (struct sockaddr_in *)&ifr.ifr_addr;
1071 printf("\tinet %s ", inet_ntoa(sin->sin_addr));
1072 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1073 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1074 if (errno != EADDRNOTAVAIL)
1075 warn("SIOCGIFNETMASK");
1076 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1077 } else
1078 netmask.sin_addr =
1079 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1080 if (flags & IFF_POINTOPOINT) {
1081 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1082 if (errno == EADDRNOTAVAIL)
1083 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1084 else
1085 warn("SIOCGIFDSTADDR");
1086 }
1087 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1088 sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1089 printf("--> %s ", inet_ntoa(sin->sin_addr));
1090 }
1091 printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
1092 if (flags & IFF_BROADCAST) {
1093 if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
1094 if (errno == EADDRNOTAVAIL)
1095 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1096 else
1097 warn("SIOCGIFBRDADDR");
1098 }
1099 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1100 sin = (struct sockaddr_in *)&ifr.ifr_addr;
1101 if (sin->sin_addr.s_addr != 0)
1102 printf("broadcast %s", inet_ntoa(sin->sin_addr));
1103 }
1104 putchar('\n');
1105 }
1106
1107 #ifndef INET_ONLY
1108
1109 void
1110 xns_status(force)
1111 int force;
1112 {
1113 struct sockaddr_ns *sns;
1114
1115 getsock(AF_NS);
1116 if (s < 0) {
1117 if (errno == EPROTONOSUPPORT)
1118 return;
1119 err(1, "socket");
1120 }
1121 memset(&ifr, 0, sizeof(ifr));
1122 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1123 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1124 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1125 if (!force)
1126 return;
1127 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1128 } else
1129 warn("SIOCGIFADDR");
1130 }
1131 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1132 sns = (struct sockaddr_ns *)&ifr.ifr_addr;
1133 printf("\tns %s ", ns_ntoa(sns->sns_addr));
1134 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1135 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1136 if (errno == EADDRNOTAVAIL)
1137 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1138 else
1139 warn("SIOCGIFDSTADDR");
1140 }
1141 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1142 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
1143 printf("--> %s ", ns_ntoa(sns->sns_addr));
1144 }
1145 putchar('\n');
1146 }
1147
1148 void
1149 iso_status(force)
1150 int force;
1151 {
1152 struct sockaddr_iso *siso;
1153
1154 getsock(AF_ISO);
1155 if (s < 0) {
1156 if (errno == EPROTONOSUPPORT)
1157 return;
1158 err(1, "socket");
1159 }
1160 memset(&ifr, 0, sizeof(ifr));
1161 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1162 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1163 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1164 if (!force)
1165 return;
1166 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1167 } else
1168 warn("SIOCGIFADDR");
1169 }
1170 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1171 siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1172 printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
1173 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1174 if (errno == EADDRNOTAVAIL)
1175 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1176 else
1177 warn("SIOCGIFNETMASK");
1178 } else {
1179 printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
1180 }
1181 if (flags & IFF_POINTOPOINT) {
1182 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1183 if (errno == EADDRNOTAVAIL)
1184 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1185 else
1186 warn("SIOCGIFDSTADDR");
1187 }
1188 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1189 siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1190 printf("--> %s ", iso_ntoa(&siso->siso_addr));
1191 }
1192 putchar('\n');
1193 }
1194
1195 #endif /* INET_ONLY */
1196
1197 struct in_addr inet_makeaddr();
1198
1199 #define SIN(x) ((struct sockaddr_in *) &(x))
1200 struct sockaddr_in *sintab[] = {
1201 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1202 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1203
1204 void
1205 in_getaddr(s, which)
1206 char *s;
1207 int which;
1208 {
1209 register struct sockaddr_in *sin = sintab[which];
1210 struct hostent *hp;
1211 struct netent *np;
1212
1213 sin->sin_len = sizeof(*sin);
1214 if (which != MASK)
1215 sin->sin_family = AF_INET;
1216
1217 if (inet_aton(s, &sin->sin_addr) == 0) {
1218 if (hp = gethostbyname(s))
1219 memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1220 else if (np = getnetbyname(s))
1221 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1222 else
1223 errx(1, "%s: bad value", s);
1224 }
1225 }
1226
1227 /*
1228 * Print a value a la the %b format of the kernel's printf
1229 */
1230 void
1231 printb(s, v, bits)
1232 char *s;
1233 register char *bits;
1234 register unsigned short v;
1235 {
1236 register int i, any = 0;
1237 register char c;
1238
1239 if (bits && *bits == 8)
1240 printf("%s=%o", s, v);
1241 else
1242 printf("%s=%x", s, v);
1243 bits++;
1244 if (bits) {
1245 putchar('<');
1246 while (i = *bits++) {
1247 if (v & (1 << (i-1))) {
1248 if (any)
1249 putchar(',');
1250 any = 1;
1251 for (; (c = *bits) > 32; bits++)
1252 putchar(c);
1253 } else
1254 for (; *bits > 32; bits++)
1255 ;
1256 }
1257 putchar('>');
1258 }
1259 }
1260
1261 #ifndef INET_ONLY
1262
1263 #define SNS(x) ((struct sockaddr_ns *) &(x))
1264 struct sockaddr_ns *snstab[] = {
1265 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1266 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1267
1268 void
1269 xns_getaddr(addr, which)
1270 char *addr;
1271 int which;
1272 {
1273 struct sockaddr_ns *sns = snstab[which];
1274 struct ns_addr ns_addr();
1275
1276 sns->sns_family = AF_NS;
1277 sns->sns_len = sizeof(*sns);
1278 sns->sns_addr = ns_addr(addr);
1279 if (which == MASK)
1280 printf("Attempt to set XNS netmask will be ineffectual\n");
1281 }
1282
1283 #define SISO(x) ((struct sockaddr_iso *) &(x))
1284 struct sockaddr_iso *sisotab[] = {
1285 SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1286 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1287
1288 void
1289 iso_getaddr(addr, which)
1290 char *addr;
1291 int which;
1292 {
1293 register struct sockaddr_iso *siso = sisotab[which];
1294 struct iso_addr *iso_addr();
1295 siso->siso_addr = *iso_addr(addr);
1296
1297 if (which == MASK) {
1298 siso->siso_len = TSEL(siso) - (caddr_t)(siso);
1299 siso->siso_nlen = 0;
1300 } else {
1301 siso->siso_len = sizeof(*siso);
1302 siso->siso_family = AF_ISO;
1303 }
1304 }
1305
1306 void
1307 setsnpaoffset(val)
1308 char *val;
1309 {
1310 iso_addreq.ifra_snpaoffset = atoi(val);
1311 }
1312
1313 void
1314 setnsellength(val)
1315 char *val;
1316 {
1317 nsellength = atoi(val);
1318 if (nsellength < 0)
1319 errx(1, "Negative NSEL length is absurd");
1320 if (afp == 0 || afp->af_af != AF_ISO)
1321 errx(1, "Setting NSEL length valid only for iso");
1322 }
1323
1324 void
1325 fixnsel(s)
1326 register struct sockaddr_iso *s;
1327 {
1328 if (s->siso_family == 0)
1329 return;
1330 s->siso_tlen = nsellength;
1331 }
1332
1333 void
1334 adjust_nsellength()
1335 {
1336 fixnsel(sisotab[RIDADDR]);
1337 fixnsel(sisotab[ADDR]);
1338 fixnsel(sisotab[DSTADDR]);
1339 }
1340
1341 #endif /* INET_ONLY */
1342
1343 void
1344 usage()
1345 {
1346 fprintf(stderr,
1347 "usage: ifconfig [ -m ] interface\n%s%s%s%s%s%s%s%s%s%s",
1348 "\t[ af [ address [ dest_addr ] ] [ up ] [ down ] ",
1349 "[ netmask mask ] ]\n",
1350 "\t[ metric n ]\n",
1351 "\t[ arp | -arp ]\n",
1352 "\t[ media mtype ]\n",
1353 "\t[ mediaopt mopts ]\n",
1354 "\t[ -mediaopt mopts ]\n",
1355 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n",
1356 " ifconfig -a [ -m ] [ af ]\n",
1357 " ifconfig -l\n");
1358 exit(1);
1359 }
1360