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