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