ifconfig.c revision 1.29 1 /* $NetBSD: ifconfig.c,v 1.29 1997/03/25 01:37:11 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.29 1997/03/25 01:37:11 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 *mwords, options;
627
628 memset(&ifmr, 0, sizeof(ifmr));
629 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
630
631 /*
632 * We must go through the motions of reading all
633 * supported media because we need to know both
634 * the current media type and the top-level type.
635 */
636
637 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
638 err(1, "SIOCGIFMEDIA");
639
640 if (ifmr.ifm_count == 0)
641 errx(1, "%s: no media types?", name);
642
643 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
644 if (mwords == NULL)
645 err(1, "malloc");
646
647 ifmr.ifm_ulist = mwords;
648 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
649 err(1, "SIOCGIFMEDIA");
650
651 options = get_media_options(IFM_TYPE(mwords[0]), val);
652
653 free(mwords);
654
655 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
656 ifr.ifr_media = ifmr.ifm_current;
657 if (clear)
658 ifr.ifr_media &= ~options;
659 else
660 ifr.ifr_media |= options;
661
662 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
663 err(1, "SIOCSIFMEDIA");
664 }
665
666 /**********************************************************************
667 * A good chunk of this is duplicated from sys/net/ifmedia.c
668 **********************************************************************/
669
670 struct ifmedia_description ifm_type_descriptions[] =
671 IFM_TYPE_DESCRIPTIONS;
672
673 struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
674 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
675
676 struct ifmedia_description ifm_subtype_ethernet_aliases[] =
677 IFM_SUBTYPE_ETHERNET_ALIASES;
678
679 struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
680 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
681
682 struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
683 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
684
685 struct ifmedia_description ifm_subtype_tokenring_aliases[] =
686 IFM_SUBTYPE_TOKENRING_ALIASES;
687
688 struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
689 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
690
691 struct ifmedia_description ifm_subtype_fddi_descriptions[] =
692 IFM_SUBTYPE_FDDI_DESCRIPTIONS;
693
694 struct ifmedia_description ifm_subtype_fddi_aliases[] =
695 IFM_SUBTYPE_FDDI_ALIASES;
696
697 struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
698 IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
699
700 struct ifmedia_description ifm_subtype_shared_descriptions[] =
701 IFM_SUBTYPE_SHARED_DESCRIPTIONS;
702
703 struct ifmedia_description ifm_subtype_shared_aliases[] =
704 IFM_SUBTYPE_SHARED_ALIASES;
705
706 struct ifmedia_description ifm_shared_option_descriptions[] =
707 IFM_SHARED_OPTION_DESCRIPTIONS;
708
709 struct ifmedia_type_to_subtype {
710 struct {
711 struct ifmedia_description *desc;
712 int alias;
713 } subtypes[5];
714 struct {
715 struct ifmedia_description *desc;
716 int alias;
717 } options[3];
718 };
719
720 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
721 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
722 {
723 {
724 { &ifm_subtype_shared_descriptions[0], 0 },
725 { &ifm_subtype_shared_aliases[0], 1 },
726 { &ifm_subtype_ethernet_descriptions[0], 0 },
727 { &ifm_subtype_ethernet_aliases[0], 1 },
728 { NULL, 0 },
729 },
730 {
731 { &ifm_shared_option_descriptions[0], 0 },
732 { &ifm_subtype_ethernet_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_tokenring_descriptions[0], 0 },
741 { &ifm_subtype_tokenring_aliases[0], 1 },
742 { NULL, 0 },
743 },
744 {
745 { &ifm_shared_option_descriptions[0], 0 },
746 { &ifm_subtype_tokenring_option_descriptions[0], 1 },
747 { NULL, 0 },
748 },
749 },
750 {
751 {
752 { &ifm_subtype_shared_descriptions[0], 0 },
753 { &ifm_subtype_shared_aliases[0], 1 },
754 { &ifm_subtype_fddi_descriptions[0], 0 },
755 { &ifm_subtype_fddi_aliases[0], 1 },
756 { NULL, 0 },
757 },
758 {
759 { &ifm_shared_option_descriptions[0], 0 },
760 { &ifm_subtype_fddi_option_descriptions[0], 1 },
761 { NULL, 0 },
762 },
763 },
764 };
765
766 int
767 get_media_subtype(type, val)
768 int type;
769 char *val;
770 {
771 struct ifmedia_description *desc;
772 struct ifmedia_type_to_subtype *ttos;
773 int rval, i;
774
775 /* Find the top-level interface type. */
776 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
777 desc->ifmt_string != NULL; desc++, ttos++)
778 if (type == desc->ifmt_word)
779 break;
780 if (desc->ifmt_string == NULL)
781 errx(1, "unknown media type 0x%x", type);
782
783 for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
784 rval = lookup_media_word(ttos->subtypes[i].desc, val);
785 if (rval != -1)
786 return (rval);
787 }
788 errx(1, "unknown media subtype: %s", val);
789 /* NOTREACHED */
790 }
791
792 int
793 get_media_options(type, val)
794 int type;
795 char *val;
796 {
797 struct ifmedia_description *desc;
798 struct ifmedia_type_to_subtype *ttos;
799 char *optlist;
800 int option, i, rval = 0;
801
802 /* We muck with the string, so copy it. */
803 optlist = strdup(val);
804 if (optlist == NULL)
805 err(1, "strdup");
806 val = optlist;
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 /*
817 * Look up the options in the user-provided comma-separated
818 * list.
819 */
820 for (; (val = strtok(val, ",")) != NULL; val = NULL) {
821 for (i = 0; ttos->options[i].desc != NULL; i++) {
822 option = lookup_media_word(ttos->options[i].desc, val);
823 if (option != -1)
824 break;
825 }
826 if (option == 0)
827 errx(1, "unknown option: %s", val);
828 rval |= option;
829 }
830
831 free(optlist);
832 return (rval);
833 }
834
835 int
836 lookup_media_word(desc, val)
837 struct ifmedia_description *desc;
838 char *val;
839 {
840
841 for (; desc->ifmt_string != NULL; desc++)
842 if (strcasecmp(desc->ifmt_string, val) == 0)
843 return (desc->ifmt_word);
844
845 return (-1);
846 }
847
848 void
849 print_media_word(ifmw)
850 int ifmw;
851 {
852 struct ifmedia_description *desc;
853 struct ifmedia_type_to_subtype *ttos;
854 int seen_option = 0, i;
855
856 /* Find the top-level interface type. */
857 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
858 desc->ifmt_string != NULL; desc++, ttos++)
859 if (IFM_TYPE(ifmw) == desc->ifmt_word)
860 break;
861 if (desc->ifmt_string == NULL) {
862 printf("<unknown type>");
863 return;
864 }
865
866 /*
867 * Don't print the top-level type; it's not like we can
868 * change it, or anything.
869 */
870
871 /* Find subtype. */
872 for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
873 if (ttos->subtypes[i].alias)
874 continue;
875 for (desc = ttos->subtypes[i].desc;
876 desc->ifmt_string != NULL; desc++) {
877 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
878 goto got_subtype;
879 }
880 }
881
882 /* Falling to here means unknown subtype. */
883 printf("<unknown subtype>");
884 return;
885
886 got_subtype:
887 printf("%s", desc->ifmt_string);
888
889 /* Find options. */
890 for (i = 0; ttos->options[i].desc != NULL; i++) {
891 if (ttos->options[i].alias)
892 continue;
893 for (desc = ttos->options[i].desc;
894 desc->ifmt_string != NULL; desc++) {
895 if (ifmw & desc->ifmt_word) {
896 if (seen_option == 0)
897 printf(" <");
898 printf("%s%s", seen_option++ ? "," : "",
899 desc->ifmt_string);
900 }
901 }
902 }
903 printf("%s", seen_option ? ">" : "");
904 }
905
906 /**********************************************************************
907 * ...until here.
908 **********************************************************************/
909
910 #define IFFBITS \
911 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
912 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
913
914 /*
915 * Print the status of the interface. If an address family was
916 * specified, show it and it only; otherwise, show them all.
917 */
918 void
919 status()
920 {
921 register struct afswtch *p = afp;
922 struct ifmediareq ifmr;
923 int *media_list, i;
924
925 printf("%s: ", name);
926 printb("flags", flags, IFFBITS);
927 if (metric)
928 printf(" metric %d", metric);
929 putchar('\n');
930
931 memset(&ifmr, 0, sizeof(ifmr));
932 strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
933
934 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
935 /*
936 * Interface doesn't support SIOC{G,S}IFMEDIA.
937 */
938 goto proto_status;
939 }
940
941 if (ifmr.ifm_count == 0) {
942 warnx("%s: no media types?", name);
943 goto proto_status;
944 }
945
946 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
947 if (media_list == NULL)
948 err(1, "malloc");
949 ifmr.ifm_ulist = media_list;
950
951 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
952 err(1, "SIOCGIFMEDIA");
953
954 printf("\tmedia: ");
955 print_media_word(ifmr.ifm_current);
956 if (ifmr.ifm_active != ifmr.ifm_current) {
957 putchar(' ');
958 putchar('(');
959 print_media_word(ifmr.ifm_active);
960 putchar(')');
961 }
962
963 if (ifmr.ifm_status & IFM_AVALID) {
964 printf(" status: ");
965 switch (IFM_TYPE(ifmr.ifm_active)) {
966 case IFM_ETHER:
967 if (ifmr.ifm_status & IFM_ACTIVE)
968 printf("active");
969 else
970 printf("no carrier");
971 break;
972
973 case IFM_FDDI:
974 case IFM_TOKEN:
975 if (ifmr.ifm_status & IFM_ACTIVE)
976 printf("inserted");
977 else
978 printf("no ring");
979 break;
980 }
981 }
982
983 putchar('\n');
984
985 if (mflag) {
986 printf("\tsupported media:");
987 for (i = 0; i < ifmr.ifm_count; i++) {
988 putchar(' ');
989 print_media_word(media_list[i]);
990 }
991 putchar('\n');
992 }
993
994 free(media_list);
995
996 proto_status:
997 if ((p = afp) != NULL) {
998 (*p->af_status)(1);
999 } else for (p = afs; p->af_name; p++) {
1000 ifr.ifr_addr.sa_family = p->af_af;
1001 (*p->af_status)(0);
1002 }
1003 }
1004
1005 void
1006 in_status(force)
1007 int force;
1008 {
1009 struct sockaddr_in *sin;
1010 char *inet_ntoa();
1011
1012 getsock(AF_INET);
1013 if (s < 0) {
1014 if (errno == EPROTONOSUPPORT)
1015 return;
1016 err(1, "socket");
1017 }
1018 memset(&ifr, 0, sizeof(ifr));
1019 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1020 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1021 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1022 if (!force)
1023 return;
1024 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1025 } else
1026 warn("SIOCGIFADDR");
1027 }
1028 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1029 sin = (struct sockaddr_in *)&ifr.ifr_addr;
1030 printf("\tinet %s ", inet_ntoa(sin->sin_addr));
1031 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1032 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1033 if (errno != EADDRNOTAVAIL)
1034 warn("SIOCGIFNETMASK");
1035 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1036 } else
1037 netmask.sin_addr =
1038 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1039 if (flags & IFF_POINTOPOINT) {
1040 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1041 if (errno == EADDRNOTAVAIL)
1042 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1043 else
1044 warn("SIOCGIFDSTADDR");
1045 }
1046 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1047 sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1048 printf("--> %s ", inet_ntoa(sin->sin_addr));
1049 }
1050 printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
1051 if (flags & IFF_BROADCAST) {
1052 if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
1053 if (errno == EADDRNOTAVAIL)
1054 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1055 else
1056 warn("SIOCGIFBRDADDR");
1057 }
1058 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1059 sin = (struct sockaddr_in *)&ifr.ifr_addr;
1060 if (sin->sin_addr.s_addr != 0)
1061 printf("broadcast %s", inet_ntoa(sin->sin_addr));
1062 }
1063 putchar('\n');
1064 }
1065
1066 #ifndef INET_ONLY
1067
1068 void
1069 xns_status(force)
1070 int force;
1071 {
1072 struct sockaddr_ns *sns;
1073
1074 getsock(AF_NS);
1075 if (s < 0) {
1076 if (errno == EPROTONOSUPPORT)
1077 return;
1078 err(1, "socket");
1079 }
1080 memset(&ifr, 0, sizeof(ifr));
1081 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1082 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1083 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1084 if (!force)
1085 return;
1086 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1087 } else
1088 warn("SIOCGIFADDR");
1089 }
1090 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1091 sns = (struct sockaddr_ns *)&ifr.ifr_addr;
1092 printf("\tns %s ", ns_ntoa(sns->sns_addr));
1093 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1094 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1095 if (errno == EADDRNOTAVAIL)
1096 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1097 else
1098 warn("SIOCGIFDSTADDR");
1099 }
1100 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1101 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
1102 printf("--> %s ", ns_ntoa(sns->sns_addr));
1103 }
1104 putchar('\n');
1105 }
1106
1107 void
1108 iso_status(force)
1109 int force;
1110 {
1111 struct sockaddr_iso *siso;
1112
1113 getsock(AF_ISO);
1114 if (s < 0) {
1115 if (errno == EPROTONOSUPPORT)
1116 return;
1117 err(1, "socket");
1118 }
1119 memset(&ifr, 0, sizeof(ifr));
1120 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1121 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1122 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1123 if (!force)
1124 return;
1125 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1126 } else
1127 warn("SIOCGIFADDR");
1128 }
1129 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1130 siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1131 printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
1132 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1133 if (errno == EADDRNOTAVAIL)
1134 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1135 else
1136 warn("SIOCGIFNETMASK");
1137 } else {
1138 printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
1139 }
1140 if (flags & IFF_POINTOPOINT) {
1141 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1142 if (errno == EADDRNOTAVAIL)
1143 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1144 else
1145 warn("SIOCGIFDSTADDR");
1146 }
1147 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1148 siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1149 printf("--> %s ", iso_ntoa(&siso->siso_addr));
1150 }
1151 putchar('\n');
1152 }
1153
1154 #endif /* INET_ONLY */
1155
1156 struct in_addr inet_makeaddr();
1157
1158 #define SIN(x) ((struct sockaddr_in *) &(x))
1159 struct sockaddr_in *sintab[] = {
1160 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1161 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1162
1163 void
1164 in_getaddr(s, which)
1165 char *s;
1166 int which;
1167 {
1168 register struct sockaddr_in *sin = sintab[which];
1169 struct hostent *hp;
1170 struct netent *np;
1171
1172 sin->sin_len = sizeof(*sin);
1173 if (which != MASK)
1174 sin->sin_family = AF_INET;
1175
1176 if (inet_aton(s, &sin->sin_addr) == 0) {
1177 if (hp = gethostbyname(s))
1178 memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1179 else if (np = getnetbyname(s))
1180 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1181 else
1182 errx(1, "%s: bad value", s);
1183 }
1184 }
1185
1186 /*
1187 * Print a value a la the %b format of the kernel's printf
1188 */
1189 void
1190 printb(s, v, bits)
1191 char *s;
1192 register char *bits;
1193 register unsigned short v;
1194 {
1195 register int i, any = 0;
1196 register char c;
1197
1198 if (bits && *bits == 8)
1199 printf("%s=%o", s, v);
1200 else
1201 printf("%s=%x", s, v);
1202 bits++;
1203 if (bits) {
1204 putchar('<');
1205 while (i = *bits++) {
1206 if (v & (1 << (i-1))) {
1207 if (any)
1208 putchar(',');
1209 any = 1;
1210 for (; (c = *bits) > 32; bits++)
1211 putchar(c);
1212 } else
1213 for (; *bits > 32; bits++)
1214 ;
1215 }
1216 putchar('>');
1217 }
1218 }
1219
1220 #ifndef INET_ONLY
1221
1222 #define SNS(x) ((struct sockaddr_ns *) &(x))
1223 struct sockaddr_ns *snstab[] = {
1224 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1225 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1226
1227 void
1228 xns_getaddr(addr, which)
1229 char *addr;
1230 int which;
1231 {
1232 struct sockaddr_ns *sns = snstab[which];
1233 struct ns_addr ns_addr();
1234
1235 sns->sns_family = AF_NS;
1236 sns->sns_len = sizeof(*sns);
1237 sns->sns_addr = ns_addr(addr);
1238 if (which == MASK)
1239 printf("Attempt to set XNS netmask will be ineffectual\n");
1240 }
1241
1242 #define SISO(x) ((struct sockaddr_iso *) &(x))
1243 struct sockaddr_iso *sisotab[] = {
1244 SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1245 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1246
1247 void
1248 iso_getaddr(addr, which)
1249 char *addr;
1250 int which;
1251 {
1252 register struct sockaddr_iso *siso = sisotab[which];
1253 struct iso_addr *iso_addr();
1254 siso->siso_addr = *iso_addr(addr);
1255
1256 if (which == MASK) {
1257 siso->siso_len = TSEL(siso) - (caddr_t)(siso);
1258 siso->siso_nlen = 0;
1259 } else {
1260 siso->siso_len = sizeof(*siso);
1261 siso->siso_family = AF_ISO;
1262 }
1263 }
1264
1265 void
1266 setsnpaoffset(val)
1267 char *val;
1268 {
1269 iso_addreq.ifra_snpaoffset = atoi(val);
1270 }
1271
1272 void
1273 setnsellength(val)
1274 char *val;
1275 {
1276 nsellength = atoi(val);
1277 if (nsellength < 0)
1278 errx(1, "Negative NSEL length is absurd");
1279 if (afp == 0 || afp->af_af != AF_ISO)
1280 errx(1, "Setting NSEL length valid only for iso");
1281 }
1282
1283 void
1284 fixnsel(s)
1285 register struct sockaddr_iso *s;
1286 {
1287 if (s->siso_family == 0)
1288 return;
1289 s->siso_tlen = nsellength;
1290 }
1291
1292 void
1293 adjust_nsellength()
1294 {
1295 fixnsel(sisotab[RIDADDR]);
1296 fixnsel(sisotab[ADDR]);
1297 fixnsel(sisotab[DSTADDR]);
1298 }
1299
1300 #endif /* INET_ONLY */
1301
1302 void
1303 usage()
1304 {
1305 fprintf(stderr, "usage: ifconfig [ -m ] interface\n%s%s%s%s%s%s%s%s%s",
1306 "\t[ af [ address [ dest_addr ] ] [ up ] [ down ] ",
1307 "[ netmask mask ] ]\n",
1308 "\t[ metric n ]\n",
1309 "\t[ arp | -arp ]\n",
1310 "\t[ media mtype ]\n",
1311 "\t[ mediaopt mopts ]\n",
1312 "\t[ -mediaopt mopts ]\n",
1313 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n",
1314 " ifconfig -a [ -m ] [ af ]\n");
1315 exit(1);
1316 }
1317