e95f8c36562b1e7c8e6bf4970acba2978de87bb1
[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.8 2005/03/06 05:01:59 dillon 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 #ifndef IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS
94   #define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS {                       \
95         { IFM_AUTO, "autoselect" },                                     \
96         { IFM_IEEE80211_11A, "11a" },                                   \
97         { IFM_IEEE80211_11B, "11b" },                                   \
98         { IFM_IEEE80211_11G, "11g" },                                   \
99         { IFM_IEEE80211_FH, "fh" },                                     \
100         { 0, NULL },                                                    \
101 }
102 #endif
103
104 #ifndef IFM_SUBTYPE_IEEE80211_MODE_ALIASES
105   #define IFM_SUBTYPE_IEEE80211_MODE_ALIASES {                            \
106         { IFM_AUTO, "auto" },                                           \
107         { 0, NULL },                                                    \
108 }
109 #endif
110
111 static void     domediaopt(const char *, int, int);
112 static int      get_media_subtype(int, const char *);
113 static int      get_media_mode(int, const char *);
114 static int      get_media_options(int, const char *);
115 static int      lookup_media_word(struct ifmedia_description *, const char *);
116 static void     print_media_word(int, int);
117 static void     print_media_word_ifconfig(int);
118
119 static struct ifmedia_description *get_toptype_desc(int);
120 static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
121 static struct ifmedia_description *get_subtype_desc(int,
122     struct ifmedia_type_to_subtype *ttos);
123
124 void
125 media_status(int s, struct rt_addrinfo *info __unused)
126 {
127         struct ifmediareq ifmr;
128         int *media_list, i;
129
130         (void) memset(&ifmr, 0, sizeof(ifmr));
131         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
132
133         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
134                 /*
135                  * Interface doesn't support SIOC{G,S}IFMEDIA.
136                  */
137                 return;
138         }
139
140         if (ifmr.ifm_count == 0) {
141                 warnx("%s: no media types?", name);
142                 return;
143         }
144
145         media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
146         if (media_list == NULL)
147                 err(1, "malloc");
148         ifmr.ifm_ulist = media_list;
149
150         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
151                 err(1, "SIOCGIFMEDIA");
152
153         printf("\tmedia: ");
154         print_media_word(ifmr.ifm_current, 1);
155         if (ifmr.ifm_active != ifmr.ifm_current) {
156                 putchar(' ');
157                 putchar('(');
158                 print_media_word(ifmr.ifm_active, 0);
159                 putchar(')');
160         }
161
162         putchar('\n');
163
164         if (ifmr.ifm_status & IFM_AVALID) {
165                 printf("\tstatus: ");
166                 switch (IFM_TYPE(ifmr.ifm_active)) {
167                 case IFM_ETHER:
168                         if (ifmr.ifm_status & IFM_ACTIVE)
169                                 printf("active");
170                         else
171                                 printf("no carrier");
172                         break;
173
174                 case IFM_FDDI:
175                 case IFM_TOKEN:
176                         if (ifmr.ifm_status & IFM_ACTIVE)
177                                 printf("inserted");
178                         else
179                                 printf("no ring");
180                         break;
181
182 #if notyet
183                 case IFM_ATM:
184                         if (ifmr.ifm_status & IFM_ACTIVE)
185                                 printf("active");
186                         else
187                                 printf("no carrier");
188                         break;
189 #endif
190
191                 case IFM_IEEE80211:
192                         /* XXX: Different value for adhoc? */
193                         if (ifmr.ifm_status & IFM_ACTIVE)
194                                 printf("associated");
195                         else
196                                 printf("no carrier");
197                         break;
198                 }
199                 putchar('\n');
200         }
201
202         if (ifmr.ifm_count > 0 && supmedia) {
203                 printf("\tsupported media:\n");
204                 for (i = 0; i < ifmr.ifm_count; i++) {
205                         printf("\t\t");
206                         print_media_word_ifconfig(media_list[i]);
207                         putchar('\n');
208                 }
209         }
210
211         free(media_list);
212 }
213
214 void
215 setmedia(const char *val, int d __unused, int s,
216          const struct afswtch *afp __unused)
217 {
218         struct ifmediareq ifmr;
219         int first_type, subtype;
220
221         (void) memset(&ifmr, 0, sizeof(ifmr));
222         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
223
224         ifmr.ifm_count = 1;
225         ifmr.ifm_ulist = &first_type;
226         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
227                 /*
228                  * If we get E2BIG, the kernel is telling us
229                  * that there are more, so we can ignore it.
230                  */
231                 if (errno != E2BIG)
232                         err(1, "SIOCGIFMEDIA");
233         }
234
235         if (ifmr.ifm_count == 0)
236                 errx(1, "%s: no media types?", name);
237
238         /*
239          * We are primarily concerned with the top-level type.
240          * However, "current" may be only IFM_NONE, so we just look
241          * for the top-level type in the first "supported type"
242          * entry.
243          *
244          * (I'm assuming that all supported media types for a given
245          * interface will be the same top-level type..)
246          */
247         subtype = get_media_subtype(IFM_TYPE(first_type), val);
248
249         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
250         ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
251             IFM_TYPE(first_type) | subtype;
252
253         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
254                 err(1, "SIOCSIFMEDIA (media)");
255 }
256
257 void
258 setmediaopt(const char *val, int d __unused, int s,
259             const struct afswtch *afp __unused)
260 {
261
262         domediaopt(val, 0, s);
263 }
264
265 void
266 unsetmediaopt(const char *val, int d __unused, int s,
267               const struct afswtch *afp __unused)
268 {
269
270         domediaopt(val, 1, s);
271 }
272
273 static void
274 domediaopt(const char *val, int clear, int s)
275 {
276         struct ifmediareq ifmr;
277         int *mwords, options;
278
279         (void) memset(&ifmr, 0, sizeof(ifmr));
280         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
281
282         /*
283          * We must go through the motions of reading all
284          * supported media because we need to know both
285          * the current media type and the top-level type.
286          */
287
288         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
289                 err(1, "SIOCGIFMEDIA");
290
291         if (ifmr.ifm_count == 0)
292                 errx(1, "%s: no media types?", name);
293
294         mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
295         if (mwords == NULL)
296                 err(1, "malloc");
297
298         ifmr.ifm_ulist = mwords;
299         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
300                 err(1, "SIOCGIFMEDIA");
301
302         options = get_media_options(IFM_TYPE(mwords[0]), val);
303
304         free(mwords);
305
306         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
307         ifr.ifr_media = ifmr.ifm_current;
308         if (clear)
309                 ifr.ifr_media &= ~options;
310         else
311                 ifr.ifr_media |= options;
312
313         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
314                 err(1, "SIOCSIFMEDIA (mediaopt)");
315 }
316
317
318 void
319 setmediamode(const char *val, int d __unused, int s,
320         const struct afswtch *afp __unused)
321 {
322         struct ifmediareq ifmr;
323         int *mwords, mode;
324
325         (void) memset(&ifmr, 0, sizeof(ifmr));
326         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
327
328         /*
329          * We must go through the motions of reading all
330          * supported media because we need to know both
331          * the current media type and the top-level type.
332          */
333
334         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
335                 err(1, "SIOCGIFMEDIA");
336
337         if (ifmr.ifm_count == 0)
338                 errx(1, "%s: no media types?", name);
339
340         mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
341         if (mwords == NULL)
342                 err(1, "malloc");
343
344         ifmr.ifm_ulist = mwords;
345         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
346                 err(1, "SIOCGIFMEDIA");
347
348         mode = get_media_mode(IFM_TYPE(mwords[0]), val);
349
350         free(mwords);
351
352         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
353         ifr.ifr_media = (ifmr.ifm_current & ~IFM_MMASK) | mode;
354
355         if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
356                 err(1, "SIOCSIFMEDIA (mode)");
357 }
358
359 /**********************************************************************
360  * A good chunk of this is duplicated from sys/net/ifmedia.c
361  **********************************************************************/
362
363 static struct ifmedia_description ifm_type_descriptions[] =
364     IFM_TYPE_DESCRIPTIONS;
365
366 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
367     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
368
369 static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
370     IFM_SUBTYPE_ETHERNET_ALIASES;
371
372 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
373     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
374
375 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
376     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
377
378 static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
379     IFM_SUBTYPE_TOKENRING_ALIASES;
380
381 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
382     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
383
384 static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
385     IFM_SUBTYPE_FDDI_DESCRIPTIONS;
386
387 static struct ifmedia_description ifm_subtype_fddi_aliases[] =
388     IFM_SUBTYPE_FDDI_ALIASES;
389
390 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
391     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
392
393 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
394     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
395
396 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
397     IFM_SUBTYPE_IEEE80211_ALIASES;
398
399 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
400     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
401
402 struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
403     IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
404
405 struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
406     IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
407
408 #if notyet
409 static struct ifmedia_description ifm_subtype_atm_descriptions[] =
410     IFM_SUBTYPE_ATM_DESCRIPTIONS;
411
412 static struct ifmedia_description ifm_subtype_atm_aliases[] =
413     IFM_SUBTYPE_ATM_ALIASES;
414
415 static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
416     IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
417 #endif
418
419 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
420     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
421
422 static struct ifmedia_description ifm_subtype_shared_aliases[] =
423     IFM_SUBTYPE_SHARED_ALIASES;
424
425 static struct ifmedia_description ifm_shared_option_descriptions[] =
426     IFM_SHARED_OPTION_DESCRIPTIONS;
427
428 struct ifmedia_type_to_subtype {
429         struct {
430                 struct ifmedia_description *desc;
431                 int alias;
432         } subtypes[5];
433         struct {
434                 struct ifmedia_description *desc;
435                 int alias;
436         } options[3];
437         struct {
438                 struct ifmedia_description *desc;
439                 int alias;
440         } modes[3];
441 };
442
443 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
444 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
445         {
446                 {
447                         { &ifm_subtype_shared_descriptions[0], 0 },
448                         { &ifm_subtype_shared_aliases[0], 1 },
449                         { &ifm_subtype_ethernet_descriptions[0], 0 },
450                         { &ifm_subtype_ethernet_aliases[0], 1 },
451                         { NULL, 0 },
452                 },
453                 {
454                         { &ifm_shared_option_descriptions[0], 0 },
455                         { &ifm_subtype_ethernet_option_descriptions[0], 0 },
456                         { NULL, 0 },
457                 },
458                 {
459                         { NULL, 0 },
460                 },
461         },
462         {
463                 {
464                         { &ifm_subtype_shared_descriptions[0], 0 },
465                         { &ifm_subtype_shared_aliases[0], 1 },
466                         { &ifm_subtype_tokenring_descriptions[0], 0 },
467                         { &ifm_subtype_tokenring_aliases[0], 1 },
468                         { NULL, 0 },
469                 },
470                 {
471                         { &ifm_shared_option_descriptions[0], 0 },
472                         { &ifm_subtype_tokenring_option_descriptions[0], 0 },
473                         { NULL, 0 },
474                 },
475                 {
476                         { NULL, 0 },
477                 },
478         },
479         {
480                 {
481                         { &ifm_subtype_shared_descriptions[0], 0 },
482                         { &ifm_subtype_shared_aliases[0], 1 },
483                         { &ifm_subtype_fddi_descriptions[0], 0 },
484                         { &ifm_subtype_fddi_aliases[0], 1 },
485                         { NULL, 0 },
486                 },
487                 {
488                         { &ifm_shared_option_descriptions[0], 0 },
489                         { &ifm_subtype_fddi_option_descriptions[0], 0 },
490                         { NULL, 0 },
491                 },
492                 {
493                         { NULL, 0 },
494                 },
495         },
496         {
497                 {
498                         { &ifm_subtype_shared_descriptions[0], 0 },
499                         { &ifm_subtype_shared_aliases[0], 1 },
500                         { &ifm_subtype_ieee80211_descriptions[0], 0 },
501                         { &ifm_subtype_ieee80211_aliases[0], 1 },
502                         { NULL, 0 },
503                 },
504                 {
505                         { &ifm_shared_option_descriptions[0], 0 },
506                         { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
507                         { NULL, 0 },
508                 },
509                 {
510                         { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
511                         { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
512                         { NULL, 0 },
513                 },
514         },
515         {
516                 {
517                         { &ifm_subtype_shared_descriptions[0], 0 },
518                         { &ifm_subtype_shared_aliases[0], 1 },
519 #if notyet
520                         { &ifm_subtype_atm_descriptions[0], 0 },
521                         { &ifm_subtype_atm_aliases[0], 1 },
522 #endif
523                         { NULL, 0 },
524                 },
525                 {
526                         { &ifm_shared_option_descriptions[0], 0 },
527 #if notyet
528                         { &ifm_subtype_atm_option_descriptions[0], 0 },
529 #endif
530                         { NULL, 0 },
531                 },
532                 {
533                         { NULL, 0 },
534                 },
535         },
536 };
537
538 static int
539 get_media_subtype(int type, const char *val)
540 {
541         struct ifmedia_description *desc;
542         struct ifmedia_type_to_subtype *ttos;
543         int rval, i;
544
545         /* Find the top-level interface type. */
546         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
547             desc->ifmt_string != NULL; desc++, ttos++)
548                 if (type == desc->ifmt_word)
549                         break;
550         if (desc->ifmt_string == NULL)
551                 errx(1, "unknown media type 0x%x", type);
552
553         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
554                 rval = lookup_media_word(ttos->subtypes[i].desc, val);
555                 if (rval != -1)
556                         return (rval);
557         }
558         errx(1, "unknown media subtype: %s", val);
559         /*NOTREACHED*/
560 }
561
562 static int
563 get_media_mode(int type, const char *val)
564 {
565         struct ifmedia_description *desc;
566         struct ifmedia_type_to_subtype *ttos;
567         int rval, i;
568
569         /* Find the top-level interface type. */
570         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
571             desc->ifmt_string != NULL; desc++, ttos++)
572                 if (type == desc->ifmt_word)
573                         break;
574         if (desc->ifmt_string == NULL)
575                 errx(1, "unknown media mode 0x%x", type);
576
577         for (i = 0; ttos->modes[i].desc != NULL; i++) {
578                 rval = lookup_media_word(ttos->modes[i].desc, val);
579                 if (rval != -1)
580                         return (rval);
581         }
582         return -1;
583 }
584
585 static int
586 get_media_options(int type, const char *val)
587 {
588         struct ifmedia_description *desc;
589         struct ifmedia_type_to_subtype *ttos;
590         char *optlist, *optptr;
591         int option = 0, i, rval = 0;
592
593         /* We muck with the string, so copy it. */
594         optlist = strdup(val);
595         if (optlist == NULL)
596                 err(1, "strdup");
597
598         /* Find the top-level interface type. */
599         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
600             desc->ifmt_string != NULL; desc++, ttos++)
601                 if (type == desc->ifmt_word)
602                         break;
603         if (desc->ifmt_string == NULL)
604                 errx(1, "unknown media type 0x%x", type);
605
606         /*
607          * Look up the options in the user-provided comma-separated
608          * list.
609          */
610         optptr = optlist;
611         for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
612                 for (i = 0; ttos->options[i].desc != NULL; i++) {
613                         option = lookup_media_word(ttos->options[i].desc, optptr);
614                         if (option != -1)
615                                 break;
616                 }
617                 if (option == 0)
618                         errx(1, "unknown option: %s", optptr);
619                 rval |= option;
620         }
621
622         free(optlist);
623         return (rval);
624 }
625
626 static int
627 lookup_media_word(struct ifmedia_description *desc, const char *val)
628 {
629
630         for (; desc->ifmt_string != NULL; desc++)
631                 if (strcasecmp(desc->ifmt_string, val) == 0)
632                         return (desc->ifmt_word);
633
634         return (-1);
635 }
636
637 static struct ifmedia_description *get_toptype_desc(int ifmw)
638 {
639         struct ifmedia_description *desc;
640
641         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
642                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
643                         break;
644
645         return desc;
646 }
647
648 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
649 {
650         struct ifmedia_description *desc;
651         struct ifmedia_type_to_subtype *ttos;
652
653         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
654             desc->ifmt_string != NULL; desc++, ttos++)
655                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
656                         break;
657
658         return ttos;
659 }
660
661 static struct ifmedia_description *get_subtype_desc(int ifmw, 
662     struct ifmedia_type_to_subtype *ttos)
663 {
664         int i;
665         struct ifmedia_description *desc;
666
667         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
668                 if (ttos->subtypes[i].alias)
669                         continue;
670                 for (desc = ttos->subtypes[i].desc;
671                     desc->ifmt_string != NULL; desc++) {
672                         if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
673                                 return desc;
674                 }
675         }
676
677         return NULL;
678 }
679
680 static struct ifmedia_description *get_mode_desc(int ifmw, 
681     struct ifmedia_type_to_subtype *ttos)
682 {
683         int i;
684         struct ifmedia_description *desc;
685
686         for (i = 0; ttos->modes[i].desc != NULL; i++) {
687                 if (ttos->modes[i].alias)
688                         continue;
689                 for (desc = ttos->modes[i].desc;
690                     desc->ifmt_string != NULL; desc++) {
691                         if (IFM_MODE(ifmw) == desc->ifmt_word)
692                                 return desc;
693                 }
694         }
695
696         return NULL;
697 }
698
699 static void
700 print_media_word(int ifmw, int print_toptype)
701 {
702         struct ifmedia_description *desc;
703         struct ifmedia_type_to_subtype *ttos;
704         int seen_option = 0, i;
705
706         /* Find the top-level interface type. */
707         desc = get_toptype_desc(ifmw);
708         ttos = get_toptype_ttos(ifmw);
709         if (desc->ifmt_string == NULL) {
710                 printf("<unknown type>");
711                 return;
712         } else if (print_toptype) {
713                 printf("%s", desc->ifmt_string);
714         }
715
716         /*
717          * Don't print the top-level type; it's not like we can
718          * change it, or anything.
719          */
720
721         /* Find subtype. */
722         desc = get_subtype_desc(ifmw, ttos);
723         if (desc != NULL)
724                 goto got_subtype;
725
726         /* Falling to here means unknown subtype. */
727         printf("<unknown subtype>");
728         return;
729
730  got_subtype:
731         if (print_toptype)
732                 putchar(' ');
733
734         printf("%s", desc->ifmt_string);
735
736         if (print_toptype) {
737                 desc = get_mode_desc(ifmw, ttos);
738                 if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
739                         printf(" mode %s", desc->ifmt_string);
740         }
741
742         /* Find options. */
743         for (i = 0; ttos->options[i].desc != NULL; i++) {
744                 if (ttos->options[i].alias)
745                         continue;
746                 for (desc = ttos->options[i].desc;
747                     desc->ifmt_string != NULL; desc++) {
748                         if (ifmw & desc->ifmt_word) {
749                                 if (seen_option == 0)
750                                         printf(" <");
751                                 printf("%s%s", seen_option++ ? "," : "",
752                                     desc->ifmt_string);
753                         }
754                 }
755         }
756         printf("%s", seen_option ? ">" : "");
757 }
758
759 static void
760 print_media_word_ifconfig(int ifmw)
761 {
762         struct ifmedia_description *desc;
763         struct ifmedia_type_to_subtype *ttos;
764         int i;
765
766         /* Find the top-level interface type. */
767         desc = get_toptype_desc(ifmw);
768         ttos = get_toptype_ttos(ifmw);
769         if (desc->ifmt_string == NULL) {
770                 printf("<unknown type>");
771                 return;
772         }
773
774         /*
775          * Don't print the top-level type; it's not like we can
776          * change it, or anything.
777          */
778
779         /* Find subtype. */
780         desc = get_subtype_desc(ifmw, ttos);
781         if (desc != NULL)
782                 goto got_subtype;
783
784         /* Falling to here means unknown subtype. */
785         printf("<unknown subtype>");
786         return;
787
788  got_subtype:
789         printf("media %s", desc->ifmt_string);
790
791         desc = get_mode_desc(ifmw, ttos);
792         if (desc != NULL)
793                 printf(" mode %s", desc->ifmt_string);
794
795         /* Find options. */
796         for (i = 0; ttos->options[i].desc != NULL; i++) {
797                 if (ttos->options[i].alias)
798                         continue;
799                 for (desc = ttos->options[i].desc;
800                     desc->ifmt_string != NULL; desc++) {
801                         if (ifmw & desc->ifmt_word) {
802                                 printf(" mediaopt %s", desc->ifmt_string);
803                         }
804                 }
805         }
806 }
807
808 /**********************************************************************
809  * ...until here.
810  **********************************************************************/