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