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