ifmedia.c revision 140913
125450Speter/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
250476Speter/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 140913 2005-01-27 16:40:12Z ambrisko $ */
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 * 3. All advertising materials mentioning features or use of this software
4925450Speter *    must display the following acknowledgement:
5025450Speter *	This product includes software developed by the University of
5125450Speter *	California, Berkeley and its contributors.
5225450Speter * 4. Neither the name of the University nor the names of its contributors
5325450Speter *    may be used to endorse or promote products derived from this software
5425450Speter *    without specific prior written permission.
5525450Speter *
5625450Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5725450Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5825450Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5925450Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6025450Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6125450Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6225450Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6325450Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6425450Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6525450Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6625450Speter * SUCH DAMAGE.
6725450Speter */
6825450Speter
6925450Speter#include <sys/param.h>
7025450Speter#include <sys/ioctl.h>
7125450Speter#include <sys/socket.h>
7225450Speter#include <sys/sysctl.h>
7325450Speter#include <sys/time.h>
7425450Speter
7525450Speter#include <net/if.h>
7625450Speter#include <net/if_dl.h>
7725450Speter#include <net/if_types.h>
7825450Speter#include <net/if_media.h>
7925450Speter#include <net/route.h>
8025450Speter
8125450Speter#include <ctype.h>
8225450Speter#include <err.h>
8325450Speter#include <errno.h>
8425450Speter#include <fcntl.h>
8525450Speter#include <stdio.h>
8625450Speter#include <stdlib.h>
8725450Speter#include <string.h>
8825450Speter#include <unistd.h>
8925450Speter
9025450Speter#include "ifconfig.h"
9125450Speter
9295005Simpstatic void	domediaopt(const char *, int, int);
9395005Simpstatic int	get_media_subtype(int, const char *);
94114164Ssamstatic int	get_media_mode(int, const char *);
9595005Simpstatic int	get_media_options(int, const char *);
9695005Simpstatic int	lookup_media_word(struct ifmedia_description *, const char *);
9795005Simpstatic void	print_media_word(int, int);
9895005Simpstatic void	print_media_word_ifconfig(int);
9925450Speter
10095005Simpstatic struct ifmedia_description *get_toptype_desc(int);
10195005Simpstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int);
10295005Simpstatic struct ifmedia_description *get_subtype_desc(int,
10395005Simp    struct ifmedia_type_to_subtype *ttos);
10477385Sphk
105138593Ssamstatic void
106139494Ssammedia_status(int s)
10725450Speter{
10825450Speter	struct ifmediareq ifmr;
10925450Speter	int *media_list, i;
11025450Speter
11125450Speter	(void) memset(&ifmr, 0, sizeof(ifmr));
11225450Speter	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
11325450Speter
11425450Speter	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
11525450Speter		/*
11625450Speter		 * Interface doesn't support SIOC{G,S}IFMEDIA.
11725450Speter		 */
11825450Speter		return;
11925450Speter	}
12025450Speter
12125450Speter	if (ifmr.ifm_count == 0) {
12225450Speter		warnx("%s: no media types?", name);
12325450Speter		return;
12425450Speter	}
12525450Speter
12625450Speter	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
12725450Speter	if (media_list == NULL)
12825450Speter		err(1, "malloc");
12925450Speter	ifmr.ifm_ulist = media_list;
13025450Speter
13125450Speter	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
13225450Speter		err(1, "SIOCGIFMEDIA");
13325450Speter
13425450Speter	printf("\tmedia: ");
13577385Sphk	print_media_word(ifmr.ifm_current, 1);
13625450Speter	if (ifmr.ifm_active != ifmr.ifm_current) {
13725450Speter		putchar(' ');
13825450Speter		putchar('(');
13977385Sphk		print_media_word(ifmr.ifm_active, 0);
14025450Speter		putchar(')');
14125450Speter	}
14225450Speter
14377385Sphk	putchar('\n');
14477385Sphk
14525450Speter	if (ifmr.ifm_status & IFM_AVALID) {
14677385Sphk		printf("\tstatus: ");
14725450Speter		switch (IFM_TYPE(ifmr.ifm_active)) {
14825450Speter		case IFM_ETHER:
14925450Speter			if (ifmr.ifm_status & IFM_ACTIVE)
15025450Speter				printf("active");
15125450Speter			else
15225450Speter				printf("no carrier");
15325450Speter			break;
15425450Speter
15525450Speter		case IFM_FDDI:
15625450Speter		case IFM_TOKEN:
15725450Speter			if (ifmr.ifm_status & IFM_ACTIVE)
15825450Speter				printf("inserted");
15925450Speter			else
16025450Speter				printf("no ring");
16125450Speter			break;
162114232Sharti
163114232Sharti		case IFM_ATM:
164114232Sharti			if (ifmr.ifm_status & IFM_ACTIVE)
165114232Sharti				printf("active");
166114232Sharti			else
167114232Sharti				printf("no carrier");
168114232Sharti			break;
169114232Sharti
17077217Sphk		case IFM_IEEE80211:
17177217Sphk			/* XXX: Different value for adhoc? */
17277217Sphk			if (ifmr.ifm_status & IFM_ACTIVE)
17377217Sphk				printf("associated");
17477217Sphk			else
17577217Sphk				printf("no carrier");
17677217Sphk			break;
17725450Speter		}
17885853Syar		putchar('\n');
17925450Speter	}
18025450Speter
18177385Sphk	if (ifmr.ifm_count > 0 && supmedia) {
18277385Sphk		printf("\tsupported media:\n");
18325450Speter		for (i = 0; i < ifmr.ifm_count; i++) {
18477385Sphk			printf("\t\t");
18577385Sphk			print_media_word_ifconfig(media_list[i]);
18677385Sphk			putchar('\n');
18725450Speter		}
18825450Speter	}
18925450Speter
19025450Speter	free(media_list);
19125450Speter}
19225450Speter
193140913Sambriskostatic struct ifmediareq *
194140913Sambriskogetifmediastate(int s)
19525450Speter{
196140913Sambrisko	static struct ifmediareq *ifmr = NULL;
197140913Sambrisko	int *mwords;
19825450Speter
199140913Sambrisko	if (ifmr == NULL) {
200140913Sambrisko		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
201140913Sambrisko		if (ifmr == NULL)
202140913Sambrisko			err(1, "malloc");
20325450Speter
204140913Sambrisko		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
205140913Sambrisko		(void) strncpy(ifmr->ifm_name, name,
206140913Sambrisko		    sizeof(ifmr->ifm_name));
207140913Sambrisko
208140913Sambrisko		ifmr->ifm_count = 0;
209140913Sambrisko		ifmr->ifm_ulist = NULL;
210140913Sambrisko
21125450Speter		/*
212140913Sambrisko		 * We must go through the motions of reading all
213140913Sambrisko		 * supported media because we need to know both
214140913Sambrisko		 * the current media type and the top-level type.
21525450Speter		 */
216140913Sambrisko
217140913Sambrisko		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
21825450Speter			err(1, "SIOCGIFMEDIA");
219140913Sambrisko		}
220140913Sambrisko
221140913Sambrisko		if (ifmr->ifm_count == 0)
222140913Sambrisko			errx(1, "%s: no media types?", name);
223140913Sambrisko
224140913Sambrisko		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
225140913Sambrisko		if (mwords == NULL)
226140913Sambrisko			err(1, "malloc");
227140913Sambrisko
228140913Sambrisko		ifmr->ifm_ulist = mwords;
229140913Sambrisko		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
230140913Sambrisko			err(1, "SIOCGIFMEDIA");
23125450Speter	}
23225450Speter
233140913Sambrisko	return ifmr;
234140913Sambrisko}
23525450Speter
236140913Sambriskostatic void
237140913Sambriskosetifmediacallback(int s, void *arg)
238140913Sambrisko{
239140913Sambrisko	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
240140913Sambrisko	static int did_it = 0;
241140913Sambrisko
242140913Sambrisko	if (!did_it) {
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
257140913Sambrisko
258140913Sambrisko	ifmr = getifmediastate(s);
259140913Sambrisko
26025450Speter	/*
26125450Speter	 * We are primarily concerned with the top-level type.
26225450Speter	 * However, "current" may be only IFM_NONE, so we just look
26325450Speter	 * for the top-level type in the first "supported type"
26425450Speter	 * entry.
26525450Speter	 *
26625450Speter	 * (I'm assuming that all supported media types for a given
26725450Speter	 * interface will be the same top-level type..)
26825450Speter	 */
269140913Sambrisko	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
27025450Speter
27125450Speter	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
272140913Sambrisko	ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
273140913Sambrisko	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
27425450Speter
275140913Sambrisko	if ((ifr.ifr_media & IFM_TMASK) == 0) {
276140913Sambrisko		ifr.ifr_media &= ~IFM_GMASK;
277140913Sambrisko	}
278140913Sambrisko
279140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
280140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
28125450Speter}
28225450Speter
283138593Ssamstatic void
28495005Simpsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
28525450Speter{
28625450Speter
28725450Speter	domediaopt(val, 0, s);
28825450Speter}
28925450Speter
290138593Ssamstatic void
29195005Simpunsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
29225450Speter{
29325450Speter
29425450Speter	domediaopt(val, 1, s);
29525450Speter}
29625450Speter
29725450Speterstatic void
29895005Simpdomediaopt(const char *val, int clear, int s)
29925450Speter{
300140913Sambrisko	struct ifmediareq *ifmr;
301140913Sambrisko	int options;
30225450Speter
303140913Sambrisko	ifmr = getifmediastate(s);
30425450Speter
305140913Sambrisko	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
30625450Speter
30725450Speter	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
308140913Sambrisko	ifr.ifr_media = ifmr->ifm_current;
30925450Speter	if (clear)
31025450Speter		ifr.ifr_media &= ~options;
31125450Speter	else
31225450Speter		ifr.ifr_media |= options;
31325450Speter
314140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
315140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
31625450Speter}
31725450Speter
318114164Ssam
319138593Ssamstatic void
320114164Ssamsetmediamode(const char *val, int d, int s, const struct afswtch *afp)
321114164Ssam{
322140913Sambrisko	struct ifmediareq *ifmr;
323140913Sambrisko	int mode;
324114164Ssam
325140913Sambrisko	ifmr = getifmediastate(s);
326114164Ssam
327140913Sambrisko	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
328114164Ssam
329114164Ssam	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
330140913Sambrisko	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
331114164Ssam
332140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
333140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
334114164Ssam}
335114164Ssam
33625450Speter/**********************************************************************
33725450Speter * A good chunk of this is duplicated from sys/net/ifmedia.c
33825450Speter **********************************************************************/
33925450Speter
34025450Speterstatic struct ifmedia_description ifm_type_descriptions[] =
34125450Speter    IFM_TYPE_DESCRIPTIONS;
34225450Speter
34325450Speterstatic struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
34425450Speter    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
34525450Speter
34625450Speterstatic struct ifmedia_description ifm_subtype_ethernet_aliases[] =
34725450Speter    IFM_SUBTYPE_ETHERNET_ALIASES;
34825450Speter
34925450Speterstatic struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
35025450Speter    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
35125450Speter
35225450Speterstatic struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
35325450Speter    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
35425450Speter
35525450Speterstatic struct ifmedia_description ifm_subtype_tokenring_aliases[] =
35625450Speter    IFM_SUBTYPE_TOKENRING_ALIASES;
35725450Speter
35825450Speterstatic struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
35925450Speter    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
36025450Speter
36125450Speterstatic struct ifmedia_description ifm_subtype_fddi_descriptions[] =
36225450Speter    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
36325450Speter
36425450Speterstatic struct ifmedia_description ifm_subtype_fddi_aliases[] =
36525450Speter    IFM_SUBTYPE_FDDI_ALIASES;
36625450Speter
36725450Speterstatic struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
36825450Speter    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
36925450Speter
37077217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
37177217Sphk    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
37277217Sphk
37377217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
37477217Sphk    IFM_SUBTYPE_IEEE80211_ALIASES;
37577217Sphk
37677217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
37777217Sphk    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
37877217Sphk
379114164Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
380114164Ssam    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
381114164Ssam
382116820Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
383116820Ssam    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
384116820Ssam
385114232Shartistatic struct ifmedia_description ifm_subtype_atm_descriptions[] =
386114232Sharti    IFM_SUBTYPE_ATM_DESCRIPTIONS;
387114232Sharti
388114232Shartistatic struct ifmedia_description ifm_subtype_atm_aliases[] =
389114232Sharti    IFM_SUBTYPE_ATM_ALIASES;
390114232Sharti
391114232Shartistatic struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
392114232Sharti    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
393114232Sharti
39425450Speterstatic struct ifmedia_description ifm_subtype_shared_descriptions[] =
39525450Speter    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
39625450Speter
39725450Speterstatic struct ifmedia_description ifm_subtype_shared_aliases[] =
39825450Speter    IFM_SUBTYPE_SHARED_ALIASES;
39925450Speter
40025450Speterstatic struct ifmedia_description ifm_shared_option_descriptions[] =
40125450Speter    IFM_SHARED_OPTION_DESCRIPTIONS;
40225450Speter
40325450Speterstruct ifmedia_type_to_subtype {
40425450Speter	struct {
40525450Speter		struct ifmedia_description *desc;
40625450Speter		int alias;
40725450Speter	} subtypes[5];
40825450Speter	struct {
40925450Speter		struct ifmedia_description *desc;
41025450Speter		int alias;
41125450Speter	} options[3];
412114164Ssam	struct {
413114164Ssam		struct ifmedia_description *desc;
414114164Ssam		int alias;
415116820Ssam	} modes[3];
41625450Speter};
41725450Speter
41825450Speter/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
41925450Speterstatic struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
42025450Speter	{
42125450Speter		{
42225450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
42325450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
42425450Speter			{ &ifm_subtype_ethernet_descriptions[0], 0 },
42525450Speter			{ &ifm_subtype_ethernet_aliases[0], 1 },
42625450Speter			{ NULL, 0 },
42725450Speter		},
42825450Speter		{
42925450Speter			{ &ifm_shared_option_descriptions[0], 0 },
43077217Sphk			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
43125450Speter			{ NULL, 0 },
43225450Speter		},
433114164Ssam		{
434114164Ssam			{ NULL, 0 },
435114164Ssam		},
43625450Speter	},
43725450Speter	{
43825450Speter		{
43925450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
44025450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
44125450Speter			{ &ifm_subtype_tokenring_descriptions[0], 0 },
44225450Speter			{ &ifm_subtype_tokenring_aliases[0], 1 },
44325450Speter			{ NULL, 0 },
44425450Speter		},
44525450Speter		{
44625450Speter			{ &ifm_shared_option_descriptions[0], 0 },
44777217Sphk			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
44825450Speter			{ NULL, 0 },
44925450Speter		},
450114164Ssam		{
451114164Ssam			{ NULL, 0 },
452114164Ssam		},
45325450Speter	},
45425450Speter	{
45525450Speter		{
45625450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
45725450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
45825450Speter			{ &ifm_subtype_fddi_descriptions[0], 0 },
45925450Speter			{ &ifm_subtype_fddi_aliases[0], 1 },
46025450Speter			{ NULL, 0 },
46125450Speter		},
46225450Speter		{
46325450Speter			{ &ifm_shared_option_descriptions[0], 0 },
46477217Sphk			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
46525450Speter			{ NULL, 0 },
46625450Speter		},
467114164Ssam		{
468114164Ssam			{ NULL, 0 },
469114164Ssam		},
47025450Speter	},
47177217Sphk	{
47277217Sphk		{
47377217Sphk			{ &ifm_subtype_shared_descriptions[0], 0 },
47477217Sphk			{ &ifm_subtype_shared_aliases[0], 1 },
47577217Sphk			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
47677217Sphk			{ &ifm_subtype_ieee80211_aliases[0], 1 },
47777217Sphk			{ NULL, 0 },
47877217Sphk		},
47977217Sphk		{
48077217Sphk			{ &ifm_shared_option_descriptions[0], 0 },
48177217Sphk			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
48277217Sphk			{ NULL, 0 },
48377217Sphk		},
484114164Ssam		{
485114164Ssam			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
486116820Ssam			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
487114164Ssam			{ NULL, 0 },
488114164Ssam		},
48977217Sphk	},
490114232Sharti	{
491114232Sharti		{
492114232Sharti			{ &ifm_subtype_shared_descriptions[0], 0 },
493114232Sharti			{ &ifm_subtype_shared_aliases[0], 1 },
494114232Sharti			{ &ifm_subtype_atm_descriptions[0], 0 },
495114232Sharti			{ &ifm_subtype_atm_aliases[0], 1 },
496114232Sharti			{ NULL, 0 },
497114232Sharti		},
498114232Sharti		{
499114232Sharti			{ &ifm_shared_option_descriptions[0], 0 },
500114232Sharti			{ &ifm_subtype_atm_option_descriptions[0], 0 },
501114232Sharti			{ NULL, 0 },
502114232Sharti		},
503114232Sharti		{
504114232Sharti			{ NULL, 0 },
505114232Sharti		},
506114232Sharti	},
50725450Speter};
50825450Speter
50925450Speterstatic int
51095005Simpget_media_subtype(int type, const char *val)
51125450Speter{
51225450Speter	struct ifmedia_description *desc;
51325450Speter	struct ifmedia_type_to_subtype *ttos;
51425450Speter	int rval, i;
51525450Speter
51625450Speter	/* Find the top-level interface type. */
51725450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
51825450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
51925450Speter		if (type == desc->ifmt_word)
52025450Speter			break;
52125450Speter	if (desc->ifmt_string == NULL)
52225450Speter		errx(1, "unknown media type 0x%x", type);
52325450Speter
52425450Speter	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
52525450Speter		rval = lookup_media_word(ttos->subtypes[i].desc, val);
52625450Speter		if (rval != -1)
52725450Speter			return (rval);
52825450Speter	}
52925450Speter	errx(1, "unknown media subtype: %s", val);
530114164Ssam	/*NOTREACHED*/
53125450Speter}
53225450Speter
53325450Speterstatic int
534114164Ssamget_media_mode(int type, const char *val)
535114164Ssam{
536114164Ssam	struct ifmedia_description *desc;
537114164Ssam	struct ifmedia_type_to_subtype *ttos;
538114164Ssam	int rval, i;
539114164Ssam
540114164Ssam	/* Find the top-level interface type. */
541114164Ssam	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
542114164Ssam	    desc->ifmt_string != NULL; desc++, ttos++)
543114164Ssam		if (type == desc->ifmt_word)
544114164Ssam			break;
545114164Ssam	if (desc->ifmt_string == NULL)
546114164Ssam		errx(1, "unknown media mode 0x%x", type);
547114164Ssam
548114164Ssam	for (i = 0; ttos->modes[i].desc != NULL; i++) {
549114164Ssam		rval = lookup_media_word(ttos->modes[i].desc, val);
550114164Ssam		if (rval != -1)
551114164Ssam			return (rval);
552114164Ssam	}
553114164Ssam	return -1;
554114164Ssam}
555114164Ssam
556114164Ssamstatic int
55795005Simpget_media_options(int type, const char *val)
55825450Speter{
55925450Speter	struct ifmedia_description *desc;
56025450Speter	struct ifmedia_type_to_subtype *ttos;
56125450Speter	char *optlist, *optptr;
56225450Speter	int option = 0, i, rval = 0;
56325450Speter
56425450Speter	/* We muck with the string, so copy it. */
56525450Speter	optlist = strdup(val);
56625450Speter	if (optlist == NULL)
56725450Speter		err(1, "strdup");
56825450Speter
56925450Speter	/* Find the top-level interface type. */
57025450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
57125450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
57225450Speter		if (type == desc->ifmt_word)
57325450Speter			break;
57425450Speter	if (desc->ifmt_string == NULL)
57525450Speter		errx(1, "unknown media type 0x%x", type);
57625450Speter
57725450Speter	/*
57825450Speter	 * Look up the options in the user-provided comma-separated
57925450Speter	 * list.
58025450Speter	 */
58125450Speter	optptr = optlist;
58225450Speter	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
58325450Speter		for (i = 0; ttos->options[i].desc != NULL; i++) {
58425450Speter			option = lookup_media_word(ttos->options[i].desc, optptr);
58525450Speter			if (option != -1)
58625450Speter				break;
58725450Speter		}
58825450Speter		if (option == 0)
58925450Speter			errx(1, "unknown option: %s", optptr);
59025450Speter		rval |= option;
59125450Speter	}
59225450Speter
59325450Speter	free(optlist);
59425450Speter	return (rval);
59525450Speter}
59625450Speter
59725450Speterstatic int
59895005Simplookup_media_word(struct ifmedia_description *desc, const char *val)
59925450Speter{
60025450Speter
60125450Speter	for (; desc->ifmt_string != NULL; desc++)
60225450Speter		if (strcasecmp(desc->ifmt_string, val) == 0)
60325450Speter			return (desc->ifmt_word);
60425450Speter
60525450Speter	return (-1);
60625450Speter}
60725450Speter
60895005Simpstatic struct ifmedia_description *get_toptype_desc(int ifmw)
60925450Speter{
61025450Speter	struct ifmedia_description *desc;
61177385Sphk
61277385Sphk	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
61377385Sphk		if (IFM_TYPE(ifmw) == desc->ifmt_word)
61477385Sphk			break;
61577385Sphk
61677385Sphk	return desc;
61777385Sphk}
61877385Sphk
61995005Simpstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
62077385Sphk{
62177385Sphk	struct ifmedia_description *desc;
62225450Speter	struct ifmedia_type_to_subtype *ttos;
62325450Speter
62425450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
62525450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
62625450Speter		if (IFM_TYPE(ifmw) == desc->ifmt_word)
62725450Speter			break;
62877385Sphk
62977385Sphk	return ttos;
63077385Sphk}
63177385Sphk
63295005Simpstatic struct ifmedia_description *get_subtype_desc(int ifmw,
63395005Simp    struct ifmedia_type_to_subtype *ttos)
63477385Sphk{
63577385Sphk	int i;
63677385Sphk	struct ifmedia_description *desc;
63777385Sphk
63877385Sphk	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
63977385Sphk		if (ttos->subtypes[i].alias)
64077385Sphk			continue;
64177385Sphk		for (desc = ttos->subtypes[i].desc;
64277385Sphk		    desc->ifmt_string != NULL; desc++) {
64377385Sphk			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
64477385Sphk				return desc;
64577385Sphk		}
64677385Sphk	}
64777385Sphk
64877385Sphk	return NULL;
64977385Sphk}
65077385Sphk
651114164Ssamstatic struct ifmedia_description *get_mode_desc(int ifmw,
652114164Ssam    struct ifmedia_type_to_subtype *ttos)
653114164Ssam{
654114164Ssam	int i;
655114164Ssam	struct ifmedia_description *desc;
656114164Ssam
657114164Ssam	for (i = 0; ttos->modes[i].desc != NULL; i++) {
658114164Ssam		if (ttos->modes[i].alias)
659114164Ssam			continue;
660114164Ssam		for (desc = ttos->modes[i].desc;
661114164Ssam		    desc->ifmt_string != NULL; desc++) {
662114164Ssam			if (IFM_MODE(ifmw) == desc->ifmt_word)
663114164Ssam				return desc;
664114164Ssam		}
665114164Ssam	}
666114164Ssam
667114164Ssam	return NULL;
668114164Ssam}
669114164Ssam
67077385Sphkstatic void
67195005Simpprint_media_word(int ifmw, int print_toptype)
67277385Sphk{
67377385Sphk	struct ifmedia_description *desc;
67477385Sphk	struct ifmedia_type_to_subtype *ttos;
67577385Sphk	int seen_option = 0, i;
67677385Sphk
67777385Sphk	/* Find the top-level interface type. */
67877385Sphk	desc = get_toptype_desc(ifmw);
67977385Sphk	ttos = get_toptype_ttos(ifmw);
68025450Speter	if (desc->ifmt_string == NULL) {
68125450Speter		printf("<unknown type>");
68225450Speter		return;
68377385Sphk	} else if (print_toptype) {
68477385Sphk		printf("%s", desc->ifmt_string);
68525450Speter	}
68625450Speter
68725450Speter	/*
68825450Speter	 * Don't print the top-level type; it's not like we can
68925450Speter	 * change it, or anything.
69025450Speter	 */
69125450Speter
69225450Speter	/* Find subtype. */
69377385Sphk	desc = get_subtype_desc(ifmw, ttos);
69477385Sphk	if (desc != NULL)
69577385Sphk		goto got_subtype;
69625450Speter
69725450Speter	/* Falling to here means unknown subtype. */
69825450Speter	printf("<unknown subtype>");
69925450Speter	return;
70025450Speter
70125450Speter got_subtype:
70277385Sphk	if (print_toptype)
70377385Sphk		putchar(' ');
70477385Sphk
70525450Speter	printf("%s", desc->ifmt_string);
70625450Speter
707114164Ssam	if (print_toptype) {
708114164Ssam		desc = get_mode_desc(ifmw, ttos);
709116820Ssam		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
710114164Ssam			printf(" mode %s", desc->ifmt_string);
711114164Ssam	}
712114164Ssam
71325450Speter	/* Find options. */
71425450Speter	for (i = 0; ttos->options[i].desc != NULL; i++) {
71525450Speter		if (ttos->options[i].alias)
71625450Speter			continue;
71725450Speter		for (desc = ttos->options[i].desc;
71825450Speter		    desc->ifmt_string != NULL; desc++) {
71925450Speter			if (ifmw & desc->ifmt_word) {
72025450Speter				if (seen_option == 0)
72125450Speter					printf(" <");
72225450Speter				printf("%s%s", seen_option++ ? "," : "",
72325450Speter				    desc->ifmt_string);
72425450Speter			}
72525450Speter		}
72625450Speter	}
72725450Speter	printf("%s", seen_option ? ">" : "");
72825450Speter}
72925450Speter
73077385Sphkstatic void
73195005Simpprint_media_word_ifconfig(int ifmw)
73277385Sphk{
73377385Sphk	struct ifmedia_description *desc;
73477385Sphk	struct ifmedia_type_to_subtype *ttos;
73577385Sphk	int i;
73677385Sphk
73777385Sphk	/* Find the top-level interface type. */
73877385Sphk	desc = get_toptype_desc(ifmw);
73977385Sphk	ttos = get_toptype_ttos(ifmw);
74077385Sphk	if (desc->ifmt_string == NULL) {
74177385Sphk		printf("<unknown type>");
74277385Sphk		return;
74377385Sphk	}
74477385Sphk
74577385Sphk	/*
74677385Sphk	 * Don't print the top-level type; it's not like we can
74777385Sphk	 * change it, or anything.
74877385Sphk	 */
74977385Sphk
75077385Sphk	/* Find subtype. */
75177385Sphk	desc = get_subtype_desc(ifmw, ttos);
75277385Sphk	if (desc != NULL)
75377385Sphk		goto got_subtype;
75477385Sphk
75577385Sphk	/* Falling to here means unknown subtype. */
75677385Sphk	printf("<unknown subtype>");
75777385Sphk	return;
75877385Sphk
75977385Sphk got_subtype:
76077385Sphk	printf("media %s", desc->ifmt_string);
76177385Sphk
762114164Ssam	desc = get_mode_desc(ifmw, ttos);
763114164Ssam	if (desc != NULL)
764114164Ssam		printf(" mode %s", desc->ifmt_string);
765114164Ssam
76677385Sphk	/* Find options. */
76777385Sphk	for (i = 0; ttos->options[i].desc != NULL; i++) {
76877385Sphk		if (ttos->options[i].alias)
76977385Sphk			continue;
77077385Sphk		for (desc = ttos->options[i].desc;
77177385Sphk		    desc->ifmt_string != NULL; desc++) {
77277385Sphk			if (ifmw & desc->ifmt_word) {
77377385Sphk				printf(" mediaopt %s", desc->ifmt_string);
77477385Sphk			}
77577385Sphk		}
77677385Sphk	}
77777385Sphk}
77877385Sphk
77925450Speter/**********************************************************************
78025450Speter * ...until here.
78125450Speter **********************************************************************/
782138593Ssam
783138593Ssamstatic struct cmd media_cmds[] = {
784138593Ssam	DEF_CMD_ARG("media",	setmedia),
785138593Ssam	DEF_CMD_ARG("mode",	setmediamode),
786138593Ssam	DEF_CMD_ARG("mediaopt",	setmediaopt),
787138593Ssam	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
788138593Ssam};
789138593Ssamstatic struct afswtch af_media = {
790138593Ssam	.af_name	= "af_media",
791138593Ssam	.af_af		= AF_UNSPEC,
792139494Ssam	.af_other_status = media_status,
793138593Ssam};
794138593Ssam
795138593Ssamstatic __constructor void
796138593Ssamifmedia_ctor(void)
797138593Ssam{
798138593Ssam#define	N(a)	(sizeof(a) / sizeof(a[0]))
799138593Ssam	int i;
800138593Ssam
801138593Ssam	for (i = 0; i < N(media_cmds);  i++)
802138593Ssam		cmd_register(&media_cmds[i]);
803138593Ssam	af_register(&af_media);
804138593Ssam#undef N
805138593Ssam}
806