]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/etherswitchcfg/ifmedia.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sbin / etherswitchcfg / 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  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 /*
65  * based on sbin/ifconfig/ifmedia.c r221954
66  */
67
68 #include <sys/param.h>
69 #include <sys/ioctl.h>
70 #include <sys/socket.h>
71 #include <sys/sysctl.h>
72 #include <sys/time.h>
73
74 #include <net/if.h>
75 #include <net/if_dl.h>
76 #include <net/if_types.h>
77 #include <net/if_media.h>
78 #include <net/route.h>
79
80 #include <ctype.h>
81 #include <err.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88
89 void    domediaopt(const char *, int, int);
90 int     get_media_subtype(int, const char *);
91 int     get_media_mode(int, const char *);
92 int     get_media_options(int, const char *);
93 int     lookup_media_word(struct ifmedia_description *, const char *);
94 void    print_media_word(int, int);
95 void    print_media_word_ifconfig(int);
96
97 #if 0
98 static struct ifmedia_description *get_toptype_desc(int);
99 static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
100 static struct ifmedia_description *get_subtype_desc(int,
101     struct ifmedia_type_to_subtype *ttos);
102
103 #define IFM_OPMODE(x) \
104         ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
105          IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
106          IFM_IEEE80211_MBSS))
107 #define IFM_IEEE80211_STA       0
108
109 static void
110 media_status(int s)
111 {
112         struct ifmediareq ifmr;
113         int *media_list, i;
114
115         (void) memset(&ifmr, 0, sizeof(ifmr));
116         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
117
118         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
119                 /*
120                  * Interface doesn't support SIOC{G,S}IFMEDIA.
121                  */
122                 return;
123         }
124
125         if (ifmr.ifm_count == 0) {
126                 warnx("%s: no media types?", name);
127                 return;
128         }
129
130         media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
131         if (media_list == NULL)
132                 err(1, "malloc");
133         ifmr.ifm_ulist = media_list;
134
135         if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
136                 err(1, "SIOCGIFMEDIA");
137
138         printf("\tmedia: ");
139         print_media_word(ifmr.ifm_current, 1);
140         if (ifmr.ifm_active != ifmr.ifm_current) {
141                 putchar(' ');
142                 putchar('(');
143                 print_media_word(ifmr.ifm_active, 0);
144                 putchar(')');
145         }
146
147         putchar('\n');
148
149         if (ifmr.ifm_status & IFM_AVALID) {
150                 printf("\tstatus: ");
151                 switch (IFM_TYPE(ifmr.ifm_active)) {
152                 case IFM_ETHER:
153                 case IFM_ATM:
154                         if (ifmr.ifm_status & IFM_ACTIVE)
155                                 printf("active");
156                         else
157                                 printf("no carrier");
158                         break;
159
160                 case IFM_FDDI:
161                 case IFM_TOKEN:
162                         if (ifmr.ifm_status & IFM_ACTIVE)
163                                 printf("inserted");
164                         else
165                                 printf("no ring");
166                         break;
167
168                 case IFM_IEEE80211:
169                         if (ifmr.ifm_status & IFM_ACTIVE) {
170                                 /* NB: only sta mode associates */
171                                 if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
172                                         printf("associated");
173                                 else
174                                         printf("running");
175                         } else
176                                 printf("no carrier");
177                         break;
178                 }
179                 putchar('\n');
180         }
181
182         if (ifmr.ifm_count > 0 && supmedia) {
183                 printf("\tsupported media:\n");
184                 for (i = 0; i < ifmr.ifm_count; i++) {
185                         printf("\t\t");
186                         print_media_word_ifconfig(media_list[i]);
187                         putchar('\n');
188                 }
189         }
190
191         free(media_list);
192 }
193
194 struct ifmediareq *
195 ifmedia_getstate(int s)
196 {
197         static struct ifmediareq *ifmr = NULL;
198         int *mwords;
199
200         if (ifmr == NULL) {
201                 ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
202                 if (ifmr == NULL)
203                         err(1, "malloc");
204
205                 (void) memset(ifmr, 0, sizeof(struct ifmediareq));
206                 (void) strncpy(ifmr->ifm_name, name,
207                     sizeof(ifmr->ifm_name));
208
209                 ifmr->ifm_count = 0;
210                 ifmr->ifm_ulist = NULL;
211
212                 /*
213                  * We must go through the motions of reading all
214                  * supported media because we need to know both
215                  * the current media type and the top-level type.
216                  */
217
218                 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
219                         err(1, "SIOCGIFMEDIA");
220                 }
221
222                 if (ifmr->ifm_count == 0)
223                         errx(1, "%s: no media types?", name);
224
225                 mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
226                 if (mwords == NULL)
227                         err(1, "malloc");
228   
229                 ifmr->ifm_ulist = mwords;
230                 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
231                         err(1, "SIOCGIFMEDIA");
232         }
233
234         return ifmr;
235 }
236
237 static void
238 setifmediacallback(int s, void *arg)
239 {
240         struct ifmediareq *ifmr = (struct ifmediareq *)arg;
241         static int did_it = 0;
242
243         if (!did_it) {
244                 ifr.ifr_media = ifmr->ifm_current;
245                 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
246                         err(1, "SIOCSIFMEDIA (media)");
247                 free(ifmr->ifm_ulist);
248                 free(ifmr);
249                 did_it = 1;
250         }
251 }
252
253 static void
254 setmedia(const char *val, int d, int s, const struct afswtch *afp)
255 {
256         struct ifmediareq *ifmr;
257         int subtype;
258
259         ifmr = ifmedia_getstate(s);
260
261         /*
262          * We are primarily concerned with the top-level type.
263          * However, "current" may be only IFM_NONE, so we just look
264          * for the top-level type in the first "supported type"
265          * entry.
266          *
267          * (I'm assuming that all supported media types for a given
268          * interface will be the same top-level type..)
269          */
270         subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
271
272         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
273         ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
274             IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
275
276         ifmr->ifm_current = ifr.ifr_media;
277         callback_register(setifmediacallback, (void *)ifmr);
278 }
279
280 static void
281 setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
282 {
283
284         domediaopt(val, 0, s);
285 }
286
287 static void
288 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
289 {
290
291         domediaopt(val, 1, s);
292 }
293
294 static void
295 domediaopt(const char *val, int clear, int s)
296 {
297         struct ifmediareq *ifmr;
298         int options;
299
300         ifmr = ifmedia_getstate(s);
301
302         options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
303
304         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
305         ifr.ifr_media = ifmr->ifm_current;
306         if (clear)
307                 ifr.ifr_media &= ~options;
308         else {
309                 if (options & IFM_HDX) {
310                         ifr.ifr_media &= ~IFM_FDX;
311                         options &= ~IFM_HDX;
312                 }
313                 ifr.ifr_media |= options;
314         }
315         ifmr->ifm_current = ifr.ifr_media;
316         callback_register(setifmediacallback, (void *)ifmr);
317 }
318
319 static void
320 setmediainst(const char *val, int d, int s, const struct afswtch *afp)
321 {
322         struct ifmediareq *ifmr;
323         int inst;
324
325         ifmr = ifmedia_getstate(s);
326
327         inst = atoi(val);
328         if (inst < 0 || inst > (int)IFM_INST_MAX)
329                 errx(1, "invalid media instance: %s", val);
330
331         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
332         ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
333
334         ifmr->ifm_current = ifr.ifr_media;
335         callback_register(setifmediacallback, (void *)ifmr);
336 }
337
338 static void
339 setmediamode(const char *val, int d, int s, const struct afswtch *afp)
340 {
341         struct ifmediareq *ifmr;
342         int mode;
343
344         ifmr = ifmedia_getstate(s);
345
346         mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
347
348         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
349         ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
350
351         ifmr->ifm_current = ifr.ifr_media;
352         callback_register(setifmediacallback, (void *)ifmr);
353 }
354 #endif
355
356 /**********************************************************************
357  * A good chunk of this is duplicated from sys/net/ifmedia.c
358  **********************************************************************/
359
360 static struct ifmedia_description ifm_type_descriptions[] =
361     IFM_TYPE_DESCRIPTIONS;
362
363 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
364     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
365
366 static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
367     IFM_SUBTYPE_ETHERNET_ALIASES;
368
369 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
370     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
371
372 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
373     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
374
375 static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
376     IFM_SUBTYPE_TOKENRING_ALIASES;
377
378 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
379     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
380
381 static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
382     IFM_SUBTYPE_FDDI_DESCRIPTIONS;
383
384 static struct ifmedia_description ifm_subtype_fddi_aliases[] =
385     IFM_SUBTYPE_FDDI_ALIASES;
386
387 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
388     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
389
390 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
391     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
392
393 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
394     IFM_SUBTYPE_IEEE80211_ALIASES;
395
396 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
397     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
398
399 static struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
400     IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
401
402 static struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
403     IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
404
405 static struct ifmedia_description ifm_subtype_atm_descriptions[] =
406     IFM_SUBTYPE_ATM_DESCRIPTIONS;
407
408 static struct ifmedia_description ifm_subtype_atm_aliases[] =
409     IFM_SUBTYPE_ATM_ALIASES;
410
411 static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
412     IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
413
414 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
415     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
416
417 static struct ifmedia_description ifm_subtype_shared_aliases[] =
418     IFM_SUBTYPE_SHARED_ALIASES;
419
420 static struct ifmedia_description ifm_shared_option_descriptions[] =
421     IFM_SHARED_OPTION_DESCRIPTIONS;
422
423 static struct ifmedia_description ifm_shared_option_aliases[] =
424     IFM_SHARED_OPTION_ALIASES;
425
426 struct ifmedia_type_to_subtype {
427         struct {
428                 struct ifmedia_description *desc;
429                 int alias;
430         } subtypes[5];
431         struct {
432                 struct ifmedia_description *desc;
433                 int alias;
434         } options[4];
435         struct {
436                 struct ifmedia_description *desc;
437                 int alias;
438         } modes[3];
439 };
440
441 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
442 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
443         {
444                 {
445                         { &ifm_subtype_shared_descriptions[0], 0 },
446                         { &ifm_subtype_shared_aliases[0], 1 },
447                         { &ifm_subtype_ethernet_descriptions[0], 0 },
448                         { &ifm_subtype_ethernet_aliases[0], 1 },
449                         { NULL, 0 },
450                 },
451                 {
452                         { &ifm_shared_option_descriptions[0], 0 },
453                         { &ifm_shared_option_aliases[0], 1 },
454                         { &ifm_subtype_ethernet_option_descriptions[0], 0 },
455                         { NULL, 0 },
456                 },
457                 {
458                         { NULL, 0 },
459                 },
460         },
461         {
462                 {
463                         { &ifm_subtype_shared_descriptions[0], 0 },
464                         { &ifm_subtype_shared_aliases[0], 1 },
465                         { &ifm_subtype_tokenring_descriptions[0], 0 },
466                         { &ifm_subtype_tokenring_aliases[0], 1 },
467                         { NULL, 0 },
468                 },
469                 {
470                         { &ifm_shared_option_descriptions[0], 0 },
471                         { &ifm_shared_option_aliases[0], 1 },
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_shared_option_aliases[0], 1 },
490                         { &ifm_subtype_fddi_option_descriptions[0], 0 },
491                         { NULL, 0 },
492                 },
493                 {
494                         { NULL, 0 },
495                 },
496         },
497         {
498                 {
499                         { &ifm_subtype_shared_descriptions[0], 0 },
500                         { &ifm_subtype_shared_aliases[0], 1 },
501                         { &ifm_subtype_ieee80211_descriptions[0], 0 },
502                         { &ifm_subtype_ieee80211_aliases[0], 1 },
503                         { NULL, 0 },
504                 },
505                 {
506                         { &ifm_shared_option_descriptions[0], 0 },
507                         { &ifm_shared_option_aliases[0], 1 },
508                         { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
509                         { NULL, 0 },
510                 },
511                 {
512                         { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
513                         { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
514                         { NULL, 0 },
515                 },
516         },
517         {
518                 {
519                         { &ifm_subtype_shared_descriptions[0], 0 },
520                         { &ifm_subtype_shared_aliases[0], 1 },
521                         { &ifm_subtype_atm_descriptions[0], 0 },
522                         { &ifm_subtype_atm_aliases[0], 1 },
523                         { NULL, 0 },
524                 },
525                 {
526                         { &ifm_shared_option_descriptions[0], 0 },
527                         { &ifm_shared_option_aliases[0], 1 },
528                         { &ifm_subtype_atm_option_descriptions[0], 0 },
529                         { NULL, 0 },
530                 },
531                 {
532                         { NULL, 0 },
533                 },
534         },
535 };
536
537 int
538 get_media_subtype(int type, const char *val)
539 {
540         struct ifmedia_description *desc;
541         struct ifmedia_type_to_subtype *ttos;
542         int rval, i;
543
544         /* Find the top-level interface type. */
545         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
546             desc->ifmt_string != NULL; desc++, ttos++)
547                 if (type == desc->ifmt_word)
548                         break;
549         if (desc->ifmt_string == NULL)
550                 errx(1, "unknown media type 0x%x", type);
551
552         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
553                 rval = lookup_media_word(ttos->subtypes[i].desc, val);
554                 if (rval != -1)
555                         return (rval);
556         }
557         errx(1, "unknown media subtype: %s", val);
558         /*NOTREACHED*/
559 }
560
561 int
562 get_media_mode(int type, const char *val)
563 {
564         struct ifmedia_description *desc;
565         struct ifmedia_type_to_subtype *ttos;
566         int rval, i;
567
568         /* Find the top-level interface type. */
569         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
570             desc->ifmt_string != NULL; desc++, ttos++)
571                 if (type == desc->ifmt_word)
572                         break;
573         if (desc->ifmt_string == NULL)
574                 errx(1, "unknown media mode 0x%x", type);
575
576         for (i = 0; ttos->modes[i].desc != NULL; i++) {
577                 rval = lookup_media_word(ttos->modes[i].desc, val);
578                 if (rval != -1)
579                         return (rval);
580         }
581         return -1;
582 }
583
584 int
585 get_media_options(int type, const char *val)
586 {
587         struct ifmedia_description *desc;
588         struct ifmedia_type_to_subtype *ttos;
589         char *optlist, *optptr;
590         int option = 0, i, rval = 0;
591
592         /* We muck with the string, so copy it. */
593         optlist = strdup(val);
594         if (optlist == NULL)
595                 err(1, "strdup");
596
597         /* Find the top-level interface type. */
598         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
599             desc->ifmt_string != NULL; desc++, ttos++)
600                 if (type == desc->ifmt_word)
601                         break;
602         if (desc->ifmt_string == NULL)
603                 errx(1, "unknown media type 0x%x", type);
604
605         /*
606          * Look up the options in the user-provided comma-separated
607          * list.
608          */
609         optptr = optlist;
610         for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
611                 for (i = 0; ttos->options[i].desc != NULL; i++) {
612                         option = lookup_media_word(ttos->options[i].desc, optptr);
613                         if (option != -1)
614                                 break;
615                 }
616                 if (option == 0)
617                         errx(1, "unknown option: %s", optptr);
618                 rval |= option;
619         }
620
621         free(optlist);
622         return (rval);
623 }
624
625 int
626 lookup_media_word(struct ifmedia_description *desc, const char *val)
627 {
628
629         for (; desc->ifmt_string != NULL; desc++)
630                 if (strcasecmp(desc->ifmt_string, val) == 0)
631                         return (desc->ifmt_word);
632
633         return (-1);
634 }
635
636 static struct ifmedia_description *get_toptype_desc(int ifmw)
637 {
638         struct ifmedia_description *desc;
639
640         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
641                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
642                         break;
643
644         return desc;
645 }
646
647 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
648 {
649         struct ifmedia_description *desc;
650         struct ifmedia_type_to_subtype *ttos;
651
652         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
653             desc->ifmt_string != NULL; desc++, ttos++)
654                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
655                         break;
656
657         return ttos;
658 }
659
660 static struct ifmedia_description *get_subtype_desc(int ifmw, 
661     struct ifmedia_type_to_subtype *ttos)
662 {
663         int i;
664         struct ifmedia_description *desc;
665
666         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
667                 if (ttos->subtypes[i].alias)
668                         continue;
669                 for (desc = ttos->subtypes[i].desc;
670                     desc->ifmt_string != NULL; desc++) {
671                         if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
672                                 return desc;
673                 }
674         }
675
676         return NULL;
677 }
678
679 static struct ifmedia_description *get_mode_desc(int ifmw, 
680     struct ifmedia_type_to_subtype *ttos)
681 {
682         int i;
683         struct ifmedia_description *desc;
684
685         for (i = 0; ttos->modes[i].desc != NULL; i++) {
686                 if (ttos->modes[i].alias)
687                         continue;
688                 for (desc = ttos->modes[i].desc;
689                     desc->ifmt_string != NULL; desc++) {
690                         if (IFM_MODE(ifmw) == desc->ifmt_word)
691                                 return desc;
692                 }
693         }
694
695         return NULL;
696 }
697
698 void
699 print_media_word(int ifmw, int print_toptype)
700 {
701         struct ifmedia_description *desc;
702         struct ifmedia_type_to_subtype *ttos;
703         int seen_option = 0, i;
704
705         /* Find the top-level interface type. */
706         desc = get_toptype_desc(ifmw);
707         ttos = get_toptype_ttos(ifmw);
708         if (desc->ifmt_string == NULL) {
709                 printf("<unknown type>");
710                 return;
711         } else if (print_toptype) {
712                 printf("%s", desc->ifmt_string);
713         }
714
715         /*
716          * Don't print the top-level type; it's not like we can
717          * change it, or anything.
718          */
719
720         /* Find subtype. */
721         desc = get_subtype_desc(ifmw, ttos);
722         if (desc == NULL) {
723                 printf("<unknown subtype>");
724                 return;
725         }
726
727         if (print_toptype)
728                 putchar(' ');
729
730         printf("%s", desc->ifmt_string);
731
732         if (print_toptype) {
733                 desc = get_mode_desc(ifmw, ttos);
734                 if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
735                         printf(" mode %s", desc->ifmt_string);
736         }
737
738         /* Find options. */
739         for (i = 0; ttos->options[i].desc != NULL; i++) {
740                 if (ttos->options[i].alias)
741                         continue;
742                 for (desc = ttos->options[i].desc;
743                     desc->ifmt_string != NULL; desc++) {
744                         if (ifmw & desc->ifmt_word) {
745                                 if (seen_option == 0)
746                                         printf(" <");
747                                 printf("%s%s", seen_option++ ? "," : "",
748                                     desc->ifmt_string);
749                         }
750                 }
751         }
752         printf("%s", seen_option ? ">" : "");
753
754         if (print_toptype && IFM_INST(ifmw) != 0)
755                 printf(" instance %d", IFM_INST(ifmw));
756 }
757
758 void
759 print_media_word_ifconfig(int ifmw)
760 {
761         struct ifmedia_description *desc;
762         struct ifmedia_type_to_subtype *ttos;
763         int seen_option = 0, i;
764
765         /* Find the top-level interface type. */
766         desc = get_toptype_desc(ifmw);
767         ttos = get_toptype_ttos(ifmw);
768         if (desc->ifmt_string == NULL) {
769                 printf("<unknown type>");
770                 return;
771         }
772
773         /*
774          * Don't print the top-level type; it's not like we can
775          * change it, or anything.
776          */
777
778         /* Find subtype. */
779         desc = get_subtype_desc(ifmw, ttos);
780         if (desc == NULL) {
781                 printf("<unknown subtype>");
782                 return;
783         }
784
785         printf("media %s", desc->ifmt_string);
786
787         desc = get_mode_desc(ifmw, ttos);
788         if (desc != NULL)
789                 printf(" mode %s", desc->ifmt_string);
790
791         /* Find options. */
792         for (i = 0; ttos->options[i].desc != NULL; i++) {
793                 if (ttos->options[i].alias)
794                         continue;
795                 for (desc = ttos->options[i].desc;
796                     desc->ifmt_string != NULL; desc++) {
797                         if (ifmw & desc->ifmt_word) {
798                                 if (seen_option == 0)
799                                         printf(" mediaopt ");
800                                 printf("%s%s", seen_option++ ? "," : "",
801                                     desc->ifmt_string);
802                         }
803                 }
804         }
805
806         if (IFM_INST(ifmw) != 0)
807                 printf(" instance %d", IFM_INST(ifmw));
808 }
809
810 /**********************************************************************
811  * ...until here.
812  **********************************************************************/