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