ifconfig.c revision 1.30 1 /* $NetBSD: ifconfig.c,v 1.30 1997/03/26 01:46:49 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.30 1997/03/26 01:46:49 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;
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, "am")) != -1) {
244 switch (ch) {
245 case 'a':
246 aflag = 1;
247 break;
248
249 case 'm':
250 mflag = 1;
251 break;
252
253 default:
254 usage();
255 /* NOTREACHED */
256 }
257 }
258 argc -= optind;
259 argv += optind;
260
261 /* -a means print all interfaces */
262 if (aflag) {
263 if (argc > 1)
264 usage();
265 else if (argc == 1) {
266 afp = lookup_af(argv[0]);
267 if (afp == NULL)
268 usage();
269 } else
270 afp = afs;
271 af = ifr.ifr_addr.sa_family = afp->af_af;
272
273 printall();
274 exit(0);
275 }
276
277 /* Make sure there's an interface name. */
278 if (argc < 1)
279 usage();
280 strncpy(name, argv[0], sizeof(name));
281 argc--; argv++;
282
283 /* Check for address family. */
284 afp = NULL;
285 if (argc > 0) {
286 afp = lookup_af(argv[0]);
287 if (afp != NULL) {
288 argv++;
289 argc--;
290 }
291 }
292
293 if (afp == NULL)
294 afp = afs;
295 af = ifr.ifr_addr.sa_family = afp->af_af;
296
297 /* Get information about the interface. */
298 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
299 if (getinfo(&ifr) < 0)
300 exit(1);
301
302 /* No more arguments means interface status. */
303 if (argc == 0) {
304 status(NULL, 0);
305 exit(0);
306 }
307
308 /* Process commands. */
309 while (argc > 0) {
310 register struct cmd *p;
311
312 for (p = cmds; p->c_name; p++)
313 if (strcmp(argv[0], p->c_name) == 0)
314 break;
315 if (p->c_name == 0 && setaddr)
316 p++; /* got src, do dst */
317 if (p->c_func) {
318 if (p->c_parameter == NEXTARG) {
319 if (argc < 2)
320 errx(1, "'%s' requires argument",
321 p->c_name);
322 (*p->c_func)(argv[1]);
323 argc--, argv++;
324 } else
325 (*p->c_func)(argv[0], p->c_parameter);
326 }
327 argc--, argv++;
328 }
329
330 #ifndef INET_ONLY
331
332 if (af == AF_ISO)
333 adjust_nsellength();
334 if (setipdst && af==AF_NS) {
335 struct nsip_req rq;
336 int size = sizeof(rq);
337
338 rq.rq_ns = addreq.ifra_addr;
339 rq.rq_ip = addreq.ifra_dstaddr;
340
341 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
342 warn("encapsulation routing");
343 }
344
345 #endif /* INET_ONLY */
346
347 if (clearaddr) {
348 int ret;
349 strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
350 if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
351 if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
352 /* means no previous address for interface */
353 } else
354 warn("SIOCDIFADDR");
355 }
356 }
357 if (newaddr) {
358 strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
359 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
360 warn("SIOCAIFADDR");
361 }
362 exit(0);
363 }
364
365 struct afswtch *
366 lookup_af(cp)
367 const char *cp;
368 {
369 struct afswtch *a;
370
371 for (a = afs; a->af_name != NULL; a++)
372 if (strcmp(a->af_name, cp) == 0)
373 return (a);
374 return (NULL);
375 }
376
377 void
378 getsock(naf)
379 int naf;
380 {
381 static int oaf = -1;
382
383 if (oaf == naf)
384 return;
385 if (oaf != -1)
386 close(s);
387 s = socket(naf, SOCK_DGRAM, 0);
388 if (s < 0)
389 oaf = -1;
390 else
391 oaf = naf;
392 }
393
394 int
395 getinfo(ifr)
396 struct ifreq *ifr;
397 {
398
399 getsock(af);
400 if (s < 0)
401 err(1, "socket");
402 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
403 warn("SIOCGIFFLAGS");
404 return (-1);
405 }
406 flags = ifr->ifr_flags;
407 if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
408 warn("SIOCGIFMETRIC");
409 metric = 0;
410 } else
411 metric = ifr->ifr_metric;
412 return (0);
413 }
414
415 void
416 printall()
417 {
418 char inbuf[8192];
419 const struct sockaddr_dl *sdl = NULL;
420 struct ifconf ifc;
421 struct ifreq ifreq, *ifr;
422 int i;
423
424 ifc.ifc_len = sizeof(inbuf);
425 ifc.ifc_buf = inbuf;
426 getsock(af);
427 if (s < 0)
428 err(1, "socket");
429 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
430 err(1, "SIOCGIFCONF");
431 ifr = ifc.ifc_req;
432 ifreq.ifr_name[0] = '\0';
433 for (i = 0; i < ifc.ifc_len; ) {
434 ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
435 i += sizeof(ifr->ifr_name) +
436 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
437 ? ifr->ifr_addr.sa_len
438 : sizeof(struct sockaddr));
439 if (ifr->ifr_addr.sa_family == AF_LINK)
440 sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
441 if (!strncmp(ifreq.ifr_name, ifr->ifr_name,
442 sizeof(ifr->ifr_name)))
443 continue;
444 strncpy(name, ifr->ifr_name, sizeof(ifr->ifr_name));
445 ifreq = *ifr;
446 if (getinfo(&ifreq) < 0)
447 continue;
448 if (sdl == NULL) {
449 status(NULL, 0);
450 } else {
451 status(LLADDR(sdl), sdl->sdl_alen);
452 sdl = NULL;
453 }
454 }
455 }
456
457 #define RIDADDR 0
458 #define ADDR 1
459 #define MASK 2
460 #define DSTADDR 3
461
462 /*ARGSUSED*/
463 void
464 setifaddr(addr, param)
465 char *addr;
466 int param;
467 {
468 /*
469 * Delay the ioctl to set the interface addr until flags are all set.
470 * The address interpretation may depend on the flags,
471 * and the flags may change when the address is set.
472 */
473 setaddr++;
474 if (doalias == 0)
475 clearaddr = 1;
476 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
477 }
478
479 void
480 setifnetmask(addr)
481 char *addr;
482 {
483 (*afp->af_getaddr)(addr, MASK);
484 }
485
486 void
487 setifbroadaddr(addr)
488 char *addr;
489 {
490 (*afp->af_getaddr)(addr, DSTADDR);
491 }
492
493 void
494 setifipdst(addr)
495 char *addr;
496 {
497 in_getaddr(addr, DSTADDR);
498 setipdst++;
499 clearaddr = 0;
500 newaddr = 0;
501 }
502
503 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
504 /*ARGSUSED*/
505 void
506 notealias(addr, param)
507 char *addr;
508 int param;
509 {
510 if (setaddr && doalias == 0 && param < 0)
511 memcpy(rqtosa(af_ridreq),
512 rqtosa(af_addreq),
513 rqtosa(af_addreq)->sa_len);
514 doalias = param;
515 if (param < 0) {
516 clearaddr = 1;
517 newaddr = 0;
518 } else
519 clearaddr = 0;
520 }
521
522 /*ARGSUSED*/
523 void
524 notrailers(vname, value)
525 char *vname;
526 int value;
527 {
528 printf("Note: trailers are no longer sent, but always received\n");
529 }
530
531 /*ARGSUSED*/
532 void
533 setifdstaddr(addr, param)
534 char *addr;
535 int param;
536 {
537 (*afp->af_getaddr)(addr, DSTADDR);
538 }
539
540 void
541 setifflags(vname, value)
542 char *vname;
543 int value;
544 {
545 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
546 err(1, "SIOCGIFFLAGS");
547 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
548 flags = ifr.ifr_flags;
549
550 if (value < 0) {
551 value = -value;
552 flags &= ~value;
553 } else
554 flags |= value;
555 ifr.ifr_flags = flags;
556 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
557 err(1, "SIOCSIFFLAGS");
558 }
559
560 void
561 setifmetric(val)
562 char *val;
563 {
564 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
565 ifr.ifr_metric = atoi(val);
566 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
567 warn("SIOCSIFMETRIC");
568 }
569
570 void
571 setmedia(val)
572 char *val;
573 {
574 struct ifmediareq ifmr;
575 int first_type, subtype;
576
577 memset(&ifmr, 0, sizeof(ifmr));
578 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
579
580 ifmr.ifm_count = 1;
581 ifmr.ifm_ulist = &first_type;
582 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
583 /*
584 * If we get E2BIG, the kernel is telling us
585 * that there are more, so we can ignore it.
586 */
587 if (errno != E2BIG)
588 err(1, "SIOCGIFMEDIA");
589 }
590
591 if (ifmr.ifm_count == 0)
592 errx(1, "%s: no media types?", name);
593
594 /*
595 * We are primarily concerned with the top-level type.
596 * However, "current" may be only IFM_NONE, so we just look
597 * for the top-level type in the first "supported type"
598 * entry.
599 *
600 * (I'm assuming that all supported media types for a given
601 * interface will be the same top-level type..)
602 */
603 subtype = get_media_subtype(IFM_TYPE(first_type), val);
604
605 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
606 ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
607 IFM_TYPE(first_type) | subtype;
608
609 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
610 err(1, "SIOCSIFMEDIA");
611 }
612
613 void
614 setmediaopt(val)
615 char *val;
616 {
617
618 domediaopt(val, 0);
619 }
620
621 void
622 unsetmediaopt(val)
623 char *val;
624 {
625
626 domediaopt(val, 1);
627 }
628
629 void
630 domediaopt(val, clear)
631 char *val;
632 int clear;
633 {
634 struct ifmediareq ifmr;
635 int *mwords, options;
636
637 memset(&ifmr, 0, sizeof(ifmr));
638 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
639
640 /*
641 * We must go through the motions of reading all
642 * supported media because we need to know both
643 * the current media type and the top-level type.
644 */
645
646 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
647 err(1, "SIOCGIFMEDIA");
648
649 if (ifmr.ifm_count == 0)
650 errx(1, "%s: no media types?", name);
651
652 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
653 if (mwords == NULL)
654 err(1, "malloc");
655
656 ifmr.ifm_ulist = mwords;
657 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
658 err(1, "SIOCGIFMEDIA");
659
660 options = get_media_options(IFM_TYPE(mwords[0]), val);
661
662 free(mwords);
663
664 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
665 ifr.ifr_media = ifmr.ifm_current;
666 if (clear)
667 ifr.ifr_media &= ~options;
668 else
669 ifr.ifr_media |= options;
670
671 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
672 err(1, "SIOCSIFMEDIA");
673 }
674
675 /**********************************************************************
676 * A good chunk of this is duplicated from sys/net/ifmedia.c
677 **********************************************************************/
678
679 struct ifmedia_description ifm_type_descriptions[] =
680 IFM_TYPE_DESCRIPTIONS;
681
682 struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
683 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
684
685 struct ifmedia_description ifm_subtype_ethernet_aliases[] =
686 IFM_SUBTYPE_ETHERNET_ALIASES;
687
688 struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
689 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
690
691 struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
692 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
693
694 struct ifmedia_description ifm_subtype_tokenring_aliases[] =
695 IFM_SUBTYPE_TOKENRING_ALIASES;
696
697 struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
698 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
699
700 struct ifmedia_description ifm_subtype_fddi_descriptions[] =
701 IFM_SUBTYPE_FDDI_DESCRIPTIONS;
702
703 struct ifmedia_description ifm_subtype_fddi_aliases[] =
704 IFM_SUBTYPE_FDDI_ALIASES;
705
706 struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
707 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
708
709 struct ifmedia_description ifm_subtype_shared_descriptions[] =
710 IFM_SUBTYPE_SHARED_DESCRIPTIONS;
711
712 struct ifmedia_description ifm_subtype_shared_aliases[] =
713 IFM_SUBTYPE_SHARED_ALIASES;
714
715 struct ifmedia_description ifm_shared_option_descriptions[] =
716 IFM_SHARED_OPTION_DESCRIPTIONS;
717
718 struct ifmedia_type_to_subtype {
719 struct {
720 struct ifmedia_description *desc;
721 int alias;
722 } subtypes[5];
723 struct {
724 struct ifmedia_description *desc;
725 int alias;
726 } options[3];
727 };
728
729 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
730 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
731 {
732 {
733 { &ifm_subtype_shared_descriptions[0], 0 },
734 { &ifm_subtype_shared_aliases[0], 1 },
735 { &ifm_subtype_ethernet_descriptions[0], 0 },
736 { &ifm_subtype_ethernet_aliases[0], 1 },
737 { NULL, 0 },
738 },
739 {
740 { &ifm_shared_option_descriptions[0], 0 },
741 { &ifm_subtype_ethernet_option_descriptions[0], 1 },
742 { NULL, 0 },
743 },
744 },
745 {
746 {
747 { &ifm_subtype_shared_descriptions[0], 0 },
748 { &ifm_subtype_shared_aliases[0], 1 },
749 { &ifm_subtype_tokenring_descriptions[0], 0 },
750 { &ifm_subtype_tokenring_aliases[0], 1 },
751 { NULL, 0 },
752 },
753 {
754 { &ifm_shared_option_descriptions[0], 0 },
755 { &ifm_subtype_tokenring_option_descriptions[0], 1 },
756 { NULL, 0 },
757 },
758 },
759 {
760 {
761 { &ifm_subtype_shared_descriptions[0], 0 },
762 { &ifm_subtype_shared_aliases[0], 1 },
763 { &ifm_subtype_fddi_descriptions[0], 0 },
764 { &ifm_subtype_fddi_aliases[0], 1 },
765 { NULL, 0 },
766 },
767 {
768 { &ifm_shared_option_descriptions[0], 0 },
769 { &ifm_subtype_fddi_option_descriptions[0], 1 },
770 { NULL, 0 },
771 },
772 },
773 };
774
775 int
776 get_media_subtype(type, val)
777 int type;
778 char *val;
779 {
780 struct ifmedia_description *desc;
781 struct ifmedia_type_to_subtype *ttos;
782 int rval, i;
783
784 /* Find the top-level interface type. */
785 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
786 desc->ifmt_string != NULL; desc++, ttos++)
787 if (type == desc->ifmt_word)
788 break;
789 if (desc->ifmt_string == NULL)
790 errx(1, "unknown media type 0x%x", type);
791
792 for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
793 rval = lookup_media_word(ttos->subtypes[i].desc, val);
794 if (rval != -1)
795 return (rval);
796 }
797 errx(1, "unknown media subtype: %s", val);
798 /* NOTREACHED */
799 }
800
801 int
802 get_media_options(type, val)
803 int type;
804 char *val;
805 {
806 struct ifmedia_description *desc;
807 struct ifmedia_type_to_subtype *ttos;
808 char *optlist;
809 int option, i, rval = 0;
810
811 /* We muck with the string, so copy it. */
812 optlist = strdup(val);
813 if (optlist == NULL)
814 err(1, "strdup");
815 val = optlist;
816
817 /* Find the top-level interface type. */
818 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
819 desc->ifmt_string != NULL; desc++, ttos++)
820 if (type == desc->ifmt_word)
821 break;
822 if (desc->ifmt_string == NULL)
823 errx(1, "unknown media type 0x%x", type);
824
825 /*
826 * Look up the options in the user-provided comma-separated
827 * list.
828 */
829 for (; (val = strtok(val, ",")) != NULL; val = NULL) {
830 for (i = 0; ttos->options[i].desc != NULL; i++) {
831 option = lookup_media_word(ttos->options[i].desc, val);
832 if (option != -1)
833 break;
834 }
835 if (option == 0)
836 errx(1, "unknown option: %s", val);
837 rval |= option;
838 }
839
840 free(optlist);
841 return (rval);
842 }
843
844 int
845 lookup_media_word(desc, val)
846 struct ifmedia_description *desc;
847 char *val;
848 {
849
850 for (; desc->ifmt_string != NULL; desc++)
851 if (strcasecmp(desc->ifmt_string, val) == 0)
852 return (desc->ifmt_word);
853
854 return (-1);
855 }
856
857 void
858 print_media_word(ifmw)
859 int ifmw;
860 {
861 struct ifmedia_description *desc;
862 struct ifmedia_type_to_subtype *ttos;
863 int seen_option = 0, i;
864
865 /* Find the top-level interface type. */
866 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
867 desc->ifmt_string != NULL; desc++, ttos++)
868 if (IFM_TYPE(ifmw) == desc->ifmt_word)
869 break;
870 if (desc->ifmt_string == NULL) {
871 printf("<unknown type>");
872 return;
873 }
874
875 /*
876 * Don't print the top-level type; it's not like we can
877 * change it, or anything.
878 */
879
880 /* Find subtype. */
881 for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
882 if (ttos->subtypes[i].alias)
883 continue;
884 for (desc = ttos->subtypes[i].desc;
885 desc->ifmt_string != NULL; desc++) {
886 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
887 goto got_subtype;
888 }
889 }
890
891 /* Falling to here means unknown subtype. */
892 printf("<unknown subtype>");
893 return;
894
895 got_subtype:
896 printf("%s", desc->ifmt_string);
897
898 /* Find options. */
899 for (i = 0; ttos->options[i].desc != NULL; i++) {
900 if (ttos->options[i].alias)
901 continue;
902 for (desc = ttos->options[i].desc;
903 desc->ifmt_string != NULL; desc++) {
904 if (ifmw & desc->ifmt_word) {
905 if (seen_option == 0)
906 printf(" <");
907 printf("%s%s", seen_option++ ? "," : "",
908 desc->ifmt_string);
909 }
910 }
911 }
912 printf("%s", seen_option ? ">" : "");
913 }
914
915 /**********************************************************************
916 * ...until here.
917 **********************************************************************/
918
919 #define IFFBITS \
920 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
921 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
922
923 /*
924 * Print the status of the interface. If an address family was
925 * specified, show it and it only; otherwise, show them all.
926 */
927 void
928 status(ap, alen)
929 const u_int8_t *ap;
930 int alen;
931 {
932 register struct afswtch *p = afp;
933 struct ifmediareq ifmr;
934 int *media_list, i;
935
936 printf("%s: ", name);
937 printb("flags", flags, IFFBITS);
938 if (metric)
939 printf(" metric %d", metric);
940 putchar('\n');
941 if (ap && alen > 0) {
942 printf("\taddress:");
943 for (i = 0; i < alen; i++, ap++)
944 printf("%c%02x", i > 0 ? ':' : ' ', *ap);
945 putchar('\n');
946 }
947
948 memset(&ifmr, 0, sizeof(ifmr));
949 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
950
951 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
952 /*
953 * Interface doesn't support SIOC{G,S}IFMEDIA.
954 */
955 goto proto_status;
956 }
957
958 if (ifmr.ifm_count == 0) {
959 warnx("%s: no media types?", name);
960 goto proto_status;
961 }
962
963 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
964 if (media_list == NULL)
965 err(1, "malloc");
966 ifmr.ifm_ulist = media_list;
967
968 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
969 err(1, "SIOCGIFMEDIA");
970
971 printf("\tmedia: ");
972 print_media_word(ifmr.ifm_current);
973 if (ifmr.ifm_active != ifmr.ifm_current) {
974 putchar(' ');
975 putchar('(');
976 print_media_word(ifmr.ifm_active);
977 putchar(')');
978 }
979
980 if (ifmr.ifm_status & IFM_AVALID) {
981 printf(" status: ");
982 switch (IFM_TYPE(ifmr.ifm_active)) {
983 case IFM_ETHER:
984 if (ifmr.ifm_status & IFM_ACTIVE)
985 printf("active");
986 else
987 printf("no carrier");
988 break;
989
990 case IFM_FDDI:
991 case IFM_TOKEN:
992 if (ifmr.ifm_status & IFM_ACTIVE)
993 printf("inserted");
994 else
995 printf("no ring");
996 break;
997 }
998 }
999
1000 putchar('\n');
1001
1002 if (mflag) {
1003 printf("\tsupported media:");
1004 for (i = 0; i < ifmr.ifm_count; i++) {
1005 putchar(' ');
1006 print_media_word(media_list[i]);
1007 }
1008 putchar('\n');
1009 }
1010
1011 free(media_list);
1012
1013 proto_status:
1014 if ((p = afp) != NULL) {
1015 (*p->af_status)(1);
1016 } else for (p = afs; p->af_name; p++) {
1017 ifr.ifr_addr.sa_family = p->af_af;
1018 (*p->af_status)(0);
1019 }
1020 }
1021
1022 void
1023 in_status(force)
1024 int force;
1025 {
1026 struct sockaddr_in *sin;
1027 char *inet_ntoa();
1028
1029 getsock(AF_INET);
1030 if (s < 0) {
1031 if (errno == EPROTONOSUPPORT)
1032 return;
1033 err(1, "socket");
1034 }
1035 memset(&ifr, 0, sizeof(ifr));
1036 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1037 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1038 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1039 if (!force)
1040 return;
1041 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1042 } else
1043 warn("SIOCGIFADDR");
1044 }
1045 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1046 sin = (struct sockaddr_in *)&ifr.ifr_addr;
1047 printf("\tinet %s ", inet_ntoa(sin->sin_addr));
1048 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1049 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1050 if (errno != EADDRNOTAVAIL)
1051 warn("SIOCGIFNETMASK");
1052 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1053 } else
1054 netmask.sin_addr =
1055 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1056 if (flags & IFF_POINTOPOINT) {
1057 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1058 if (errno == EADDRNOTAVAIL)
1059 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1060 else
1061 warn("SIOCGIFDSTADDR");
1062 }
1063 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1064 sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1065 printf("--> %s ", inet_ntoa(sin->sin_addr));
1066 }
1067 printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
1068 if (flags & IFF_BROADCAST) {
1069 if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
1070 if (errno == EADDRNOTAVAIL)
1071 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1072 else
1073 warn("SIOCGIFBRDADDR");
1074 }
1075 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1076 sin = (struct sockaddr_in *)&ifr.ifr_addr;
1077 if (sin->sin_addr.s_addr != 0)
1078 printf("broadcast %s", inet_ntoa(sin->sin_addr));
1079 }
1080 putchar('\n');
1081 }
1082
1083 #ifndef INET_ONLY
1084
1085 void
1086 xns_status(force)
1087 int force;
1088 {
1089 struct sockaddr_ns *sns;
1090
1091 getsock(AF_NS);
1092 if (s < 0) {
1093 if (errno == EPROTONOSUPPORT)
1094 return;
1095 err(1, "socket");
1096 }
1097 memset(&ifr, 0, sizeof(ifr));
1098 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1099 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1100 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1101 if (!force)
1102 return;
1103 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1104 } else
1105 warn("SIOCGIFADDR");
1106 }
1107 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1108 sns = (struct sockaddr_ns *)&ifr.ifr_addr;
1109 printf("\tns %s ", ns_ntoa(sns->sns_addr));
1110 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1111 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1112 if (errno == EADDRNOTAVAIL)
1113 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1114 else
1115 warn("SIOCGIFDSTADDR");
1116 }
1117 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1118 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
1119 printf("--> %s ", ns_ntoa(sns->sns_addr));
1120 }
1121 putchar('\n');
1122 }
1123
1124 void
1125 iso_status(force)
1126 int force;
1127 {
1128 struct sockaddr_iso *siso;
1129
1130 getsock(AF_ISO);
1131 if (s < 0) {
1132 if (errno == EPROTONOSUPPORT)
1133 return;
1134 err(1, "socket");
1135 }
1136 memset(&ifr, 0, sizeof(ifr));
1137 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1138 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1139 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1140 if (!force)
1141 return;
1142 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1143 } else
1144 warn("SIOCGIFADDR");
1145 }
1146 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1147 siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1148 printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
1149 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1150 if (errno == EADDRNOTAVAIL)
1151 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1152 else
1153 warn("SIOCGIFNETMASK");
1154 } else {
1155 printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
1156 }
1157 if (flags & IFF_POINTOPOINT) {
1158 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1159 if (errno == EADDRNOTAVAIL)
1160 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1161 else
1162 warn("SIOCGIFDSTADDR");
1163 }
1164 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1165 siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1166 printf("--> %s ", iso_ntoa(&siso->siso_addr));
1167 }
1168 putchar('\n');
1169 }
1170
1171 #endif /* INET_ONLY */
1172
1173 struct in_addr inet_makeaddr();
1174
1175 #define SIN(x) ((struct sockaddr_in *) &(x))
1176 struct sockaddr_in *sintab[] = {
1177 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1178 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1179
1180 void
1181 in_getaddr(s, which)
1182 char *s;
1183 int which;
1184 {
1185 register struct sockaddr_in *sin = sintab[which];
1186 struct hostent *hp;
1187 struct netent *np;
1188
1189 sin->sin_len = sizeof(*sin);
1190 if (which != MASK)
1191 sin->sin_family = AF_INET;
1192
1193 if (inet_aton(s, &sin->sin_addr) == 0) {
1194 if (hp = gethostbyname(s))
1195 memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1196 else if (np = getnetbyname(s))
1197 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1198 else
1199 errx(1, "%s: bad value", s);
1200 }
1201 }
1202
1203 /*
1204 * Print a value a la the %b format of the kernel's printf
1205 */
1206 void
1207 printb(s, v, bits)
1208 char *s;
1209 register char *bits;
1210 register unsigned short v;
1211 {
1212 register int i, any = 0;
1213 register char c;
1214
1215 if (bits && *bits == 8)
1216 printf("%s=%o", s, v);
1217 else
1218 printf("%s=%x", s, v);
1219 bits++;
1220 if (bits) {
1221 putchar('<');
1222 while (i = *bits++) {
1223 if (v & (1 << (i-1))) {
1224 if (any)
1225 putchar(',');
1226 any = 1;
1227 for (; (c = *bits) > 32; bits++)
1228 putchar(c);
1229 } else
1230 for (; *bits > 32; bits++)
1231 ;
1232 }
1233 putchar('>');
1234 }
1235 }
1236
1237 #ifndef INET_ONLY
1238
1239 #define SNS(x) ((struct sockaddr_ns *) &(x))
1240 struct sockaddr_ns *snstab[] = {
1241 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1242 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1243
1244 void
1245 xns_getaddr(addr, which)
1246 char *addr;
1247 int which;
1248 {
1249 struct sockaddr_ns *sns = snstab[which];
1250 struct ns_addr ns_addr();
1251
1252 sns->sns_family = AF_NS;
1253 sns->sns_len = sizeof(*sns);
1254 sns->sns_addr = ns_addr(addr);
1255 if (which == MASK)
1256 printf("Attempt to set XNS netmask will be ineffectual\n");
1257 }
1258
1259 #define SISO(x) ((struct sockaddr_iso *) &(x))
1260 struct sockaddr_iso *sisotab[] = {
1261 SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1262 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1263
1264 void
1265 iso_getaddr(addr, which)
1266 char *addr;
1267 int which;
1268 {
1269 register struct sockaddr_iso *siso = sisotab[which];
1270 struct iso_addr *iso_addr();
1271 siso->siso_addr = *iso_addr(addr);
1272
1273 if (which == MASK) {
1274 siso->siso_len = TSEL(siso) - (caddr_t)(siso);
1275 siso->siso_nlen = 0;
1276 } else {
1277 siso->siso_len = sizeof(*siso);
1278 siso->siso_family = AF_ISO;
1279 }
1280 }
1281
1282 void
1283 setsnpaoffset(val)
1284 char *val;
1285 {
1286 iso_addreq.ifra_snpaoffset = atoi(val);
1287 }
1288
1289 void
1290 setnsellength(val)
1291 char *val;
1292 {
1293 nsellength = atoi(val);
1294 if (nsellength < 0)
1295 errx(1, "Negative NSEL length is absurd");
1296 if (afp == 0 || afp->af_af != AF_ISO)
1297 errx(1, "Setting NSEL length valid only for iso");
1298 }
1299
1300 void
1301 fixnsel(s)
1302 register struct sockaddr_iso *s;
1303 {
1304 if (s->siso_family == 0)
1305 return;
1306 s->siso_tlen = nsellength;
1307 }
1308
1309 void
1310 adjust_nsellength()
1311 {
1312 fixnsel(sisotab[RIDADDR]);
1313 fixnsel(sisotab[ADDR]);
1314 fixnsel(sisotab[DSTADDR]);
1315 }
1316
1317 #endif /* INET_ONLY */
1318
1319 void
1320 usage()
1321 {
1322 fprintf(stderr, "usage: ifconfig [ -m ] interface\n%s%s%s%s%s%s%s%s%s",
1323 "\t[ af [ address [ dest_addr ] ] [ up ] [ down ] ",
1324 "[ netmask mask ] ]\n",
1325 "\t[ metric n ]\n",
1326 "\t[ arp | -arp ]\n",
1327 "\t[ media mtype ]\n",
1328 "\t[ mediaopt mopts ]\n",
1329 "\t[ -mediaopt mopts ]\n",
1330 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n",
1331 " ifconfig -a [ -m ] [ af ]\n");
1332 exit(1);
1333 }
1334