ifmedia.c revision 178354
1194196Sjilles/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
2194196Sjilles/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 178354 2008-04-20 20:35:46Z sam $ */
3194196Sjilles
4194196Sjilles/*
5194196Sjilles * Copyright (c) 1997 Jason R. Thorpe.
6194196Sjilles * All rights reserved.
7213738Sobrien *
8194196Sjilles * Redistribution and use in source and binary forms, with or without
9194196Sjilles * modification, are permitted provided that the following conditions
10194196Sjilles * are met:
11213738Sobrien * 1. Redistributions of source code must retain the above copyright
12194196Sjilles *    notice, this list of conditions and the following disclaimer.
13194196Sjilles * 2. Redistributions in binary form must reproduce the above copyright
14194196Sjilles *    notice, this list of conditions and the following disclaimer in the
15194196Sjilles *    documentation and/or other materials provided with the distribution.
16194196Sjilles * 3. All advertising materials mentioning features or use of this software
17194196Sjilles *    must display the following acknowledgement:
18194196Sjilles *      This product includes software developed for the NetBSD Project
19194196Sjilles *	by Jason R. Thorpe.
20194196Sjilles * 4. The name of the author may not be used to endorse or promote products
21194196Sjilles *    derived from this software without specific prior written permission.
22194196Sjilles *
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
105#define	IFM_OPMODE(x) \
106	((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
107	 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR))
108#define	IFM_IEEE80211_STA	0
109
110static void
111media_status(int s)
112{
113	struct ifmediareq ifmr;
114	int *media_list, i;
115
116	(void) memset(&ifmr, 0, sizeof(ifmr));
117	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
118
119	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
120		/*
121		 * Interface doesn't support SIOC{G,S}IFMEDIA.
122		 */
123		return;
124	}
125
126	if (ifmr.ifm_count == 0) {
127		warnx("%s: no media types?", name);
128		return;
129	}
130
131	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
132	if (media_list == NULL)
133		err(1, "malloc");
134	ifmr.ifm_ulist = media_list;
135
136	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
137		err(1, "SIOCGIFMEDIA");
138
139	printf("\tmedia: ");
140	print_media_word(ifmr.ifm_current, 1);
141	if (ifmr.ifm_active != ifmr.ifm_current) {
142		putchar(' ');
143		putchar('(');
144		print_media_word(ifmr.ifm_active, 0);
145		putchar(')');
146	}
147
148	putchar('\n');
149
150	if (ifmr.ifm_status & IFM_AVALID) {
151		printf("\tstatus: ");
152		switch (IFM_TYPE(ifmr.ifm_active)) {
153		case IFM_ETHER:
154		case IFM_ATM:
155			if (ifmr.ifm_status & IFM_ACTIVE)
156				printf("active");
157			else
158				printf("no carrier");
159			break;
160
161		case IFM_FDDI:
162		case IFM_TOKEN:
163			if (ifmr.ifm_status & IFM_ACTIVE)
164				printf("inserted");
165			else
166				printf("no ring");
167			break;
168
169		case IFM_IEEE80211:
170			if (ifmr.ifm_status & IFM_ACTIVE) {
171				/* NB: only sta mode associates */
172				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
173					printf("associated");
174				else
175					printf("running");
176			} else
177				printf("no carrier");
178			break;
179		}
180		putchar('\n');
181	}
182
183	if (ifmr.ifm_count > 0 && supmedia) {
184		printf("\tsupported media:\n");
185		for (i = 0; i < ifmr.ifm_count; i++) {
186			printf("\t\t");
187			print_media_word_ifconfig(media_list[i]);
188			putchar('\n');
189		}
190	}
191
192	free(media_list);
193}
194
195struct ifmediareq *
196ifmedia_getstate(int s)
197{
198	static struct ifmediareq *ifmr = NULL;
199	int *mwords;
200
201	if (ifmr == NULL) {
202		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
203		if (ifmr == NULL)
204			err(1, "malloc");
205
206		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
207		(void) strncpy(ifmr->ifm_name, name,
208		    sizeof(ifmr->ifm_name));
209
210		ifmr->ifm_count = 0;
211		ifmr->ifm_ulist = NULL;
212
213		/*
214		 * We must go through the motions of reading all
215		 * supported media because we need to know both
216		 * the current media type and the top-level type.
217		 */
218
219		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
220			err(1, "SIOCGIFMEDIA");
221		}
222
223		if (ifmr->ifm_count == 0)
224			errx(1, "%s: no media types?", name);
225
226		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
227		if (mwords == NULL)
228			err(1, "malloc");
229
230		ifmr->ifm_ulist = mwords;
231		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
232			err(1, "SIOCGIFMEDIA");
233	}
234
235	return ifmr;
236}
237
238static void
239setifmediacallback(int s, void *arg)
240{
241	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
242	static int did_it = 0;
243
244	if (!did_it) {
245		ifr.ifr_media = ifmr->ifm_current;
246		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
247			err(1, "SIOCSIFMEDIA (media)");
248		free(ifmr->ifm_ulist);
249		free(ifmr);
250		did_it = 1;
251	}
252}
253
254static void
255setmedia(const char *val, int d, int s, const struct afswtch *afp)
256{
257	struct ifmediareq *ifmr;
258	int subtype;
259
260	ifmr = ifmedia_getstate(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
285static void
286setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
287{
288
289	domediaopt(val, 0, s);
290}
291
292static void
293unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
294{
295
296	domediaopt(val, 1, s);
297}
298
299static void
300domediaopt(const char *val, int clear, int s)
301{
302	struct ifmediareq *ifmr;
303	int options;
304
305	ifmr = ifmedia_getstate(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		if (options & IFM_HDX) {
315			ifr.ifr_media &= ~IFM_FDX;
316			options &= ~IFM_HDX;
317		}
318		ifr.ifr_media |= options;
319	}
320	ifmr->ifm_current = ifr.ifr_media;
321	callback_register(setifmediacallback, (void *)ifmr);
322}
323
324static void
325setmediainst(const char *val, int d, int s, const struct afswtch *afp)
326{
327	struct ifmediareq *ifmr;
328	int inst;
329
330	ifmr = ifmedia_getstate(s);
331
332	inst = atoi(val);
333	if (inst < 0 || inst > IFM_INST_MAX)
334		errx(1, "invalid media instance: %s", val);
335
336	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
337	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
338
339	ifmr->ifm_current = ifr.ifr_media;
340	callback_register(setifmediacallback, (void *)ifmr);
341}
342
343static void
344setmediamode(const char *val, int d, int s, const struct afswtch *afp)
345{
346	struct ifmediareq *ifmr;
347	int mode;
348
349	ifmr = ifmedia_getstate(s);
350
351	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
352
353	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
354	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
355
356	ifmr->ifm_current = ifr.ifr_media;
357	callback_register(setifmediacallback, (void *)ifmr);
358}
359
360/**********************************************************************
361 * A good chunk of this is duplicated from sys/net/ifmedia.c
362 **********************************************************************/
363
364static struct ifmedia_description ifm_type_descriptions[] =
365    IFM_TYPE_DESCRIPTIONS;
366
367static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
368    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
369
370static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
371    IFM_SUBTYPE_ETHERNET_ALIASES;
372
373static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
374    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
375
376static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
377    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
378
379static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
380    IFM_SUBTYPE_TOKENRING_ALIASES;
381
382static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
383    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
384
385static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
386    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
387
388static struct ifmedia_description ifm_subtype_fddi_aliases[] =
389    IFM_SUBTYPE_FDDI_ALIASES;
390
391static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
392    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
393
394static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
395    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
396
397static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
398    IFM_SUBTYPE_IEEE80211_ALIASES;
399
400static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
401    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
402
403struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
404    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
405
406struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
407    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
408
409static struct ifmedia_description ifm_subtype_atm_descriptions[] =
410    IFM_SUBTYPE_ATM_DESCRIPTIONS;
411
412static struct ifmedia_description ifm_subtype_atm_aliases[] =
413    IFM_SUBTYPE_ATM_ALIASES;
414
415static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
416    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
417
418static struct ifmedia_description ifm_subtype_shared_descriptions[] =
419    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
420
421static struct ifmedia_description ifm_subtype_shared_aliases[] =
422    IFM_SUBTYPE_SHARED_ALIASES;
423
424static struct ifmedia_description ifm_shared_option_descriptions[] =
425    IFM_SHARED_OPTION_DESCRIPTIONS;
426
427struct ifmedia_type_to_subtype {
428	struct {
429		struct ifmedia_description *desc;
430		int alias;
431	} subtypes[5];
432	struct {
433		struct ifmedia_description *desc;
434		int alias;
435	} options[3];
436	struct {
437		struct ifmedia_description *desc;
438		int alias;
439	} modes[3];
440};
441
442/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
443static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
444	{
445		{
446			{ &ifm_subtype_shared_descriptions[0], 0 },
447			{ &ifm_subtype_shared_aliases[0], 1 },
448			{ &ifm_subtype_ethernet_descriptions[0], 0 },
449			{ &ifm_subtype_ethernet_aliases[0], 1 },
450			{ NULL, 0 },
451		},
452		{
453			{ &ifm_shared_option_descriptions[0], 0 },
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_subtype_tokenring_option_descriptions[0], 0 },
472			{ NULL, 0 },
473		},
474		{
475			{ NULL, 0 },
476		},
477	},
478	{
479		{
480			{ &ifm_subtype_shared_descriptions[0], 0 },
481			{ &ifm_subtype_shared_aliases[0], 1 },
482			{ &ifm_subtype_fddi_descriptions[0], 0 },
483			{ &ifm_subtype_fddi_aliases[0], 1 },
484			{ NULL, 0 },
485		},
486		{
487			{ &ifm_shared_option_descriptions[0], 0 },
488			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
489			{ NULL, 0 },
490		},
491		{
492			{ NULL, 0 },
493		},
494	},
495	{
496		{
497			{ &ifm_subtype_shared_descriptions[0], 0 },
498			{ &ifm_subtype_shared_aliases[0], 1 },
499			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
500			{ &ifm_subtype_ieee80211_aliases[0], 1 },
501			{ NULL, 0 },
502		},
503		{
504			{ &ifm_shared_option_descriptions[0], 0 },
505			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
506			{ NULL, 0 },
507		},
508		{
509			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
510			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
511			{ NULL, 0 },
512		},
513	},
514	{
515		{
516			{ &ifm_subtype_shared_descriptions[0], 0 },
517			{ &ifm_subtype_shared_aliases[0], 1 },
518			{ &ifm_subtype_atm_descriptions[0], 0 },
519			{ &ifm_subtype_atm_aliases[0], 1 },
520			{ NULL, 0 },
521		},
522		{
523			{ &ifm_shared_option_descriptions[0], 0 },
524			{ &ifm_subtype_atm_option_descriptions[0], 0 },
525			{ NULL, 0 },
526		},
527		{
528			{ NULL, 0 },
529		},
530	},
531};
532
533static int
534get_media_subtype(int type, const char *val)
535{
536	struct ifmedia_description *desc;
537	struct ifmedia_type_to_subtype *ttos;
538	int rval, i;
539
540	/* Find the top-level interface type. */
541	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
542	    desc->ifmt_string != NULL; desc++, ttos++)
543		if (type == desc->ifmt_word)
544			break;
545	if (desc->ifmt_string == NULL)
546		errx(1, "unknown media type 0x%x", type);
547
548	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
549		rval = lookup_media_word(ttos->subtypes[i].desc, val);
550		if (rval != -1)
551			return (rval);
552	}
553	errx(1, "unknown media subtype: %s", val);
554	/*NOTREACHED*/
555}
556
557static int
558get_media_mode(int type, const char *val)
559{
560	struct ifmedia_description *desc;
561	struct ifmedia_type_to_subtype *ttos;
562	int rval, i;
563
564	/* Find the top-level interface type. */
565	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
566	    desc->ifmt_string != NULL; desc++, ttos++)
567		if (type == desc->ifmt_word)
568			break;
569	if (desc->ifmt_string == NULL)
570		errx(1, "unknown media mode 0x%x", type);
571
572	for (i = 0; ttos->modes[i].desc != NULL; i++) {
573		rval = lookup_media_word(ttos->modes[i].desc, val);
574		if (rval != -1)
575			return (rval);
576	}
577	return -1;
578}
579
580static int
581get_media_options(int type, const char *val)
582{
583	struct ifmedia_description *desc;
584	struct ifmedia_type_to_subtype *ttos;
585	char *optlist, *optptr;
586	int option = 0, i, rval = 0;
587
588	/* We muck with the string, so copy it. */
589	optlist = strdup(val);
590	if (optlist == NULL)
591		err(1, "strdup");
592
593	/* Find the top-level interface type. */
594	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
595	    desc->ifmt_string != NULL; desc++, ttos++)
596		if (type == desc->ifmt_word)
597			break;
598	if (desc->ifmt_string == NULL)
599		errx(1, "unknown media type 0x%x", type);
600
601	/*
602	 * Look up the options in the user-provided comma-separated
603	 * list.
604	 */
605	optptr = optlist;
606	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
607		for (i = 0; ttos->options[i].desc != NULL; i++) {
608			option = lookup_media_word(ttos->options[i].desc, optptr);
609			if (option != -1)
610				break;
611		}
612		if (option == 0)
613			errx(1, "unknown option: %s", optptr);
614		rval |= option;
615	}
616
617	free(optlist);
618	return (rval);
619}
620
621static int
622lookup_media_word(struct ifmedia_description *desc, const char *val)
623{
624
625	for (; desc->ifmt_string != NULL; desc++)
626		if (strcasecmp(desc->ifmt_string, val) == 0)
627			return (desc->ifmt_word);
628
629	return (-1);
630}
631
632static struct ifmedia_description *get_toptype_desc(int ifmw)
633{
634	struct ifmedia_description *desc;
635
636	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
637		if (IFM_TYPE(ifmw) == desc->ifmt_word)
638			break;
639
640	return desc;
641}
642
643static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
644{
645	struct ifmedia_description *desc;
646	struct ifmedia_type_to_subtype *ttos;
647
648	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
649	    desc->ifmt_string != NULL; desc++, ttos++)
650		if (IFM_TYPE(ifmw) == desc->ifmt_word)
651			break;
652
653	return ttos;
654}
655
656static struct ifmedia_description *get_subtype_desc(int ifmw,
657    struct ifmedia_type_to_subtype *ttos)
658{
659	int i;
660	struct ifmedia_description *desc;
661
662	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
663		if (ttos->subtypes[i].alias)
664			continue;
665		for (desc = ttos->subtypes[i].desc;
666		    desc->ifmt_string != NULL; desc++) {
667			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
668				return desc;
669		}
670	}
671
672	return NULL;
673}
674
675static struct ifmedia_description *get_mode_desc(int ifmw,
676    struct ifmedia_type_to_subtype *ttos)
677{
678	int i;
679	struct ifmedia_description *desc;
680
681	for (i = 0; ttos->modes[i].desc != NULL; i++) {
682		if (ttos->modes[i].alias)
683			continue;
684		for (desc = ttos->modes[i].desc;
685		    desc->ifmt_string != NULL; desc++) {
686			if (IFM_MODE(ifmw) == desc->ifmt_word)
687				return desc;
688		}
689	}
690
691	return NULL;
692}
693
694static void
695print_media_word(int ifmw, int print_toptype)
696{
697	struct ifmedia_description *desc;
698	struct ifmedia_type_to_subtype *ttos;
699	int seen_option = 0, i;
700
701	/* Find the top-level interface type. */
702	desc = get_toptype_desc(ifmw);
703	ttos = get_toptype_ttos(ifmw);
704	if (desc->ifmt_string == NULL) {
705		printf("<unknown type>");
706		return;
707	} else if (print_toptype) {
708		printf("%s", desc->ifmt_string);
709	}
710
711	/*
712	 * Don't print the top-level type; it's not like we can
713	 * change it, or anything.
714	 */
715
716	/* Find subtype. */
717	desc = get_subtype_desc(ifmw, ttos);
718	if (desc == NULL) {
719		printf("<unknown subtype>");
720		return;
721	}
722
723	if (print_toptype)
724		putchar(' ');
725
726	printf("%s", desc->ifmt_string);
727
728	if (print_toptype) {
729		desc = get_mode_desc(ifmw, ttos);
730		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
731			printf(" mode %s", desc->ifmt_string);
732	}
733
734	/* Find options. */
735	for (i = 0; ttos->options[i].desc != NULL; i++) {
736		if (ttos->options[i].alias)
737			continue;
738		for (desc = ttos->options[i].desc;
739		    desc->ifmt_string != NULL; desc++) {
740			if (ifmw & desc->ifmt_word) {
741				if (seen_option == 0)
742					printf(" <");
743				printf("%s%s", seen_option++ ? "," : "",
744				    desc->ifmt_string);
745			}
746		}
747	}
748	printf("%s", seen_option ? ">" : "");
749
750	if (print_toptype && IFM_INST(ifmw) != 0)
751		printf(" instance %d", IFM_INST(ifmw));
752}
753
754static void
755print_media_word_ifconfig(int ifmw)
756{
757	struct ifmedia_description *desc;
758	struct ifmedia_type_to_subtype *ttos;
759	int i;
760
761	/* Find the top-level interface type. */
762	desc = get_toptype_desc(ifmw);
763	ttos = get_toptype_ttos(ifmw);
764	if (desc->ifmt_string == NULL) {
765		printf("<unknown type>");
766		return;
767	}
768
769	/*
770	 * Don't print the top-level type; it's not like we can
771	 * change it, or anything.
772	 */
773
774	/* Find subtype. */
775	desc = get_subtype_desc(ifmw, ttos);
776	if (desc == NULL) {
777		printf("<unknown subtype>");
778		return;
779	}
780
781	printf("media %s", desc->ifmt_string);
782
783	desc = get_mode_desc(ifmw, ttos);
784	if (desc != NULL)
785		printf(" mode %s", desc->ifmt_string);
786
787	/* Find options. */
788	for (i = 0; ttos->options[i].desc != NULL; i++) {
789		if (ttos->options[i].alias)
790			continue;
791		for (desc = ttos->options[i].desc;
792		    desc->ifmt_string != NULL; desc++) {
793			if (ifmw & desc->ifmt_word) {
794				printf(" mediaopt %s", desc->ifmt_string);
795			}
796		}
797	}
798
799	if (IFM_INST(ifmw) != 0)
800		printf(" instance %d", IFM_INST(ifmw));
801}
802
803/**********************************************************************
804 * ...until here.
805 **********************************************************************/
806
807static struct cmd media_cmds[] = {
808	DEF_CMD_ARG("media",	setmedia),
809	DEF_CMD_ARG("mode",	setmediamode),
810	DEF_CMD_ARG("mediaopt",	setmediaopt),
811	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
812	DEF_CMD_ARG("inst",	setmediainst),
813	DEF_CMD_ARG("instance",	setmediainst),
814};
815static struct afswtch af_media = {
816	.af_name	= "af_media",
817	.af_af		= AF_UNSPEC,
818	.af_other_status = media_status,
819};
820
821static __constructor void
822ifmedia_ctor(void)
823{
824#define	N(a)	(sizeof(a) / sizeof(a[0]))
825	int i;
826
827	for (i = 0; i < N(media_cmds);  i++)
828		cmd_register(&media_cmds[i]);
829	af_register(&af_media);
830#undef N
831}
832