Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sbin / ifconfig / ifmedia.c
1 /*      $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $      */
2 /* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.6.2.3 2001/11/14 04:35:07 yar Exp $ */
3
4 /*
5  * Copyright (c) 1997 Jason R. Thorpe.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed for the NetBSD Project
19  *      by Jason R. Thorpe.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 /*
37  * Copyright (c) 1983, 1993
38  *      The Regents of the University of California.  All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. All advertising materials mentioning features or use of this software
49  *    must display the following acknowledgement:
50  *      This product includes software developed by the University of
51  *      California, Berkeley and its contributors.
52  * 4. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  */
68
69 #include <sys/param.h>
70 #include <sys/ioctl.h>
71 #include <sys/socket.h>
72 #include <sys/sysctl.h>
73 #include <sys/time.h>
74
75 #include <net/if.h>
76 #include <net/if_dl.h>
77 #include <net/if_types.h>
78 #include <net/if_media.h>
79 #include <net/route.h>
80
81 #include <ctype.h>
82 #include <err.h>
83 #include <errno.h>
84 #include <fcntl.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <unistd.h>
89
90 #include "ifconfig.h"
91
92 static void     domediaopt __P((const char *, int, int));
93 static int      get_media_subtype __P((int, const char *));
94 static int      get_media_options __P((int, const char *));
95 static int      lookup_media_word __P((struct ifmedia_description *, const char *));
96 static void     print_media_word __P((int, int));
97 static void     print_media_word_ifconfig __P((int));
98
99 static struct ifmedia_description *get_toptype_desc __P((int));
100 static struct ifmedia_type_to_subtype *get_toptype_ttos __P((int));
101 static struct ifmedia_description *get_subtype_desc __P((int,
102     struct ifmedia_type_to_subtype *ttos));
103
104 void
105 media_status(s, info)
106         int s;
107         struct rt_addrinfo *info __unused;
108 {
109         struct ifmediareq ifmr;
110         int *media_list, i;
111
112         (void) memset(&ifmr, 0, sizeof(ifmr));
113         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
114
115         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
116                 /*
117                  * Interface doesn't support SIOC{G,S}IFMEDIA.
118                  */
119                 return;
120         }
121
122         if (ifmr.ifm_count == 0) {
123                 warnx("%s: no media types?", name);
124                 return;
125         }
126
127         media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
128         if (media_list == NULL)
129                 err(1, "malloc");
130         ifmr.ifm_ulist = media_list;
131
132         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
133                 err(1, "SIOCGIFMEDIA");
134
135         printf("\tmedia: ");
136         print_media_word(ifmr.ifm_current, 1);
137         if (ifmr.ifm_active != ifmr.ifm_current) {
138                 putchar(' ');
139                 putchar('(');
140                 print_media_word(ifmr.ifm_active, 0);
141                 putchar(')');
142         }
143
144         putchar('\n');
145
146         if (ifmr.ifm_status & IFM_AVALID) {
147                 printf("\tstatus: ");
148                 switch (IFM_TYPE(ifmr.ifm_active)) {
149                 case IFM_ETHER:
150                         if (ifmr.ifm_status & IFM_ACTIVE)
151                                 printf("active");
152                         else
153                                 printf("no carrier");
154                         break;
155
156                 case IFM_FDDI:
157                 case IFM_TOKEN:
158                         if (ifmr.ifm_status & IFM_ACTIVE)
159                                 printf("inserted");
160                         else
161                                 printf("no ring");
162                         break;
163                 case IFM_IEEE80211:
164                         /* XXX: Different value for adhoc? */
165                         if (ifmr.ifm_status & IFM_ACTIVE)
166                                 printf("associated");
167                         else
168                                 printf("no carrier");
169                         break;
170                 }
171                 putchar('\n');
172         }
173
174         if (ifmr.ifm_count > 0 && supmedia) {
175                 printf("\tsupported media:\n");
176                 for (i = 0; i < ifmr.ifm_count; i++) {
177                         printf("\t\t");
178                         print_media_word_ifconfig(media_list[i]);
179                         putchar('\n');
180                 }
181         }
182
183         free(media_list);
184 }
185
186 void
187 setmedia(val, d, s, afp)
188         const char *val;
189         int d;
190         int s;
191         const struct afswtch *afp;
192 {
193         struct ifmediareq ifmr;
194         int first_type, subtype;
195
196         (void) memset(&ifmr, 0, sizeof(ifmr));
197         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
198
199         ifmr.ifm_count = 1;
200         ifmr.ifm_ulist = &first_type;
201         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
202                 /*
203                  * If we get E2BIG, the kernel is telling us
204                  * that there are more, so we can ignore it.
205                  */
206                 if (errno != E2BIG)
207                         err(1, "SIOCGIFMEDIA");
208         }
209
210         if (ifmr.ifm_count == 0)
211                 errx(1, "%s: no media types?", name);
212
213         /*
214          * We are primarily concerned with the top-level type.
215          * However, "current" may be only IFM_NONE, so we just look
216          * for the top-level type in the first "supported type"
217          * entry.
218          *
219          * (I'm assuming that all supported media types for a given
220          * interface will be the same top-level type..)
221          */
222         subtype = get_media_subtype(IFM_TYPE(first_type), val);
223
224         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
225         ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
226             IFM_TYPE(first_type) | subtype;
227
228         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
229                 err(1, "SIOCSIFMEDIA");
230 }
231
232 void
233 setmediaopt(val, d, s, afp)
234         const char *val;
235         int d;
236         int s;
237         const struct afswtch *afp;
238 {
239
240         domediaopt(val, 0, s);
241 }
242
243 void
244 unsetmediaopt(val, d, s, afp)
245         const char *val;
246         int d;
247         int s;
248         const struct afswtch *afp;
249 {
250
251         domediaopt(val, 1, s);
252 }
253
254 static void
255 domediaopt(val, clear, s)
256         const char *val;
257         int clear;
258         int s;
259 {
260         struct ifmediareq ifmr;
261         int *mwords, options;
262
263         (void) memset(&ifmr, 0, sizeof(ifmr));
264         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
265
266         /*
267          * We must go through the motions of reading all
268          * supported media because we need to know both
269          * the current media type and the top-level type.
270          */
271
272         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
273                 err(1, "SIOCGIFMEDIA");
274
275         if (ifmr.ifm_count == 0)
276                 errx(1, "%s: no media types?", name);
277
278         mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
279         if (mwords == NULL)
280                 err(1, "malloc");
281
282         ifmr.ifm_ulist = mwords;
283         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
284                 err(1, "SIOCGIFMEDIA");
285
286         options = get_media_options(IFM_TYPE(mwords[0]), val);
287
288         free(mwords);
289
290         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
291         ifr.ifr_media = ifmr.ifm_current;
292         if (clear)
293                 ifr.ifr_media &= ~options;
294         else
295                 ifr.ifr_media |= options;
296
297         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
298                 err(1, "SIOCSIFMEDIA");
299 }
300
301 /**********************************************************************
302  * A good chunk of this is duplicated from sys/net/ifmedia.c
303  **********************************************************************/
304
305 static struct ifmedia_description ifm_type_descriptions[] =
306     IFM_TYPE_DESCRIPTIONS;
307
308 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
309     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
310
311 static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
312     IFM_SUBTYPE_ETHERNET_ALIASES;
313
314 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
315     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
316
317 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
318     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
319
320 static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
321     IFM_SUBTYPE_TOKENRING_ALIASES;
322
323 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
324     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
325
326 static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
327     IFM_SUBTYPE_FDDI_DESCRIPTIONS;
328
329 static struct ifmedia_description ifm_subtype_fddi_aliases[] =
330     IFM_SUBTYPE_FDDI_ALIASES;
331
332 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
333     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
334
335 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
336     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
337
338 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
339     IFM_SUBTYPE_IEEE80211_ALIASES;
340
341 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
342     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
343
344 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
345     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
346
347 static struct ifmedia_description ifm_subtype_shared_aliases[] =
348     IFM_SUBTYPE_SHARED_ALIASES;
349
350 static struct ifmedia_description ifm_shared_option_descriptions[] =
351     IFM_SHARED_OPTION_DESCRIPTIONS;
352
353 struct ifmedia_type_to_subtype {
354         struct {
355                 struct ifmedia_description *desc;
356                 int alias;
357         } subtypes[5];
358         struct {
359                 struct ifmedia_description *desc;
360                 int alias;
361         } options[3];
362 };
363
364 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
365 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
366         {
367                 {
368                         { &ifm_subtype_shared_descriptions[0], 0 },
369                         { &ifm_subtype_shared_aliases[0], 1 },
370                         { &ifm_subtype_ethernet_descriptions[0], 0 },
371                         { &ifm_subtype_ethernet_aliases[0], 1 },
372                         { NULL, 0 },
373                 },
374                 {
375                         { &ifm_shared_option_descriptions[0], 0 },
376                         { &ifm_subtype_ethernet_option_descriptions[0], 0 },
377                         { NULL, 0 },
378                 },
379         },
380         {
381                 {
382                         { &ifm_subtype_shared_descriptions[0], 0 },
383                         { &ifm_subtype_shared_aliases[0], 1 },
384                         { &ifm_subtype_tokenring_descriptions[0], 0 },
385                         { &ifm_subtype_tokenring_aliases[0], 1 },
386                         { NULL, 0 },
387                 },
388                 {
389                         { &ifm_shared_option_descriptions[0], 0 },
390                         { &ifm_subtype_tokenring_option_descriptions[0], 0 },
391                         { NULL, 0 },
392                 },
393         },
394         {
395                 {
396                         { &ifm_subtype_shared_descriptions[0], 0 },
397                         { &ifm_subtype_shared_aliases[0], 1 },
398                         { &ifm_subtype_fddi_descriptions[0], 0 },
399                         { &ifm_subtype_fddi_aliases[0], 1 },
400                         { NULL, 0 },
401                 },
402                 {
403                         { &ifm_shared_option_descriptions[0], 0 },
404                         { &ifm_subtype_fddi_option_descriptions[0], 0 },
405                         { NULL, 0 },
406                 },
407         },
408         {
409                 {
410                         { &ifm_subtype_shared_descriptions[0], 0 },
411                         { &ifm_subtype_shared_aliases[0], 1 },
412                         { &ifm_subtype_ieee80211_descriptions[0], 0 },
413                         { &ifm_subtype_ieee80211_aliases[0], 1 },
414                         { NULL, 0 },
415                 },
416                 {
417                         { &ifm_shared_option_descriptions[0], 0 },
418                         { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
419                         { NULL, 0 },
420                 },
421         },
422 };
423
424 static int
425 get_media_subtype(type, val)
426         int type;
427         const char *val;
428 {
429         struct ifmedia_description *desc;
430         struct ifmedia_type_to_subtype *ttos;
431         int rval, i;
432
433         /* Find the top-level interface type. */
434         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
435             desc->ifmt_string != NULL; desc++, ttos++)
436                 if (type == desc->ifmt_word)
437                         break;
438         if (desc->ifmt_string == NULL)
439                 errx(1, "unknown media type 0x%x", type);
440
441         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
442                 rval = lookup_media_word(ttos->subtypes[i].desc, val);
443                 if (rval != -1)
444                         return (rval);
445         }
446         errx(1, "unknown media subtype: %s", val);
447         /* NOTREACHED */
448 }
449
450 static int
451 get_media_options(type, val)
452         int type;
453         const char *val;
454 {
455         struct ifmedia_description *desc;
456         struct ifmedia_type_to_subtype *ttos;
457         char *optlist, *optptr;
458         int option = 0, i, rval = 0;
459
460         /* We muck with the string, so copy it. */
461         optlist = strdup(val);
462         if (optlist == NULL)
463                 err(1, "strdup");
464
465         /* Find the top-level interface type. */
466         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
467             desc->ifmt_string != NULL; desc++, ttos++)
468                 if (type == desc->ifmt_word)
469                         break;
470         if (desc->ifmt_string == NULL)
471                 errx(1, "unknown media type 0x%x", type);
472
473         /*
474          * Look up the options in the user-provided comma-separated
475          * list.
476          */
477         optptr = optlist;
478         for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
479                 for (i = 0; ttos->options[i].desc != NULL; i++) {
480                         option = lookup_media_word(ttos->options[i].desc, optptr);
481                         if (option != -1)
482                                 break;
483                 }
484                 if (option == 0)
485                         errx(1, "unknown option: %s", optptr);
486                 rval |= option;
487         }
488
489         free(optlist);
490         return (rval);
491 }
492
493 static int
494 lookup_media_word(desc, val)
495         struct ifmedia_description *desc;
496         const char *val;
497 {
498
499         for (; desc->ifmt_string != NULL; desc++)
500                 if (strcasecmp(desc->ifmt_string, val) == 0)
501                         return (desc->ifmt_word);
502
503         return (-1);
504 }
505
506 static struct ifmedia_description *get_toptype_desc(ifmw)
507         int ifmw;
508 {
509         struct ifmedia_description *desc;
510
511         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
512                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
513                         break;
514
515         return desc;
516 }
517
518 static struct ifmedia_type_to_subtype *get_toptype_ttos(ifmw)
519         int ifmw;
520 {
521         struct ifmedia_description *desc;
522         struct ifmedia_type_to_subtype *ttos;
523
524         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
525             desc->ifmt_string != NULL; desc++, ttos++)
526                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
527                         break;
528
529         return ttos;
530 }
531
532 static struct ifmedia_description *get_subtype_desc(ifmw, ttos)
533         int ifmw;
534         struct ifmedia_type_to_subtype *ttos;
535 {
536         int i;
537         struct ifmedia_description *desc;
538
539         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
540                 if (ttos->subtypes[i].alias)
541                         continue;
542                 for (desc = ttos->subtypes[i].desc;
543                     desc->ifmt_string != NULL; desc++) {
544                         if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
545                                 return desc;
546                 }
547         }
548
549         return NULL;
550 }
551
552 static void
553 print_media_word(ifmw, print_toptype)
554         int ifmw;
555         int print_toptype;
556 {
557         struct ifmedia_description *desc;
558         struct ifmedia_type_to_subtype *ttos;
559         int seen_option = 0, i;
560
561         /* Find the top-level interface type. */
562         desc = get_toptype_desc(ifmw);
563         ttos = get_toptype_ttos(ifmw);
564         if (desc->ifmt_string == NULL) {
565                 printf("<unknown type>");
566                 return;
567         } else if (print_toptype) {
568                 printf("%s", desc->ifmt_string);
569         }
570
571         /*
572          * Don't print the top-level type; it's not like we can
573          * change it, or anything.
574          */
575
576         /* Find subtype. */
577         desc = get_subtype_desc(ifmw, ttos);
578         if (desc != NULL)
579                 goto got_subtype;
580
581         /* Falling to here means unknown subtype. */
582         printf("<unknown subtype>");
583         return;
584
585  got_subtype:
586         if (print_toptype)
587                 putchar(' ');
588
589         printf("%s", desc->ifmt_string);
590
591         /* Find options. */
592         for (i = 0; ttos->options[i].desc != NULL; i++) {
593                 if (ttos->options[i].alias)
594                         continue;
595                 for (desc = ttos->options[i].desc;
596                     desc->ifmt_string != NULL; desc++) {
597                         if (ifmw & desc->ifmt_word) {
598                                 if (seen_option == 0)
599                                         printf(" <");
600                                 printf("%s%s", seen_option++ ? "," : "",
601                                     desc->ifmt_string);
602                         }
603                 }
604         }
605         printf("%s", seen_option ? ">" : "");
606 }
607
608 static void
609 print_media_word_ifconfig(ifmw)
610         int ifmw;
611 {
612         struct ifmedia_description *desc;
613         struct ifmedia_type_to_subtype *ttos;
614         int i;
615
616         /* Find the top-level interface type. */
617         desc = get_toptype_desc(ifmw);
618         ttos = get_toptype_ttos(ifmw);
619         if (desc->ifmt_string == NULL) {
620                 printf("<unknown type>");
621                 return;
622         }
623
624         /*
625          * Don't print the top-level type; it's not like we can
626          * change it, or anything.
627          */
628
629         /* Find subtype. */
630         desc = get_subtype_desc(ifmw, ttos);
631         if (desc != NULL)
632                 goto got_subtype;
633
634         /* Falling to here means unknown subtype. */
635         printf("<unknown subtype>");
636         return;
637
638  got_subtype:
639         printf("media %s", desc->ifmt_string);
640
641         /* Find options. */
642         for (i = 0; ttos->options[i].desc != NULL; i++) {
643                 if (ttos->options[i].alias)
644                         continue;
645                 for (desc = ttos->options[i].desc;
646                     desc->ifmt_string != NULL; desc++) {
647                         if (ifmw & desc->ifmt_word) {
648                                 printf(" mediaopt %s", desc->ifmt_string);
649                         }
650                 }
651         }
652 }
653
654 /**********************************************************************
655  * ...until here.
656  **********************************************************************/