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