]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/ifmedia.c
This commit was generated by cvs2svn to compensate for changes in r95415,
[FreeBSD/FreeBSD.git] / sbin / ifconfig / ifmedia.c
1 /*      $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $      */
2 /* $FreeBSD$ */
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(const char *, int, int);
93 static int      get_media_subtype(int, const char *);
94 static int      get_media_options(int, const char *);
95 static int      lookup_media_word(struct ifmedia_description *, const char *);
96 static void     print_media_word(int, int);
97 static void     print_media_word_ifconfig(int);
98
99 static struct ifmedia_description *get_toptype_desc(int);
100 static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
101 static struct ifmedia_description *get_subtype_desc(int,
102     struct ifmedia_type_to_subtype *ttos);
103
104 void
105 media_status(int s, struct rt_addrinfo *info __unused)
106 {
107         struct ifmediareq ifmr;
108         int *media_list, i;
109
110         (void) memset(&ifmr, 0, sizeof(ifmr));
111         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
112
113         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
114                 /*
115                  * Interface doesn't support SIOC{G,S}IFMEDIA.
116                  */
117                 return;
118         }
119
120         if (ifmr.ifm_count == 0) {
121                 warnx("%s: no media types?", name);
122                 return;
123         }
124
125         media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
126         if (media_list == NULL)
127                 err(1, "malloc");
128         ifmr.ifm_ulist = media_list;
129
130         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
131                 err(1, "SIOCGIFMEDIA");
132
133         printf("\tmedia: ");
134         print_media_word(ifmr.ifm_current, 1);
135         if (ifmr.ifm_active != ifmr.ifm_current) {
136                 putchar(' ');
137                 putchar('(');
138                 print_media_word(ifmr.ifm_active, 0);
139                 putchar(')');
140         }
141
142         putchar('\n');
143
144         if (ifmr.ifm_status & IFM_AVALID) {
145                 printf("\tstatus: ");
146                 switch (IFM_TYPE(ifmr.ifm_active)) {
147                 case IFM_ETHER:
148                         if (ifmr.ifm_status & IFM_ACTIVE)
149                                 printf("active");
150                         else
151                                 printf("no carrier");
152                         break;
153
154                 case IFM_FDDI:
155                 case IFM_TOKEN:
156                         if (ifmr.ifm_status & IFM_ACTIVE)
157                                 printf("inserted");
158                         else
159                                 printf("no ring");
160                         break;
161                 case IFM_IEEE80211:
162                         /* XXX: Different value for adhoc? */
163                         if (ifmr.ifm_status & IFM_ACTIVE)
164                                 printf("associated");
165                         else
166                                 printf("no carrier");
167                         break;
168                 }
169                 putchar('\n');
170         }
171
172         if (ifmr.ifm_count > 0 && supmedia) {
173                 printf("\tsupported media:\n");
174                 for (i = 0; i < ifmr.ifm_count; i++) {
175                         printf("\t\t");
176                         print_media_word_ifconfig(media_list[i]);
177                         putchar('\n');
178                 }
179         }
180
181         free(media_list);
182 }
183
184 void
185 setmedia(const char *val, int d, int s, const struct afswtch *afp)
186 {
187         struct ifmediareq ifmr;
188         int first_type, subtype;
189
190         (void) memset(&ifmr, 0, sizeof(ifmr));
191         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
192
193         ifmr.ifm_count = 1;
194         ifmr.ifm_ulist = &first_type;
195         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
196                 /*
197                  * If we get E2BIG, the kernel is telling us
198                  * that there are more, so we can ignore it.
199                  */
200                 if (errno != E2BIG)
201                         err(1, "SIOCGIFMEDIA");
202         }
203
204         if (ifmr.ifm_count == 0)
205                 errx(1, "%s: no media types?", name);
206
207         /*
208          * We are primarily concerned with the top-level type.
209          * However, "current" may be only IFM_NONE, so we just look
210          * for the top-level type in the first "supported type"
211          * entry.
212          *
213          * (I'm assuming that all supported media types for a given
214          * interface will be the same top-level type..)
215          */
216         subtype = get_media_subtype(IFM_TYPE(first_type), val);
217
218         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
219         ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
220             IFM_TYPE(first_type) | subtype;
221
222         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
223                 err(1, "SIOCSIFMEDIA");
224 }
225
226 void
227 setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
228 {
229
230         domediaopt(val, 0, s);
231 }
232
233 void
234 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
235 {
236
237         domediaopt(val, 1, s);
238 }
239
240 static void
241 domediaopt(const char *val, int clear, int s)
242 {
243         struct ifmediareq ifmr;
244         int *mwords, options;
245
246         (void) memset(&ifmr, 0, sizeof(ifmr));
247         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
248
249         /*
250          * We must go through the motions of reading all
251          * supported media because we need to know both
252          * the current media type and the top-level type.
253          */
254
255         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
256                 err(1, "SIOCGIFMEDIA");
257
258         if (ifmr.ifm_count == 0)
259                 errx(1, "%s: no media types?", name);
260
261         mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
262         if (mwords == NULL)
263                 err(1, "malloc");
264
265         ifmr.ifm_ulist = mwords;
266         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
267                 err(1, "SIOCGIFMEDIA");
268
269         options = get_media_options(IFM_TYPE(mwords[0]), val);
270
271         free(mwords);
272
273         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
274         ifr.ifr_media = ifmr.ifm_current;
275         if (clear)
276                 ifr.ifr_media &= ~options;
277         else
278                 ifr.ifr_media |= options;
279
280         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
281                 err(1, "SIOCSIFMEDIA");
282 }
283
284 /**********************************************************************
285  * A good chunk of this is duplicated from sys/net/ifmedia.c
286  **********************************************************************/
287
288 static struct ifmedia_description ifm_type_descriptions[] =
289     IFM_TYPE_DESCRIPTIONS;
290
291 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
292     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
293
294 static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
295     IFM_SUBTYPE_ETHERNET_ALIASES;
296
297 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
298     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
299
300 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
301     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
302
303 static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
304     IFM_SUBTYPE_TOKENRING_ALIASES;
305
306 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
307     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
308
309 static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
310     IFM_SUBTYPE_FDDI_DESCRIPTIONS;
311
312 static struct ifmedia_description ifm_subtype_fddi_aliases[] =
313     IFM_SUBTYPE_FDDI_ALIASES;
314
315 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
316     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
317
318 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
319     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
320
321 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
322     IFM_SUBTYPE_IEEE80211_ALIASES;
323
324 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
325     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
326
327 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
328     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
329
330 static struct ifmedia_description ifm_subtype_shared_aliases[] =
331     IFM_SUBTYPE_SHARED_ALIASES;
332
333 static struct ifmedia_description ifm_shared_option_descriptions[] =
334     IFM_SHARED_OPTION_DESCRIPTIONS;
335
336 struct ifmedia_type_to_subtype {
337         struct {
338                 struct ifmedia_description *desc;
339                 int alias;
340         } subtypes[5];
341         struct {
342                 struct ifmedia_description *desc;
343                 int alias;
344         } options[3];
345 };
346
347 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
348 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
349         {
350                 {
351                         { &ifm_subtype_shared_descriptions[0], 0 },
352                         { &ifm_subtype_shared_aliases[0], 1 },
353                         { &ifm_subtype_ethernet_descriptions[0], 0 },
354                         { &ifm_subtype_ethernet_aliases[0], 1 },
355                         { NULL, 0 },
356                 },
357                 {
358                         { &ifm_shared_option_descriptions[0], 0 },
359                         { &ifm_subtype_ethernet_option_descriptions[0], 0 },
360                         { NULL, 0 },
361                 },
362         },
363         {
364                 {
365                         { &ifm_subtype_shared_descriptions[0], 0 },
366                         { &ifm_subtype_shared_aliases[0], 1 },
367                         { &ifm_subtype_tokenring_descriptions[0], 0 },
368                         { &ifm_subtype_tokenring_aliases[0], 1 },
369                         { NULL, 0 },
370                 },
371                 {
372                         { &ifm_shared_option_descriptions[0], 0 },
373                         { &ifm_subtype_tokenring_option_descriptions[0], 0 },
374                         { NULL, 0 },
375                 },
376         },
377         {
378                 {
379                         { &ifm_subtype_shared_descriptions[0], 0 },
380                         { &ifm_subtype_shared_aliases[0], 1 },
381                         { &ifm_subtype_fddi_descriptions[0], 0 },
382                         { &ifm_subtype_fddi_aliases[0], 1 },
383                         { NULL, 0 },
384                 },
385                 {
386                         { &ifm_shared_option_descriptions[0], 0 },
387                         { &ifm_subtype_fddi_option_descriptions[0], 0 },
388                         { NULL, 0 },
389                 },
390         },
391         {
392                 {
393                         { &ifm_subtype_shared_descriptions[0], 0 },
394                         { &ifm_subtype_shared_aliases[0], 1 },
395                         { &ifm_subtype_ieee80211_descriptions[0], 0 },
396                         { &ifm_subtype_ieee80211_aliases[0], 1 },
397                         { NULL, 0 },
398                 },
399                 {
400                         { &ifm_shared_option_descriptions[0], 0 },
401                         { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
402                         { NULL, 0 },
403                 },
404         },
405 };
406
407 static int
408 get_media_subtype(int type, const char *val)
409 {
410         struct ifmedia_description *desc;
411         struct ifmedia_type_to_subtype *ttos;
412         int rval, i;
413
414         /* Find the top-level interface type. */
415         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
416             desc->ifmt_string != NULL; desc++, ttos++)
417                 if (type == desc->ifmt_word)
418                         break;
419         if (desc->ifmt_string == NULL)
420                 errx(1, "unknown media type 0x%x", type);
421
422         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
423                 rval = lookup_media_word(ttos->subtypes[i].desc, val);
424                 if (rval != -1)
425                         return (rval);
426         }
427         errx(1, "unknown media subtype: %s", val);
428         /* NOTREACHED */
429 }
430
431 static int
432 get_media_options(int type, const char *val)
433 {
434         struct ifmedia_description *desc;
435         struct ifmedia_type_to_subtype *ttos;
436         char *optlist, *optptr;
437         int option = 0, i, rval = 0;
438
439         /* We muck with the string, so copy it. */
440         optlist = strdup(val);
441         if (optlist == NULL)
442                 err(1, "strdup");
443
444         /* Find the top-level interface type. */
445         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
446             desc->ifmt_string != NULL; desc++, ttos++)
447                 if (type == desc->ifmt_word)
448                         break;
449         if (desc->ifmt_string == NULL)
450                 errx(1, "unknown media type 0x%x", type);
451
452         /*
453          * Look up the options in the user-provided comma-separated
454          * list.
455          */
456         optptr = optlist;
457         for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
458                 for (i = 0; ttos->options[i].desc != NULL; i++) {
459                         option = lookup_media_word(ttos->options[i].desc, optptr);
460                         if (option != -1)
461                                 break;
462                 }
463                 if (option == 0)
464                         errx(1, "unknown option: %s", optptr);
465                 rval |= option;
466         }
467
468         free(optlist);
469         return (rval);
470 }
471
472 static int
473 lookup_media_word(struct ifmedia_description *desc, const char *val)
474 {
475
476         for (; desc->ifmt_string != NULL; desc++)
477                 if (strcasecmp(desc->ifmt_string, val) == 0)
478                         return (desc->ifmt_word);
479
480         return (-1);
481 }
482
483 static struct ifmedia_description *get_toptype_desc(int ifmw)
484 {
485         struct ifmedia_description *desc;
486
487         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
488                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
489                         break;
490
491         return desc;
492 }
493
494 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
495 {
496         struct ifmedia_description *desc;
497         struct ifmedia_type_to_subtype *ttos;
498
499         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
500             desc->ifmt_string != NULL; desc++, ttos++)
501                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
502                         break;
503
504         return ttos;
505 }
506
507 static struct ifmedia_description *get_subtype_desc(int ifmw, 
508     struct ifmedia_type_to_subtype *ttos)
509 {
510         int i;
511         struct ifmedia_description *desc;
512
513         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
514                 if (ttos->subtypes[i].alias)
515                         continue;
516                 for (desc = ttos->subtypes[i].desc;
517                     desc->ifmt_string != NULL; desc++) {
518                         if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
519                                 return desc;
520                 }
521         }
522
523         return NULL;
524 }
525
526 static void
527 print_media_word(int ifmw, int print_toptype)
528 {
529         struct ifmedia_description *desc;
530         struct ifmedia_type_to_subtype *ttos;
531         int seen_option = 0, i;
532
533         /* Find the top-level interface type. */
534         desc = get_toptype_desc(ifmw);
535         ttos = get_toptype_ttos(ifmw);
536         if (desc->ifmt_string == NULL) {
537                 printf("<unknown type>");
538                 return;
539         } else if (print_toptype) {
540                 printf("%s", desc->ifmt_string);
541         }
542
543         /*
544          * Don't print the top-level type; it's not like we can
545          * change it, or anything.
546          */
547
548         /* Find subtype. */
549         desc = get_subtype_desc(ifmw, ttos);
550         if (desc != NULL)
551                 goto got_subtype;
552
553         /* Falling to here means unknown subtype. */
554         printf("<unknown subtype>");
555         return;
556
557  got_subtype:
558         if (print_toptype)
559                 putchar(' ');
560
561         printf("%s", desc->ifmt_string);
562
563         /* Find options. */
564         for (i = 0; ttos->options[i].desc != NULL; i++) {
565                 if (ttos->options[i].alias)
566                         continue;
567                 for (desc = ttos->options[i].desc;
568                     desc->ifmt_string != NULL; desc++) {
569                         if (ifmw & desc->ifmt_word) {
570                                 if (seen_option == 0)
571                                         printf(" <");
572                                 printf("%s%s", seen_option++ ? "," : "",
573                                     desc->ifmt_string);
574                         }
575                 }
576         }
577         printf("%s", seen_option ? ">" : "");
578 }
579
580 static void
581 print_media_word_ifconfig(int ifmw)
582 {
583         struct ifmedia_description *desc;
584         struct ifmedia_type_to_subtype *ttos;
585         int i;
586
587         /* Find the top-level interface type. */
588         desc = get_toptype_desc(ifmw);
589         ttos = get_toptype_ttos(ifmw);
590         if (desc->ifmt_string == NULL) {
591                 printf("<unknown type>");
592                 return;
593         }
594
595         /*
596          * Don't print the top-level type; it's not like we can
597          * change it, or anything.
598          */
599
600         /* Find subtype. */
601         desc = get_subtype_desc(ifmw, ttos);
602         if (desc != NULL)
603                 goto got_subtype;
604
605         /* Falling to here means unknown subtype. */
606         printf("<unknown subtype>");
607         return;
608
609  got_subtype:
610         printf("media %s", desc->ifmt_string);
611
612         /* Find options. */
613         for (i = 0; ttos->options[i].desc != NULL; i++) {
614                 if (ttos->options[i].alias)
615                         continue;
616                 for (desc = ttos->options[i].desc;
617                     desc->ifmt_string != NULL; desc++) {
618                         if (ifmw & desc->ifmt_word) {
619                                 printf(" mediaopt %s", desc->ifmt_string);
620                         }
621                 }
622         }
623 }
624
625 /**********************************************************************
626  * ...until here.
627  **********************************************************************/