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 * based on sbin/ifconfig/ifmedia.c r221954
68 */
69
70#include <sys/param.h>
71#include <sys/ioctl.h>
72#include <sys/socket.h>
73#include <sys/sysctl.h>
74#include <sys/time.h>
75
76#include <net/if.h>
77#include <net/if_dl.h>
78#include <net/if_types.h>
79#include <net/if_media.h>
80#include <net/route.h>
81
82#include <ctype.h>
83#include <err.h>
84#include <errno.h>
85#include <fcntl.h>
86#include <stdio.h>
87#include <stdlib.h>
88#include <string.h>
89#include <unistd.h>
90
91void	domediaopt(const char *, int, int);
92int	get_media_subtype(int, const char *);
93int	get_media_mode(int, const char *);
94int	get_media_options(int, const char *);
95int	lookup_media_word(struct ifmedia_description *, const char *);
96void	print_media_word(int, int);
97void	print_media_word_ifconfig(int);
98
99#if 0
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	 IFM_IEEE80211_MBSS))
109#define	IFM_IEEE80211_STA	0
110
111static void
112media_status(int s)
113{
114	struct ifmediareq ifmr;
115	int *media_list, i;
116
117	(void) memset(&ifmr, 0, sizeof(ifmr));
118	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
119
120	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
121		/*
122		 * Interface doesn't support SIOC{G,S}IFMEDIA.
123		 */
124		return;
125	}
126
127	if (ifmr.ifm_count == 0) {
128		warnx("%s: no media types?", name);
129		return;
130	}
131
132	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
133	if (media_list == NULL)
134		err(1, "malloc");
135	ifmr.ifm_ulist = media_list;
136
137	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
138		err(1, "SIOCGIFMEDIA");
139
140	printf("\tmedia: ");
141	print_media_word(ifmr.ifm_current, 1);
142	if (ifmr.ifm_active != ifmr.ifm_current) {
143		putchar(' ');
144		putchar('(');
145		print_media_word(ifmr.ifm_active, 0);
146		putchar(')');
147	}
148
149	putchar('\n');
150
151	if (ifmr.ifm_status & IFM_AVALID) {
152		printf("\tstatus: ");
153		switch (IFM_TYPE(ifmr.ifm_active)) {
154		case IFM_ETHER:
155		case IFM_ATM:
156			if (ifmr.ifm_status & IFM_ACTIVE)
157				printf("active");
158			else
159				printf("no carrier");
160			break;
161
162		case IFM_IEEE80211:
163			if (ifmr.ifm_status & IFM_ACTIVE) {
164				/* NB: only sta mode associates */
165				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
166					printf("associated");
167				else
168					printf("running");
169			} else
170				printf("no carrier");
171			break;
172		}
173		putchar('\n');
174	}
175
176	if (ifmr.ifm_count > 0 && supmedia) {
177		printf("\tsupported media:\n");
178		for (i = 0; i < ifmr.ifm_count; i++) {
179			printf("\t\t");
180			print_media_word_ifconfig(media_list[i]);
181			putchar('\n');
182		}
183	}
184
185	free(media_list);
186}
187
188struct ifmediareq *
189ifmedia_getstate(int s)
190{
191	static struct ifmediareq *ifmr = NULL;
192	int *mwords;
193
194	if (ifmr == NULL) {
195		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
196		if (ifmr == NULL)
197			err(1, "malloc");
198
199		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
200		(void) strncpy(ifmr->ifm_name, name,
201		    sizeof(ifmr->ifm_name));
202
203		ifmr->ifm_count = 0;
204		ifmr->ifm_ulist = NULL;
205
206		/*
207		 * We must go through the motions of reading all
208		 * supported media because we need to know both
209		 * the current media type and the top-level type.
210		 */
211
212		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
213			err(1, "SIOCGIFMEDIA");
214		}
215
216		if (ifmr->ifm_count == 0)
217			errx(1, "%s: no media types?", name);
218
219		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
220		if (mwords == NULL)
221			err(1, "malloc");
222
223		ifmr->ifm_ulist = mwords;
224		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
225			err(1, "SIOCGIFMEDIA");
226	}
227
228	return ifmr;
229}
230
231static void
232setifmediacallback(int s, void *arg)
233{
234	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
235	static int did_it = 0;
236
237	if (!did_it) {
238		ifr.ifr_media = ifmr->ifm_current;
239		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
240			err(1, "SIOCSIFMEDIA (media)");
241		free(ifmr->ifm_ulist);
242		free(ifmr);
243		did_it = 1;
244	}
245}
246
247static void
248setmedia(const char *val, int d, int s, const struct afswtch *afp)
249{
250	struct ifmediareq *ifmr;
251	int subtype;
252
253	ifmr = ifmedia_getstate(s);
254
255	/*
256	 * We are primarily concerned with the top-level type.
257	 * However, "current" may be only IFM_NONE, so we just look
258	 * for the top-level type in the first "supported type"
259	 * entry.
260	 *
261	 * (I'm assuming that all supported media types for a given
262	 * interface will be the same top-level type..)
263	 */
264	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
265
266	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
267	ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
268	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
269
270	ifmr->ifm_current = ifr.ifr_media;
271	callback_register(setifmediacallback, (void *)ifmr);
272}
273
274static void
275setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
276{
277
278	domediaopt(val, 0, s);
279}
280
281static void
282unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
283{
284
285	domediaopt(val, 1, s);
286}
287
288static void
289domediaopt(const char *val, int clear, int s)
290{
291	struct ifmediareq *ifmr;
292	int options;
293
294	ifmr = ifmedia_getstate(s);
295
296	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
297
298	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
299	ifr.ifr_media = ifmr->ifm_current;
300	if (clear)
301		ifr.ifr_media &= ~options;
302	else {
303		if (options & IFM_HDX) {
304			ifr.ifr_media &= ~IFM_FDX;
305			options &= ~IFM_HDX;
306		}
307		ifr.ifr_media |= options;
308	}
309	ifmr->ifm_current = ifr.ifr_media;
310	callback_register(setifmediacallback, (void *)ifmr);
311}
312
313static void
314setmediainst(const char *val, int d, int s, const struct afswtch *afp)
315{
316	struct ifmediareq *ifmr;
317	int inst;
318
319	ifmr = ifmedia_getstate(s);
320
321	inst = atoi(val);
322	if (inst < 0 || inst > (int)IFM_INST_MAX)
323		errx(1, "invalid media instance: %s", val);
324
325	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
326	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
327
328	ifmr->ifm_current = ifr.ifr_media;
329	callback_register(setifmediacallback, (void *)ifmr);
330}
331
332static void
333setmediamode(const char *val, int d, int s, const struct afswtch *afp)
334{
335	struct ifmediareq *ifmr;
336	int mode;
337
338	ifmr = ifmedia_getstate(s);
339
340	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
341
342	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
343	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
344
345	ifmr->ifm_current = ifr.ifr_media;
346	callback_register(setifmediacallback, (void *)ifmr);
347}
348#endif
349
350/**********************************************************************
351 * A good chunk of this is duplicated from sys/net/ifmedia.c
352 **********************************************************************/
353
354static struct ifmedia_description ifm_type_descriptions[] =
355    IFM_TYPE_DESCRIPTIONS;
356
357static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
358    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
359
360static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
361    IFM_SUBTYPE_ETHERNET_ALIASES;
362
363static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
364    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
365
366static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
367    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
368
369static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
370    IFM_SUBTYPE_IEEE80211_ALIASES;
371
372static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
373    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
374
375static struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
376    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
377
378static struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
379    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
380
381static struct ifmedia_description ifm_subtype_atm_descriptions[] =
382    IFM_SUBTYPE_ATM_DESCRIPTIONS;
383
384static struct ifmedia_description ifm_subtype_atm_aliases[] =
385    IFM_SUBTYPE_ATM_ALIASES;
386
387static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
388    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
389
390static struct ifmedia_description ifm_subtype_shared_descriptions[] =
391    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
392
393static struct ifmedia_description ifm_subtype_shared_aliases[] =
394    IFM_SUBTYPE_SHARED_ALIASES;
395
396static struct ifmedia_description ifm_shared_option_descriptions[] =
397    IFM_SHARED_OPTION_DESCRIPTIONS;
398
399static struct ifmedia_description ifm_shared_option_aliases[] =
400    IFM_SHARED_OPTION_ALIASES;
401
402struct ifmedia_type_to_subtype {
403	struct {
404		struct ifmedia_description *desc;
405		int alias;
406	} subtypes[5];
407	struct {
408		struct ifmedia_description *desc;
409		int alias;
410	} options[4];
411	struct {
412		struct ifmedia_description *desc;
413		int alias;
414	} modes[3];
415};
416
417/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
418static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
419	{
420		{
421			{ &ifm_subtype_shared_descriptions[0], 0 },
422			{ &ifm_subtype_shared_aliases[0], 1 },
423			{ &ifm_subtype_ethernet_descriptions[0], 0 },
424			{ &ifm_subtype_ethernet_aliases[0], 1 },
425			{ NULL, 0 },
426		},
427		{
428			{ &ifm_shared_option_descriptions[0], 0 },
429			{ &ifm_shared_option_aliases[0], 1 },
430			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
431			{ NULL, 0 },
432		},
433		{
434			{ NULL, 0 },
435		},
436	},
437	{
438		{
439			{ &ifm_subtype_shared_descriptions[0], 0 },
440			{ &ifm_subtype_shared_aliases[0], 1 },
441			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
442			{ &ifm_subtype_ieee80211_aliases[0], 1 },
443			{ NULL, 0 },
444		},
445		{
446			{ &ifm_shared_option_descriptions[0], 0 },
447			{ &ifm_shared_option_aliases[0], 1 },
448			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
449			{ NULL, 0 },
450		},
451		{
452			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
453			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
454			{ NULL, 0 },
455		},
456	},
457	{
458		{
459			{ &ifm_subtype_shared_descriptions[0], 0 },
460			{ &ifm_subtype_shared_aliases[0], 1 },
461			{ &ifm_subtype_atm_descriptions[0], 0 },
462			{ &ifm_subtype_atm_aliases[0], 1 },
463			{ NULL, 0 },
464		},
465		{
466			{ &ifm_shared_option_descriptions[0], 0 },
467			{ &ifm_shared_option_aliases[0], 1 },
468			{ &ifm_subtype_atm_option_descriptions[0], 0 },
469			{ NULL, 0 },
470		},
471		{
472			{ NULL, 0 },
473		},
474	},
475};
476
477int
478get_media_subtype(int type, const char *val)
479{
480	struct ifmedia_description *desc;
481	struct ifmedia_type_to_subtype *ttos;
482	int rval, i;
483
484	/* Find the top-level interface type. */
485	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
486	    desc->ifmt_string != NULL; desc++, ttos++)
487		if (type == desc->ifmt_word)
488			break;
489	if (desc->ifmt_string == NULL)
490		errx(1, "unknown media type 0x%x", type);
491
492	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
493		rval = lookup_media_word(ttos->subtypes[i].desc, val);
494		if (rval != -1)
495			return (rval);
496	}
497	errx(1, "unknown media subtype: %s", val);
498	/*NOTREACHED*/
499}
500
501int
502get_media_mode(int type, const char *val)
503{
504	struct ifmedia_description *desc;
505	struct ifmedia_type_to_subtype *ttos;
506	int rval, i;
507
508	/* Find the top-level interface type. */
509	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
510	    desc->ifmt_string != NULL; desc++, ttos++)
511		if (type == desc->ifmt_word)
512			break;
513	if (desc->ifmt_string == NULL)
514		errx(1, "unknown media mode 0x%x", type);
515
516	for (i = 0; ttos->modes[i].desc != NULL; i++) {
517		rval = lookup_media_word(ttos->modes[i].desc, val);
518		if (rval != -1)
519			return (rval);
520	}
521	return -1;
522}
523
524int
525get_media_options(int type, const char *val)
526{
527	struct ifmedia_description *desc;
528	struct ifmedia_type_to_subtype *ttos;
529	char *optlist, *optptr;
530	int option = 0, i, rval = 0;
531
532	/* We muck with the string, so copy it. */
533	optlist = strdup(val);
534	if (optlist == NULL)
535		err(1, "strdup");
536
537	/* Find the top-level interface type. */
538	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
539	    desc->ifmt_string != NULL; desc++, ttos++)
540		if (type == desc->ifmt_word)
541			break;
542	if (desc->ifmt_string == NULL)
543		errx(1, "unknown media type 0x%x", type);
544
545	/*
546	 * Look up the options in the user-provided comma-separated
547	 * list.
548	 */
549	optptr = optlist;
550	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
551		for (i = 0; ttos->options[i].desc != NULL; i++) {
552			option = lookup_media_word(ttos->options[i].desc, optptr);
553			if (option != -1)
554				break;
555		}
556		if (option == 0)
557			errx(1, "unknown option: %s", optptr);
558		rval |= option;
559	}
560
561	free(optlist);
562	return (rval);
563}
564
565int
566lookup_media_word(struct ifmedia_description *desc, const char *val)
567{
568
569	for (; desc->ifmt_string != NULL; desc++)
570		if (strcasecmp(desc->ifmt_string, val) == 0)
571			return (desc->ifmt_word);
572
573	return (-1);
574}
575
576static struct ifmedia_description *get_toptype_desc(int ifmw)
577{
578	struct ifmedia_description *desc;
579
580	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
581		if (IFM_TYPE(ifmw) == desc->ifmt_word)
582			break;
583
584	return desc;
585}
586
587static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
588{
589	struct ifmedia_description *desc;
590	struct ifmedia_type_to_subtype *ttos;
591
592	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
593	    desc->ifmt_string != NULL; desc++, ttos++)
594		if (IFM_TYPE(ifmw) == desc->ifmt_word)
595			break;
596
597	return ttos;
598}
599
600static struct ifmedia_description *get_subtype_desc(int ifmw,
601    struct ifmedia_type_to_subtype *ttos)
602{
603	int i;
604	struct ifmedia_description *desc;
605
606	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
607		if (ttos->subtypes[i].alias)
608			continue;
609		for (desc = ttos->subtypes[i].desc;
610		    desc->ifmt_string != NULL; desc++) {
611			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
612				return desc;
613		}
614	}
615
616	return NULL;
617}
618
619static struct ifmedia_description *get_mode_desc(int ifmw,
620    struct ifmedia_type_to_subtype *ttos)
621{
622	int i;
623	struct ifmedia_description *desc;
624
625	for (i = 0; ttos->modes[i].desc != NULL; i++) {
626		if (ttos->modes[i].alias)
627			continue;
628		for (desc = ttos->modes[i].desc;
629		    desc->ifmt_string != NULL; desc++) {
630			if (IFM_MODE(ifmw) == desc->ifmt_word)
631				return desc;
632		}
633	}
634
635	return NULL;
636}
637
638void
639print_media_word(int ifmw, int print_toptype)
640{
641	struct ifmedia_description *desc;
642	struct ifmedia_type_to_subtype *ttos;
643	int seen_option = 0, i;
644
645	/* Find the top-level interface type. */
646	desc = get_toptype_desc(ifmw);
647	ttos = get_toptype_ttos(ifmw);
648	if (desc->ifmt_string == NULL) {
649		printf("<unknown type>");
650		return;
651	} else if (print_toptype) {
652		printf("%s", desc->ifmt_string);
653	}
654
655	/*
656	 * Don't print the top-level type; it's not like we can
657	 * change it, or anything.
658	 */
659
660	/* Find subtype. */
661	desc = get_subtype_desc(ifmw, ttos);
662	if (desc == NULL) {
663		printf("<unknown subtype>");
664		return;
665	}
666
667	if (print_toptype)
668		putchar(' ');
669
670	printf("%s", desc->ifmt_string);
671
672	if (print_toptype) {
673		desc = get_mode_desc(ifmw, ttos);
674		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
675			printf(" mode %s", desc->ifmt_string);
676	}
677
678	/* Find options. */
679	for (i = 0; ttos->options[i].desc != NULL; i++) {
680		if (ttos->options[i].alias)
681			continue;
682		for (desc = ttos->options[i].desc;
683		    desc->ifmt_string != NULL; desc++) {
684			if (ifmw & desc->ifmt_word) {
685				if (seen_option == 0)
686					printf(" <");
687				printf("%s%s", seen_option++ ? "," : "",
688				    desc->ifmt_string);
689			}
690		}
691	}
692	printf("%s", seen_option ? ">" : "");
693
694	if (print_toptype && IFM_INST(ifmw) != 0)
695		printf(" instance %d", IFM_INST(ifmw));
696}
697
698void
699print_media_word_ifconfig(int ifmw)
700{
701	struct ifmedia_description *desc;
702	struct ifmedia_type_to_subtype *ttos;
703	int seen_option = 0, i;
704
705	/* Find the top-level interface type. */
706	desc = get_toptype_desc(ifmw);
707	ttos = get_toptype_ttos(ifmw);
708	if (desc->ifmt_string == NULL) {
709		printf("<unknown type>");
710		return;
711	}
712
713	/*
714	 * Don't print the top-level type; it's not like we can
715	 * change it, or anything.
716	 */
717
718	/* Find subtype. */
719	desc = get_subtype_desc(ifmw, ttos);
720	if (desc == NULL) {
721		printf("<unknown subtype>");
722		return;
723	}
724
725	printf("media %s", desc->ifmt_string);
726
727	desc = get_mode_desc(ifmw, ttos);
728	if (desc != NULL)
729		printf(" mode %s", desc->ifmt_string);
730
731	/* Find options. */
732	for (i = 0; ttos->options[i].desc != NULL; i++) {
733		if (ttos->options[i].alias)
734			continue;
735		for (desc = ttos->options[i].desc;
736		    desc->ifmt_string != NULL; desc++) {
737			if (ifmw & desc->ifmt_word) {
738				if (seen_option == 0)
739					printf(" mediaopt ");
740				printf("%s%s", seen_option++ ? "," : "",
741				    desc->ifmt_string);
742			}
743		}
744	}
745
746	if (IFM_INST(ifmw) != 0)
747		printf(" instance %d", IFM_INST(ifmw));
748}
749
750/**********************************************************************
751 * ...until here.
752 **********************************************************************/
753