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