ifmedia.c revision 217013
125450Speter/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
250476Speter/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 217013 2011-01-05 15:28:30Z marius $ */
325450Speter
425450Speter/*
525450Speter * Copyright (c) 1997 Jason R. Thorpe.
625450Speter * All rights reserved.
725450Speter *
825450Speter * Redistribution and use in source and binary forms, with or without
925450Speter * modification, are permitted provided that the following conditions
1025450Speter * are met:
1125450Speter * 1. Redistributions of source code must retain the above copyright
1225450Speter *    notice, this list of conditions and the following disclaimer.
1325450Speter * 2. Redistributions in binary form must reproduce the above copyright
1425450Speter *    notice, this list of conditions and the following disclaimer in the
1525450Speter *    documentation and/or other materials provided with the distribution.
1625450Speter * 3. All advertising materials mentioning features or use of this software
1725450Speter *    must display the following acknowledgement:
1825450Speter *      This product includes software developed for the NetBSD Project
1925450Speter *	by Jason R. Thorpe.
2025450Speter * 4. The name of the author may not be used to endorse or promote products
2125450Speter *    derived from this software without specific prior written permission.
2225450Speter *
2325450Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2425450Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2525450Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2625450Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2725450Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2825450Speter * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2925450Speter * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3025450Speter * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3125450Speter * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3225450Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3325450Speter * SUCH DAMAGE.
3425450Speter */
3525450Speter
3625450Speter/*
3725450Speter * Copyright (c) 1983, 1993
3825450Speter *	The Regents of the University of California.  All rights reserved.
3925450Speter *
4025450Speter * Redistribution and use in source and binary forms, with or without
4125450Speter * modification, are permitted provided that the following conditions
4225450Speter * are met:
4325450Speter * 1. Redistributions of source code must retain the above copyright
4425450Speter *    notice, this list of conditions and the following disclaimer.
4525450Speter * 2. Redistributions in binary form must reproduce the above copyright
4625450Speter *    notice, this list of conditions and the following disclaimer in the
4725450Speter *    documentation and/or other materials provided with the distribution.
4825450Speter * 4. Neither the name of the University nor the names of its contributors
4925450Speter *    may be used to endorse or promote products derived from this software
5025450Speter *    without specific prior written permission.
5125450Speter *
5225450Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5325450Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5425450Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5525450Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5625450Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5725450Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5825450Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5925450Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6025450Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6125450Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6225450Speter * SUCH DAMAGE.
6325450Speter */
6425450Speter
6525450Speter#include <sys/param.h>
6625450Speter#include <sys/ioctl.h>
6725450Speter#include <sys/socket.h>
6825450Speter#include <sys/sysctl.h>
6925450Speter#include <sys/time.h>
7025450Speter
7125450Speter#include <net/if.h>
7225450Speter#include <net/if_dl.h>
7325450Speter#include <net/if_types.h>
7425450Speter#include <net/if_media.h>
7525450Speter#include <net/route.h>
7625450Speter
7725450Speter#include <ctype.h>
7825450Speter#include <err.h>
7925450Speter#include <errno.h>
8025450Speter#include <fcntl.h>
8125450Speter#include <stdio.h>
8225450Speter#include <stdlib.h>
8325450Speter#include <string.h>
8425450Speter#include <unistd.h>
8525450Speter
8625450Speter#include "ifconfig.h"
8725450Speter
8895005Simpstatic void	domediaopt(const char *, int, int);
8995005Simpstatic int	get_media_subtype(int, const char *);
90114164Ssamstatic int	get_media_mode(int, const char *);
9195005Simpstatic int	get_media_options(int, const char *);
9295005Simpstatic int	lookup_media_word(struct ifmedia_description *, const char *);
9395005Simpstatic void	print_media_word(int, int);
9495005Simpstatic void	print_media_word_ifconfig(int);
9525450Speter
9695005Simpstatic struct ifmedia_description *get_toptype_desc(int);
9795005Simpstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int);
9895005Simpstatic struct ifmedia_description *get_subtype_desc(int,
9995005Simp    struct ifmedia_type_to_subtype *ttos);
10077385Sphk
101178354Ssam#define	IFM_OPMODE(x) \
102178354Ssam	((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
103195618Srpaulo	 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
104195618Srpaulo	 IFM_IEEE80211_MBSS))
105178354Ssam#define	IFM_IEEE80211_STA	0
106178354Ssam
107138593Ssamstatic void
108139494Ssammedia_status(int s)
10925450Speter{
11025450Speter	struct ifmediareq ifmr;
11125450Speter	int *media_list, i;
11225450Speter
11325450Speter	(void) memset(&ifmr, 0, sizeof(ifmr));
11425450Speter	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
11525450Speter
11625450Speter	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
11725450Speter		/*
11825450Speter		 * Interface doesn't support SIOC{G,S}IFMEDIA.
11925450Speter		 */
12025450Speter		return;
12125450Speter	}
12225450Speter
12325450Speter	if (ifmr.ifm_count == 0) {
12425450Speter		warnx("%s: no media types?", name);
12525450Speter		return;
12625450Speter	}
12725450Speter
12825450Speter	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
12925450Speter	if (media_list == NULL)
13025450Speter		err(1, "malloc");
13125450Speter	ifmr.ifm_ulist = media_list;
13225450Speter
13325450Speter	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
13425450Speter		err(1, "SIOCGIFMEDIA");
13525450Speter
13625450Speter	printf("\tmedia: ");
13777385Sphk	print_media_word(ifmr.ifm_current, 1);
13825450Speter	if (ifmr.ifm_active != ifmr.ifm_current) {
13925450Speter		putchar(' ');
14025450Speter		putchar('(');
14177385Sphk		print_media_word(ifmr.ifm_active, 0);
14225450Speter		putchar(')');
14325450Speter	}
14425450Speter
14577385Sphk	putchar('\n');
14677385Sphk
14725450Speter	if (ifmr.ifm_status & IFM_AVALID) {
14877385Sphk		printf("\tstatus: ");
14925450Speter		switch (IFM_TYPE(ifmr.ifm_active)) {
15025450Speter		case IFM_ETHER:
151161536Sthomas		case IFM_ATM:
15225450Speter			if (ifmr.ifm_status & IFM_ACTIVE)
15325450Speter				printf("active");
15425450Speter			else
15525450Speter				printf("no carrier");
15625450Speter			break;
15725450Speter
15825450Speter		case IFM_FDDI:
15925450Speter		case IFM_TOKEN:
16025450Speter			if (ifmr.ifm_status & IFM_ACTIVE)
16125450Speter				printf("inserted");
16225450Speter			else
16325450Speter				printf("no ring");
16425450Speter			break;
165114232Sharti
16677217Sphk		case IFM_IEEE80211:
167178354Ssam			if (ifmr.ifm_status & IFM_ACTIVE) {
168178354Ssam				/* NB: only sta mode associates */
169178354Ssam				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
170178354Ssam					printf("associated");
171178354Ssam				else
172178354Ssam					printf("running");
173178354Ssam			} else
17477217Sphk				printf("no carrier");
17577217Sphk			break;
17625450Speter		}
17785853Syar		putchar('\n');
17825450Speter	}
17925450Speter
18077385Sphk	if (ifmr.ifm_count > 0 && supmedia) {
18177385Sphk		printf("\tsupported media:\n");
18225450Speter		for (i = 0; i < ifmr.ifm_count; i++) {
18377385Sphk			printf("\t\t");
18477385Sphk			print_media_word_ifconfig(media_list[i]);
18577385Sphk			putchar('\n');
18625450Speter		}
18725450Speter	}
18825450Speter
18925450Speter	free(media_list);
19025450Speter}
19125450Speter
192170531Ssamstruct ifmediareq *
193170531Ssamifmedia_getstate(int s)
19425450Speter{
195140913Sambrisko	static struct ifmediareq *ifmr = NULL;
196140913Sambrisko	int *mwords;
19725450Speter
198140913Sambrisko	if (ifmr == NULL) {
199140913Sambrisko		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
200140913Sambrisko		if (ifmr == NULL)
201140913Sambrisko			err(1, "malloc");
20225450Speter
203140913Sambrisko		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
204140913Sambrisko		(void) strncpy(ifmr->ifm_name, name,
205140913Sambrisko		    sizeof(ifmr->ifm_name));
206140913Sambrisko
207140913Sambrisko		ifmr->ifm_count = 0;
208140913Sambrisko		ifmr->ifm_ulist = NULL;
209140913Sambrisko
21025450Speter		/*
211140913Sambrisko		 * We must go through the motions of reading all
212140913Sambrisko		 * supported media because we need to know both
213140913Sambrisko		 * the current media type and the top-level type.
21425450Speter		 */
215140913Sambrisko
216140913Sambrisko		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
21725450Speter			err(1, "SIOCGIFMEDIA");
218140913Sambrisko		}
219140913Sambrisko
220140913Sambrisko		if (ifmr->ifm_count == 0)
221140913Sambrisko			errx(1, "%s: no media types?", name);
222140913Sambrisko
223140913Sambrisko		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
224140913Sambrisko		if (mwords == NULL)
225140913Sambrisko			err(1, "malloc");
226140913Sambrisko
227140913Sambrisko		ifmr->ifm_ulist = mwords;
228140913Sambrisko		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
229140913Sambrisko			err(1, "SIOCGIFMEDIA");
23025450Speter	}
23125450Speter
232140913Sambrisko	return ifmr;
233140913Sambrisko}
23425450Speter
235140913Sambriskostatic void
236140913Sambriskosetifmediacallback(int s, void *arg)
237140913Sambrisko{
238140913Sambrisko	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
239140913Sambrisko	static int did_it = 0;
240140913Sambrisko
241140913Sambrisko	if (!did_it) {
242154240Sambrisko		ifr.ifr_media = ifmr->ifm_current;
243140913Sambrisko		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
244140913Sambrisko			err(1, "SIOCSIFMEDIA (media)");
245140913Sambrisko		free(ifmr->ifm_ulist);
246140913Sambrisko		free(ifmr);
247140913Sambrisko		did_it = 1;
248140913Sambrisko	}
249140913Sambrisko}
250140913Sambrisko
251140913Sambriskostatic void
252140913Sambriskosetmedia(const char *val, int d, int s, const struct afswtch *afp)
253140913Sambrisko{
254140913Sambrisko	struct ifmediareq *ifmr;
255140913Sambrisko	int subtype;
256140913Sambrisko
257170531Ssam	ifmr = ifmedia_getstate(s);
258140913Sambrisko
25925450Speter	/*
26025450Speter	 * We are primarily concerned with the top-level type.
26125450Speter	 * However, "current" may be only IFM_NONE, so we just look
26225450Speter	 * for the top-level type in the first "supported type"
26325450Speter	 * entry.
26425450Speter	 *
26525450Speter	 * (I'm assuming that all supported media types for a given
26625450Speter	 * interface will be the same top-level type..)
26725450Speter	 */
268140913Sambrisko	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
26925450Speter
27025450Speter	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
271140913Sambrisko	ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
272140913Sambrisko	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
27325450Speter
274140913Sambrisko	if ((ifr.ifr_media & IFM_TMASK) == 0) {
275215272Smarius		ifr.ifr_media &= ~(IFM_GMASK | IFM_OMASK);
276140913Sambrisko	}
277140913Sambrisko
278140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
279140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
28025450Speter}
28125450Speter
282138593Ssamstatic void
28395005Simpsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
28425450Speter{
28525450Speter
28625450Speter	domediaopt(val, 0, s);
28725450Speter}
28825450Speter
289138593Ssamstatic void
29095005Simpunsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
29125450Speter{
29225450Speter
29325450Speter	domediaopt(val, 1, s);
29425450Speter}
29525450Speter
29625450Speterstatic void
29795005Simpdomediaopt(const char *val, int clear, int s)
29825450Speter{
299140913Sambrisko	struct ifmediareq *ifmr;
300140913Sambrisko	int options;
30125450Speter
302170531Ssam	ifmr = ifmedia_getstate(s);
30325450Speter
304140913Sambrisko	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
30525450Speter
30625450Speter	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
307140913Sambrisko	ifr.ifr_media = ifmr->ifm_current;
30825450Speter	if (clear)
30925450Speter		ifr.ifr_media &= ~options;
310165359Sjkim	else {
311165359Sjkim		if (options & IFM_HDX) {
312165359Sjkim			ifr.ifr_media &= ~IFM_FDX;
313165359Sjkim			options &= ~IFM_HDX;
314165359Sjkim		}
31525450Speter		ifr.ifr_media |= options;
316165359Sjkim	}
317140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
318140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
31925450Speter}
32025450Speter
321166113Smariusstatic void
322166113Smariussetmediainst(const char *val, int d, int s, const struct afswtch *afp)
323166113Smarius{
324166113Smarius	struct ifmediareq *ifmr;
325166113Smarius	int inst;
326114164Ssam
327170531Ssam	ifmr = ifmedia_getstate(s);
328166113Smarius
329166113Smarius	inst = atoi(val);
330194799Sdelphij	if (inst < 0 || inst > (int)IFM_INST_MAX)
331166113Smarius		errx(1, "invalid media instance: %s", val);
332166113Smarius
333166113Smarius	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
334166113Smarius	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
335166113Smarius
336166113Smarius	ifmr->ifm_current = ifr.ifr_media;
337166113Smarius	callback_register(setifmediacallback, (void *)ifmr);
338166113Smarius}
339166113Smarius
340138593Ssamstatic void
341114164Ssamsetmediamode(const char *val, int d, int s, const struct afswtch *afp)
342114164Ssam{
343140913Sambrisko	struct ifmediareq *ifmr;
344140913Sambrisko	int mode;
345114164Ssam
346170531Ssam	ifmr = ifmedia_getstate(s);
347114164Ssam
348140913Sambrisko	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
349114164Ssam
350114164Ssam	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
351140913Sambrisko	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
352114164Ssam
353140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
354140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
355114164Ssam}
356114164Ssam
35725450Speter/**********************************************************************
35825450Speter * A good chunk of this is duplicated from sys/net/ifmedia.c
35925450Speter **********************************************************************/
36025450Speter
36125450Speterstatic struct ifmedia_description ifm_type_descriptions[] =
36225450Speter    IFM_TYPE_DESCRIPTIONS;
36325450Speter
36425450Speterstatic struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
36525450Speter    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
36625450Speter
36725450Speterstatic struct ifmedia_description ifm_subtype_ethernet_aliases[] =
36825450Speter    IFM_SUBTYPE_ETHERNET_ALIASES;
36925450Speter
37025450Speterstatic struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
37125450Speter    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
37225450Speter
37325450Speterstatic struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
37425450Speter    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
37525450Speter
37625450Speterstatic struct ifmedia_description ifm_subtype_tokenring_aliases[] =
37725450Speter    IFM_SUBTYPE_TOKENRING_ALIASES;
37825450Speter
37925450Speterstatic struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
38025450Speter    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
38125450Speter
38225450Speterstatic struct ifmedia_description ifm_subtype_fddi_descriptions[] =
38325450Speter    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
38425450Speter
38525450Speterstatic struct ifmedia_description ifm_subtype_fddi_aliases[] =
38625450Speter    IFM_SUBTYPE_FDDI_ALIASES;
38725450Speter
38825450Speterstatic struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
38925450Speter    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
39025450Speter
39177217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
39277217Sphk    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
39377217Sphk
39477217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
39577217Sphk    IFM_SUBTYPE_IEEE80211_ALIASES;
39677217Sphk
39777217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
39877217Sphk    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
39977217Sphk
400114164Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
401114164Ssam    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
402114164Ssam
403116820Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
404116820Ssam    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
405116820Ssam
406114232Shartistatic struct ifmedia_description ifm_subtype_atm_descriptions[] =
407114232Sharti    IFM_SUBTYPE_ATM_DESCRIPTIONS;
408114232Sharti
409114232Shartistatic struct ifmedia_description ifm_subtype_atm_aliases[] =
410114232Sharti    IFM_SUBTYPE_ATM_ALIASES;
411114232Sharti
412114232Shartistatic struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
413114232Sharti    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
414114232Sharti
41525450Speterstatic struct ifmedia_description ifm_subtype_shared_descriptions[] =
41625450Speter    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
41725450Speter
41825450Speterstatic struct ifmedia_description ifm_subtype_shared_aliases[] =
41925450Speter    IFM_SUBTYPE_SHARED_ALIASES;
42025450Speter
42125450Speterstatic struct ifmedia_description ifm_shared_option_descriptions[] =
42225450Speter    IFM_SHARED_OPTION_DESCRIPTIONS;
42325450Speter
424217013Smariusstatic struct ifmedia_description ifm_shared_option_aliases[] =
425217013Smarius    IFM_SHARED_OPTION_ALIASES;
426217013Smarius
42725450Speterstruct ifmedia_type_to_subtype {
42825450Speter	struct {
42925450Speter		struct ifmedia_description *desc;
43025450Speter		int alias;
43125450Speter	} subtypes[5];
43225450Speter	struct {
43325450Speter		struct ifmedia_description *desc;
43425450Speter		int alias;
435217013Smarius	} options[4];
436114164Ssam	struct {
437114164Ssam		struct ifmedia_description *desc;
438114164Ssam		int alias;
439116820Ssam	} modes[3];
44025450Speter};
44125450Speter
44225450Speter/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
44325450Speterstatic struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
44425450Speter	{
44525450Speter		{
44625450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
44725450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
44825450Speter			{ &ifm_subtype_ethernet_descriptions[0], 0 },
44925450Speter			{ &ifm_subtype_ethernet_aliases[0], 1 },
45025450Speter			{ NULL, 0 },
45125450Speter		},
45225450Speter		{
45325450Speter			{ &ifm_shared_option_descriptions[0], 0 },
454217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
45577217Sphk			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
45625450Speter			{ NULL, 0 },
45725450Speter		},
458114164Ssam		{
459114164Ssam			{ NULL, 0 },
460114164Ssam		},
46125450Speter	},
46225450Speter	{
46325450Speter		{
46425450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
46525450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
46625450Speter			{ &ifm_subtype_tokenring_descriptions[0], 0 },
46725450Speter			{ &ifm_subtype_tokenring_aliases[0], 1 },
46825450Speter			{ NULL, 0 },
46925450Speter		},
47025450Speter		{
47125450Speter			{ &ifm_shared_option_descriptions[0], 0 },
472217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
47377217Sphk			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
47425450Speter			{ NULL, 0 },
47525450Speter		},
476114164Ssam		{
477114164Ssam			{ NULL, 0 },
478114164Ssam		},
47925450Speter	},
48025450Speter	{
48125450Speter		{
48225450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
48325450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
48425450Speter			{ &ifm_subtype_fddi_descriptions[0], 0 },
48525450Speter			{ &ifm_subtype_fddi_aliases[0], 1 },
48625450Speter			{ NULL, 0 },
48725450Speter		},
48825450Speter		{
48925450Speter			{ &ifm_shared_option_descriptions[0], 0 },
490217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
49177217Sphk			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
49225450Speter			{ NULL, 0 },
49325450Speter		},
494114164Ssam		{
495114164Ssam			{ NULL, 0 },
496114164Ssam		},
49725450Speter	},
49877217Sphk	{
49977217Sphk		{
50077217Sphk			{ &ifm_subtype_shared_descriptions[0], 0 },
50177217Sphk			{ &ifm_subtype_shared_aliases[0], 1 },
50277217Sphk			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
50377217Sphk			{ &ifm_subtype_ieee80211_aliases[0], 1 },
50477217Sphk			{ NULL, 0 },
50577217Sphk		},
50677217Sphk		{
50777217Sphk			{ &ifm_shared_option_descriptions[0], 0 },
508217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
50977217Sphk			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
51077217Sphk			{ NULL, 0 },
51177217Sphk		},
512114164Ssam		{
513114164Ssam			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
514116820Ssam			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
515114164Ssam			{ NULL, 0 },
516114164Ssam		},
51777217Sphk	},
518114232Sharti	{
519114232Sharti		{
520114232Sharti			{ &ifm_subtype_shared_descriptions[0], 0 },
521114232Sharti			{ &ifm_subtype_shared_aliases[0], 1 },
522114232Sharti			{ &ifm_subtype_atm_descriptions[0], 0 },
523114232Sharti			{ &ifm_subtype_atm_aliases[0], 1 },
524114232Sharti			{ NULL, 0 },
525114232Sharti		},
526114232Sharti		{
527114232Sharti			{ &ifm_shared_option_descriptions[0], 0 },
528217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
529114232Sharti			{ &ifm_subtype_atm_option_descriptions[0], 0 },
530114232Sharti			{ NULL, 0 },
531114232Sharti		},
532114232Sharti		{
533114232Sharti			{ NULL, 0 },
534114232Sharti		},
535114232Sharti	},
53625450Speter};
53725450Speter
53825450Speterstatic int
53995005Simpget_media_subtype(int type, const char *val)
54025450Speter{
54125450Speter	struct ifmedia_description *desc;
54225450Speter	struct ifmedia_type_to_subtype *ttos;
54325450Speter	int rval, i;
54425450Speter
54525450Speter	/* Find the top-level interface type. */
54625450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
54725450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
54825450Speter		if (type == desc->ifmt_word)
54925450Speter			break;
55025450Speter	if (desc->ifmt_string == NULL)
55125450Speter		errx(1, "unknown media type 0x%x", type);
55225450Speter
55325450Speter	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
55425450Speter		rval = lookup_media_word(ttos->subtypes[i].desc, val);
55525450Speter		if (rval != -1)
55625450Speter			return (rval);
55725450Speter	}
55825450Speter	errx(1, "unknown media subtype: %s", val);
559114164Ssam	/*NOTREACHED*/
56025450Speter}
56125450Speter
56225450Speterstatic int
563114164Ssamget_media_mode(int type, const char *val)
564114164Ssam{
565114164Ssam	struct ifmedia_description *desc;
566114164Ssam	struct ifmedia_type_to_subtype *ttos;
567114164Ssam	int rval, i;
568114164Ssam
569114164Ssam	/* Find the top-level interface type. */
570114164Ssam	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
571114164Ssam	    desc->ifmt_string != NULL; desc++, ttos++)
572114164Ssam		if (type == desc->ifmt_word)
573114164Ssam			break;
574114164Ssam	if (desc->ifmt_string == NULL)
575114164Ssam		errx(1, "unknown media mode 0x%x", type);
576114164Ssam
577114164Ssam	for (i = 0; ttos->modes[i].desc != NULL; i++) {
578114164Ssam		rval = lookup_media_word(ttos->modes[i].desc, val);
579114164Ssam		if (rval != -1)
580114164Ssam			return (rval);
581114164Ssam	}
582114164Ssam	return -1;
583114164Ssam}
584114164Ssam
585114164Ssamstatic int
58695005Simpget_media_options(int type, const char *val)
58725450Speter{
58825450Speter	struct ifmedia_description *desc;
58925450Speter	struct ifmedia_type_to_subtype *ttos;
59025450Speter	char *optlist, *optptr;
59125450Speter	int option = 0, i, rval = 0;
59225450Speter
59325450Speter	/* We muck with the string, so copy it. */
59425450Speter	optlist = strdup(val);
59525450Speter	if (optlist == NULL)
59625450Speter		err(1, "strdup");
59725450Speter
59825450Speter	/* Find the top-level interface type. */
59925450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
60025450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
60125450Speter		if (type == desc->ifmt_word)
60225450Speter			break;
60325450Speter	if (desc->ifmt_string == NULL)
60425450Speter		errx(1, "unknown media type 0x%x", type);
60525450Speter
60625450Speter	/*
60725450Speter	 * Look up the options in the user-provided comma-separated
60825450Speter	 * list.
60925450Speter	 */
61025450Speter	optptr = optlist;
61125450Speter	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
61225450Speter		for (i = 0; ttos->options[i].desc != NULL; i++) {
61325450Speter			option = lookup_media_word(ttos->options[i].desc, optptr);
61425450Speter			if (option != -1)
61525450Speter				break;
61625450Speter		}
61725450Speter		if (option == 0)
61825450Speter			errx(1, "unknown option: %s", optptr);
61925450Speter		rval |= option;
62025450Speter	}
62125450Speter
62225450Speter	free(optlist);
62325450Speter	return (rval);
62425450Speter}
62525450Speter
62625450Speterstatic int
62795005Simplookup_media_word(struct ifmedia_description *desc, const char *val)
62825450Speter{
62925450Speter
63025450Speter	for (; desc->ifmt_string != NULL; desc++)
63125450Speter		if (strcasecmp(desc->ifmt_string, val) == 0)
63225450Speter			return (desc->ifmt_word);
63325450Speter
63425450Speter	return (-1);
63525450Speter}
63625450Speter
63795005Simpstatic struct ifmedia_description *get_toptype_desc(int ifmw)
63825450Speter{
63925450Speter	struct ifmedia_description *desc;
64077385Sphk
64177385Sphk	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
64277385Sphk		if (IFM_TYPE(ifmw) == desc->ifmt_word)
64377385Sphk			break;
64477385Sphk
64577385Sphk	return desc;
64677385Sphk}
64777385Sphk
64895005Simpstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
64977385Sphk{
65077385Sphk	struct ifmedia_description *desc;
65125450Speter	struct ifmedia_type_to_subtype *ttos;
65225450Speter
65325450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
65425450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
65525450Speter		if (IFM_TYPE(ifmw) == desc->ifmt_word)
65625450Speter			break;
65777385Sphk
65877385Sphk	return ttos;
65977385Sphk}
66077385Sphk
66195005Simpstatic struct ifmedia_description *get_subtype_desc(int ifmw,
66295005Simp    struct ifmedia_type_to_subtype *ttos)
66377385Sphk{
66477385Sphk	int i;
66577385Sphk	struct ifmedia_description *desc;
66677385Sphk
66777385Sphk	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
66877385Sphk		if (ttos->subtypes[i].alias)
66977385Sphk			continue;
67077385Sphk		for (desc = ttos->subtypes[i].desc;
67177385Sphk		    desc->ifmt_string != NULL; desc++) {
67277385Sphk			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
67377385Sphk				return desc;
67477385Sphk		}
67577385Sphk	}
67677385Sphk
67777385Sphk	return NULL;
67877385Sphk}
67977385Sphk
680114164Ssamstatic struct ifmedia_description *get_mode_desc(int ifmw,
681114164Ssam    struct ifmedia_type_to_subtype *ttos)
682114164Ssam{
683114164Ssam	int i;
684114164Ssam	struct ifmedia_description *desc;
685114164Ssam
686114164Ssam	for (i = 0; ttos->modes[i].desc != NULL; i++) {
687114164Ssam		if (ttos->modes[i].alias)
688114164Ssam			continue;
689114164Ssam		for (desc = ttos->modes[i].desc;
690114164Ssam		    desc->ifmt_string != NULL; desc++) {
691114164Ssam			if (IFM_MODE(ifmw) == desc->ifmt_word)
692114164Ssam				return desc;
693114164Ssam		}
694114164Ssam	}
695114164Ssam
696114164Ssam	return NULL;
697114164Ssam}
698114164Ssam
69977385Sphkstatic void
70095005Simpprint_media_word(int ifmw, int print_toptype)
70177385Sphk{
70277385Sphk	struct ifmedia_description *desc;
70377385Sphk	struct ifmedia_type_to_subtype *ttos;
70477385Sphk	int seen_option = 0, i;
70577385Sphk
70677385Sphk	/* Find the top-level interface type. */
70777385Sphk	desc = get_toptype_desc(ifmw);
70877385Sphk	ttos = get_toptype_ttos(ifmw);
70925450Speter	if (desc->ifmt_string == NULL) {
71025450Speter		printf("<unknown type>");
71125450Speter		return;
71277385Sphk	} else if (print_toptype) {
71377385Sphk		printf("%s", desc->ifmt_string);
71425450Speter	}
71525450Speter
71625450Speter	/*
71725450Speter	 * Don't print the top-level type; it's not like we can
71825450Speter	 * change it, or anything.
71925450Speter	 */
72025450Speter
72125450Speter	/* Find subtype. */
72277385Sphk	desc = get_subtype_desc(ifmw, ttos);
723161536Sthomas	if (desc == NULL) {
724161536Sthomas		printf("<unknown subtype>");
725161536Sthomas		return;
726161536Sthomas	}
72725450Speter
72877385Sphk	if (print_toptype)
72977385Sphk		putchar(' ');
73077385Sphk
73125450Speter	printf("%s", desc->ifmt_string);
73225450Speter
733114164Ssam	if (print_toptype) {
734114164Ssam		desc = get_mode_desc(ifmw, ttos);
735116820Ssam		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
736114164Ssam			printf(" mode %s", desc->ifmt_string);
737114164Ssam	}
738114164Ssam
73925450Speter	/* Find options. */
74025450Speter	for (i = 0; ttos->options[i].desc != NULL; i++) {
74125450Speter		if (ttos->options[i].alias)
74225450Speter			continue;
74325450Speter		for (desc = ttos->options[i].desc;
74425450Speter		    desc->ifmt_string != NULL; desc++) {
74525450Speter			if (ifmw & desc->ifmt_word) {
74625450Speter				if (seen_option == 0)
74725450Speter					printf(" <");
74825450Speter				printf("%s%s", seen_option++ ? "," : "",
74925450Speter				    desc->ifmt_string);
75025450Speter			}
75125450Speter		}
75225450Speter	}
75325450Speter	printf("%s", seen_option ? ">" : "");
754166113Smarius
755166169Smarius	if (print_toptype && IFM_INST(ifmw) != 0)
756166113Smarius		printf(" instance %d", IFM_INST(ifmw));
75725450Speter}
75825450Speter
75977385Sphkstatic void
76095005Simpprint_media_word_ifconfig(int ifmw)
76177385Sphk{
76277385Sphk	struct ifmedia_description *desc;
76377385Sphk	struct ifmedia_type_to_subtype *ttos;
764215259Smarius	int seen_option = 0, i;
76577385Sphk
76677385Sphk	/* Find the top-level interface type. */
76777385Sphk	desc = get_toptype_desc(ifmw);
76877385Sphk	ttos = get_toptype_ttos(ifmw);
76977385Sphk	if (desc->ifmt_string == NULL) {
77077385Sphk		printf("<unknown type>");
77177385Sphk		return;
77277385Sphk	}
77377385Sphk
77477385Sphk	/*
77577385Sphk	 * Don't print the top-level type; it's not like we can
77677385Sphk	 * change it, or anything.
77777385Sphk	 */
77877385Sphk
77977385Sphk	/* Find subtype. */
78077385Sphk	desc = get_subtype_desc(ifmw, ttos);
781161536Sthomas	if (desc == NULL) {
782161536Sthomas		printf("<unknown subtype>");
783161536Sthomas		return;
784161536Sthomas	}
78577385Sphk
78677385Sphk	printf("media %s", desc->ifmt_string);
78777385Sphk
788114164Ssam	desc = get_mode_desc(ifmw, ttos);
789114164Ssam	if (desc != NULL)
790114164Ssam		printf(" mode %s", desc->ifmt_string);
791114164Ssam
79277385Sphk	/* Find options. */
79377385Sphk	for (i = 0; ttos->options[i].desc != NULL; i++) {
79477385Sphk		if (ttos->options[i].alias)
79577385Sphk			continue;
79677385Sphk		for (desc = ttos->options[i].desc;
79777385Sphk		    desc->ifmt_string != NULL; desc++) {
79877385Sphk			if (ifmw & desc->ifmt_word) {
799215259Smarius				if (seen_option == 0)
800215259Smarius					printf(" mediaopt ");
801215259Smarius				printf("%s%s", seen_option++ ? "," : "",
802215259Smarius				    desc->ifmt_string);
80377385Sphk			}
80477385Sphk		}
80577385Sphk	}
806166113Smarius
807166169Smarius	if (IFM_INST(ifmw) != 0)
808166169Smarius		printf(" instance %d", IFM_INST(ifmw));
80977385Sphk}
81077385Sphk
81125450Speter/**********************************************************************
81225450Speter * ...until here.
81325450Speter **********************************************************************/
814138593Ssam
815138593Ssamstatic struct cmd media_cmds[] = {
816138593Ssam	DEF_CMD_ARG("media",	setmedia),
817138593Ssam	DEF_CMD_ARG("mode",	setmediamode),
818138593Ssam	DEF_CMD_ARG("mediaopt",	setmediaopt),
819138593Ssam	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
820166113Smarius	DEF_CMD_ARG("inst",	setmediainst),
821166113Smarius	DEF_CMD_ARG("instance",	setmediainst),
822138593Ssam};
823138593Ssamstatic struct afswtch af_media = {
824138593Ssam	.af_name	= "af_media",
825138593Ssam	.af_af		= AF_UNSPEC,
826139494Ssam	.af_other_status = media_status,
827138593Ssam};
828138593Ssam
829138593Ssamstatic __constructor void
830138593Ssamifmedia_ctor(void)
831138593Ssam{
832138593Ssam#define	N(a)	(sizeof(a) / sizeof(a[0]))
833194799Sdelphij	size_t i;
834138593Ssam
835138593Ssam	for (i = 0; i < N(media_cmds);  i++)
836138593Ssam		cmd_register(&media_cmds[i]);
837138593Ssam	af_register(&af_media);
838138593Ssam#undef N
839138593Ssam}
840