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