carp: add carp_group_demote_adj()
[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.13 2007/08/27 16:15:41 hasso 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_ATM:
157                         if (ifmr.ifm_status & IFM_ACTIVE)
158                                 printf("active");
159                         else
160                                 printf("no carrier");
161                         break;
162
163                 case IFM_IEEE80211:
164                         /* XXX: Different value for adhoc? */
165                         if (ifmr.ifm_status & IFM_ACTIVE)
166                                 printf("associated");
167                         else
168                                 printf("no carrier");
169                         break;
170                 case IFM_CARP:
171                         if (ifmr.ifm_status & IFM_ACTIVE)
172                                 printf("master");
173                         else
174                                 printf("backup");
175                         break;
176                 }
177                 putchar('\n');
178         }
179
180         if (ifmr.ifm_count > 0 && supmedia) {
181                 printf("\tsupported media:\n");
182                 for (i = 0; i < ifmr.ifm_count; i++) {
183                         printf("\t\t");
184                         print_media_word_ifconfig(media_list[i]);
185                         putchar('\n');
186                 }
187         }
188
189         free(media_list);
190 }
191
192 struct ifmediareq *
193 ifmedia_getstate(int s)
194 {
195         static struct ifmediareq *ifmr = NULL;
196         int *mwords;
197
198         if (ifmr == NULL) {
199                 ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
200                 if (ifmr == NULL)
201                         err(1, "malloc");
202
203                 (void) memset(ifmr, 0, sizeof(struct ifmediareq));
204                 (void) strncpy(ifmr->ifm_name, name,
205                     sizeof(ifmr->ifm_name));
206
207                 ifmr->ifm_count = 0;
208                 ifmr->ifm_ulist = NULL;
209
210                 /*
211                  * We must go through the motions of reading all
212                  * supported media because we need to know both
213                  * the current media type and the top-level type.
214                  */
215
216                 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
217                         err(1, "SIOCGIFMEDIA");
218                 }
219
220                 if (ifmr->ifm_count == 0)
221                         errx(1, "%s: no media types?", name);
222
223                 mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
224                 if (mwords == NULL)
225                         err(1, "malloc");
226   
227                 ifmr->ifm_ulist = mwords;
228                 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
229                         err(1, "SIOCGIFMEDIA");
230         }
231
232         return ifmr;
233 }
234
235 static void
236 setifmediacallback(int s, void *arg)
237 {
238         struct ifmediareq *ifmr = (struct ifmediareq *)arg;
239         static int did_it = 0;
240
241         if (!did_it) {
242                 ifr.ifr_media = ifmr->ifm_current;
243                 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
244                         err(1, "SIOCSIFMEDIA (media)");
245                 free(ifmr->ifm_ulist);
246                 free(ifmr);
247                 did_it = 1;
248         }
249 }
250
251 static void
252 setmedia(const char *val, int d, int s, const struct afswtch *afp)
253 {
254         struct ifmediareq *ifmr;
255         int subtype;
256         
257
258         ifmr = ifmedia_getstate(s);
259
260         /*
261          * We are primarily concerned with the top-level type.
262          * However, "current" may be only IFM_NONE, so we just look
263          * for the top-level type in the first "supported type"
264          * entry.
265          *
266          * (I'm assuming that all supported media types for a given
267          * interface will be the same top-level type..)
268          */
269         subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
270
271         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
272         ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
273             IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
274
275         if ((ifr.ifr_media & IFM_TMASK) == 0) {
276                 ifr.ifr_media &= ~IFM_GMASK;
277         }
278
279         ifmr->ifm_current = ifr.ifr_media;
280         callback_register(setifmediacallback, (void *)ifmr);
281 }
282
283 static void
284 setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
285 {
286
287         domediaopt(val, 0, s);
288 }
289
290 static void
291 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
292 {
293
294         domediaopt(val, 1, s);
295 }
296
297 static void
298 domediaopt(const char *val, int clear, int s)
299 {
300         struct ifmediareq *ifmr;
301         int options;
302
303         ifmr = ifmedia_getstate(s);
304
305         options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
306
307         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
308         ifr.ifr_media = ifmr->ifm_current;
309         if (clear)
310                 ifr.ifr_media &= ~options;
311         else
312                 ifr.ifr_media |= options;
313
314         ifmr->ifm_current = ifr.ifr_media;
315         callback_register(setifmediacallback, (void *)ifmr);
316 }
317
318
319 static void
320 setmediamode(const char *val, int d, int s, const struct afswtch *afp)
321 {
322         struct ifmediareq *ifmr;
323         int mode;
324
325         ifmr = ifmedia_getstate(s);
326
327         mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
328
329         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
330         ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
331
332         ifmr->ifm_current = ifr.ifr_media;
333         callback_register(setifmediacallback, (void *)ifmr);
334 }
335
336 /**********************************************************************
337  * A good chunk of this is duplicated from sys/net/ifmedia.c
338  **********************************************************************/
339
340 static struct ifmedia_description ifm_type_descriptions[] =
341     IFM_TYPE_DESCRIPTIONS;
342
343 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
344     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
345
346 static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
347     IFM_SUBTYPE_ETHERNET_ALIASES;
348
349 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
350     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
351
352 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
353     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
354
355 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
356     IFM_SUBTYPE_IEEE80211_ALIASES;
357
358 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
359     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
360
361 struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
362     IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
363
364 struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
365     IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
366
367 static struct ifmedia_description ifm_subtype_atm_descriptions[] =
368     IFM_SUBTYPE_ATM_DESCRIPTIONS;
369
370 static struct ifmedia_description ifm_subtype_atm_aliases[] =
371     IFM_SUBTYPE_ATM_ALIASES;
372
373 static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
374     IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
375
376 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
377     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
378
379 static struct ifmedia_description ifm_subtype_shared_aliases[] =
380     IFM_SUBTYPE_SHARED_ALIASES;
381
382 static struct ifmedia_description ifm_shared_option_descriptions[] =
383     IFM_SHARED_OPTION_DESCRIPTIONS;
384
385 struct ifmedia_type_to_subtype {
386         struct {
387                 struct ifmedia_description *desc;
388                 int alias;
389         } subtypes[5];
390         struct {
391                 struct ifmedia_description *desc;
392                 int alias;
393         } options[3];
394         struct {
395                 struct ifmedia_description *desc;
396                 int alias;
397         } modes[3];
398 };
399
400 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
401 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
402         {
403                 {
404                         { &ifm_subtype_shared_descriptions[0], 0 },
405                         { &ifm_subtype_shared_aliases[0], 1 },
406                         { &ifm_subtype_ethernet_descriptions[0], 0 },
407                         { &ifm_subtype_ethernet_aliases[0], 1 },
408                         { NULL, 0 },
409                 },
410                 {
411                         { &ifm_shared_option_descriptions[0], 0 },
412                         { &ifm_subtype_ethernet_option_descriptions[0], 0 },
413                         { NULL, 0 },
414                 },
415                 {
416                         { NULL, 0 },
417                 },
418         },
419         {
420                 {
421                         { &ifm_subtype_shared_descriptions[0], 0 },
422                         { &ifm_subtype_shared_aliases[0], 1 },
423                         { &ifm_subtype_ieee80211_descriptions[0], 0 },
424                         { &ifm_subtype_ieee80211_aliases[0], 1 },
425                         { NULL, 0 },
426                 },
427                 {
428                         { &ifm_shared_option_descriptions[0], 0 },
429                         { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
430                         { NULL, 0 },
431                 },
432                 {
433                         { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
434                         { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
435                         { NULL, 0 },
436                 },
437         },
438         {
439                 {
440                         { &ifm_subtype_shared_descriptions[0], 0 },
441                         { &ifm_subtype_shared_aliases[0], 1 },
442                         { &ifm_subtype_atm_descriptions[0], 0 },
443                         { &ifm_subtype_atm_aliases[0], 1 },
444                         { NULL, 0 },
445                 },
446                 {
447                         { &ifm_shared_option_descriptions[0], 0 },
448                         { &ifm_subtype_atm_option_descriptions[0], 0 },
449                         { NULL, 0 },
450                 },
451                 {
452                         { NULL, 0 },
453                 },
454         },
455 };
456
457 static int
458 get_media_subtype(int type, const char *val)
459 {
460         struct ifmedia_description *desc;
461         struct ifmedia_type_to_subtype *ttos;
462         int rval, i;
463
464         /* Find the top-level interface type. */
465         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
466             desc->ifmt_string != NULL; desc++, ttos++)
467                 if (type == desc->ifmt_word)
468                         break;
469         if (desc->ifmt_string == NULL)
470                 errx(1, "unknown media type 0x%x", type);
471
472         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
473                 rval = lookup_media_word(ttos->subtypes[i].desc, val);
474                 if (rval != -1)
475                         return (rval);
476         }
477         errx(1, "unknown media subtype: %s", val);
478         /*NOTREACHED*/
479 }
480
481 static int
482 get_media_mode(int type, const char *val)
483 {
484         struct ifmedia_description *desc;
485         struct ifmedia_type_to_subtype *ttos;
486         int rval, i;
487
488         /* Find the top-level interface type. */
489         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
490             desc->ifmt_string != NULL; desc++, ttos++)
491                 if (type == desc->ifmt_word)
492                         break;
493         if (desc->ifmt_string == NULL)
494                 errx(1, "unknown media mode 0x%x", type);
495
496         for (i = 0; ttos->modes[i].desc != NULL; i++) {
497                 rval = lookup_media_word(ttos->modes[i].desc, val);
498                 if (rval != -1)
499                         return (rval);
500         }
501         return -1;
502 }
503
504 static int
505 get_media_options(int type, const char *val)
506 {
507         struct ifmedia_description *desc;
508         struct ifmedia_type_to_subtype *ttos;
509         char *optlist, *optptr;
510         int option = 0, i, rval = 0;
511
512         /* We muck with the string, so copy it. */
513         optlist = strdup(val);
514         if (optlist == NULL)
515                 err(1, "strdup");
516
517         /* Find the top-level interface type. */
518         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
519             desc->ifmt_string != NULL; desc++, ttos++)
520                 if (type == desc->ifmt_word)
521                         break;
522         if (desc->ifmt_string == NULL)
523                 errx(1, "unknown media type 0x%x", type);
524
525         /*
526          * Look up the options in the user-provided comma-separated
527          * list.
528          */
529         optptr = optlist;
530         for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
531                 for (i = 0; ttos->options[i].desc != NULL; i++) {
532                         option = lookup_media_word(ttos->options[i].desc, optptr);
533                         if (option != -1)
534                                 break;
535                 }
536                 if (option == 0)
537                         errx(1, "unknown option: %s", optptr);
538                 rval |= option;
539         }
540
541         free(optlist);
542         return (rval);
543 }
544
545 static int
546 lookup_media_word(struct ifmedia_description *desc, const char *val)
547 {
548
549         for (; desc->ifmt_string != NULL; desc++)
550                 if (strcasecmp(desc->ifmt_string, val) == 0)
551                         return (desc->ifmt_word);
552
553         return (-1);
554 }
555
556 static struct ifmedia_description *get_toptype_desc(int ifmw)
557 {
558         struct ifmedia_description *desc;
559
560         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
561                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
562                         break;
563
564         return desc;
565 }
566
567 static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
568 {
569         struct ifmedia_description *desc;
570         struct ifmedia_type_to_subtype *ttos;
571
572         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
573             desc->ifmt_string != NULL; desc++, ttos++)
574                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
575                         break;
576
577         return ttos;
578 }
579
580 static struct ifmedia_description *get_subtype_desc(int ifmw, 
581     struct ifmedia_type_to_subtype *ttos)
582 {
583         int i;
584         struct ifmedia_description *desc;
585
586         for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
587                 if (ttos->subtypes[i].alias)
588                         continue;
589                 for (desc = ttos->subtypes[i].desc;
590                     desc->ifmt_string != NULL; desc++) {
591                         if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
592                                 return desc;
593                 }
594         }
595
596         return NULL;
597 }
598
599 static struct ifmedia_description *get_mode_desc(int ifmw, 
600     struct ifmedia_type_to_subtype *ttos)
601 {
602         int i;
603         struct ifmedia_description *desc;
604
605         for (i = 0; ttos->modes[i].desc != NULL; i++) {
606                 if (ttos->modes[i].alias)
607                         continue;
608                 for (desc = ttos->modes[i].desc;
609                     desc->ifmt_string != NULL; desc++) {
610                         if (IFM_MODE(ifmw) == desc->ifmt_word)
611                                 return desc;
612                 }
613         }
614
615         return NULL;
616 }
617
618 static void
619 print_media_word(int ifmw, int print_toptype)
620 {
621         struct ifmedia_description *desc;
622         struct ifmedia_type_to_subtype *ttos;
623         int seen_option = 0, i;
624
625         /* Find the top-level interface type. */
626         desc = get_toptype_desc(ifmw);
627         ttos = get_toptype_ttos(ifmw);
628         if (desc->ifmt_string == NULL) {
629                 printf("<unknown type>");
630                 return;
631         } else if (print_toptype) {
632                 printf("%s", desc->ifmt_string);
633         }
634
635         /*
636          * Don't print the top-level type; it's not like we can
637          * change it, or anything.
638          */
639
640         /* Find subtype. */
641         desc = get_subtype_desc(ifmw, ttos);
642         if (desc != NULL)
643                 goto got_subtype;
644
645         /* Falling to here means unknown subtype. */
646         printf("<unknown subtype>");
647         return;
648
649  got_subtype:
650         if (print_toptype)
651                 putchar(' ');
652
653         printf("%s", desc->ifmt_string);
654
655         if (print_toptype) {
656                 desc = get_mode_desc(ifmw, ttos);
657                 if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
658                         printf(" mode %s", desc->ifmt_string);
659         }
660
661         /* Find options. */
662         for (i = 0; ttos->options[i].desc != NULL; i++) {
663                 if (ttos->options[i].alias)
664                         continue;
665                 for (desc = ttos->options[i].desc;
666                     desc->ifmt_string != NULL; desc++) {
667                         if (ifmw & desc->ifmt_word) {
668                                 if (seen_option == 0)
669                                         printf(" <");
670                                 printf("%s%s", seen_option++ ? "," : "",
671                                     desc->ifmt_string);
672                         }
673                 }
674         }
675         printf("%s", seen_option ? ">" : "");
676 }
677
678 static void
679 print_media_word_ifconfig(int ifmw)
680 {
681         struct ifmedia_description *desc;
682         struct ifmedia_type_to_subtype *ttos;
683         int i;
684
685         /* Find the top-level interface type. */
686         desc = get_toptype_desc(ifmw);
687         ttos = get_toptype_ttos(ifmw);
688         if (desc->ifmt_string == NULL) {
689                 printf("<unknown type>");
690                 return;
691         }
692
693         /*
694          * Don't print the top-level type; it's not like we can
695          * change it, or anything.
696          */
697
698         /* Find subtype. */
699         desc = get_subtype_desc(ifmw, ttos);
700         if (desc != NULL)
701                 goto got_subtype;
702
703         /* Falling to here means unknown subtype. */
704         printf("<unknown subtype>");
705         return;
706
707  got_subtype:
708         printf("media %s", desc->ifmt_string);
709
710         desc = get_mode_desc(ifmw, ttos);
711         if (desc != NULL)
712                 printf(" mode %s", desc->ifmt_string);
713
714         /* Find options. */
715         for (i = 0; ttos->options[i].desc != NULL; i++) {
716                 if (ttos->options[i].alias)
717                         continue;
718                 for (desc = ttos->options[i].desc;
719                     desc->ifmt_string != NULL; desc++) {
720                         if (ifmw & desc->ifmt_word) {
721                                 printf(" mediaopt %s", desc->ifmt_string);
722                         }
723                 }
724         }
725 }
726
727 /**********************************************************************
728  * ...until here.
729  **********************************************************************/
730
731 static struct cmd media_cmds[] = {
732         DEF_CMD_ARG("media",    setmedia),
733         DEF_CMD_ARG("mode",     setmediamode),
734         DEF_CMD_ARG("mediaopt", setmediaopt),
735         DEF_CMD_ARG("-mediaopt",unsetmediaopt),
736 };
737 static struct afswtch af_media = {
738         .af_name        = "af_media",
739         .af_af          = AF_UNSPEC,
740         .af_other_status = media_status,
741 };
742
743 static __constructor void
744 ifmedia_ctor(void)
745 {
746 #define N(a)    (sizeof(a) / sizeof(a[0]))
747         int i;
748
749         for (i = 0; i < N(media_cmds);  i++)
750                 cmd_register(&media_cmds[i]);
751         af_register(&af_media);
752 #undef N
753 }