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