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