ifmedia.c revision 331722
125450Speter/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
250476Speter/* $FreeBSD: stable/11/sbin/ifconfig/ifmedia.c 331722 2018-03-29 02:50:57Z eadler $ */
325450Speter
4331722Seadler/*
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;
112281236Serj	int xmedia = 1;
11325450Speter
11425450Speter	(void) memset(&ifmr, 0, sizeof(ifmr));
115299873Struckman	(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
11625450Speter
117281236Serj	/*
118281236Serj	 * Check if interface supports extended media types.
119281236Serj	 */
120281236Serj	if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
121281236Serj		xmedia = 0;
122281236Serj	if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
12325450Speter		/*
12425450Speter		 * Interface doesn't support SIOC{G,S}IFMEDIA.
12525450Speter		 */
12625450Speter		return;
12725450Speter	}
12825450Speter
12925450Speter	if (ifmr.ifm_count == 0) {
13025450Speter		warnx("%s: no media types?", name);
13125450Speter		return;
13225450Speter	}
13325450Speter
13425450Speter	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
13525450Speter	if (media_list == NULL)
13625450Speter		err(1, "malloc");
13725450Speter	ifmr.ifm_ulist = media_list;
13825450Speter
139281236Serj	if (xmedia) {
140281236Serj		if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
141281236Serj			err(1, "SIOCGIFXMEDIA");
142281236Serj	} else {
143281236Serj		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
144281236Serj			err(1, "SIOCGIFMEDIA");
145281236Serj	}
14625450Speter
14725450Speter	printf("\tmedia: ");
14877385Sphk	print_media_word(ifmr.ifm_current, 1);
14925450Speter	if (ifmr.ifm_active != ifmr.ifm_current) {
15025450Speter		putchar(' ');
15125450Speter		putchar('(');
15277385Sphk		print_media_word(ifmr.ifm_active, 0);
15325450Speter		putchar(')');
15425450Speter	}
15525450Speter
15677385Sphk	putchar('\n');
15777385Sphk
15825450Speter	if (ifmr.ifm_status & IFM_AVALID) {
15977385Sphk		printf("\tstatus: ");
16025450Speter		switch (IFM_TYPE(ifmr.ifm_active)) {
16125450Speter		case IFM_ETHER:
162161536Sthomas		case IFM_ATM:
16325450Speter			if (ifmr.ifm_status & IFM_ACTIVE)
16425450Speter				printf("active");
16525450Speter			else
16625450Speter				printf("no carrier");
16725450Speter			break;
16825450Speter
16925450Speter		case IFM_FDDI:
17025450Speter		case IFM_TOKEN:
17125450Speter			if (ifmr.ifm_status & IFM_ACTIVE)
17225450Speter				printf("inserted");
17325450Speter			else
17425450Speter				printf("no ring");
17525450Speter			break;
176114232Sharti
17777217Sphk		case IFM_IEEE80211:
178178354Ssam			if (ifmr.ifm_status & IFM_ACTIVE) {
179178354Ssam				/* NB: only sta mode associates */
180178354Ssam				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
181178354Ssam					printf("associated");
182178354Ssam				else
183178354Ssam					printf("running");
184178354Ssam			} else
18577217Sphk				printf("no carrier");
18677217Sphk			break;
18725450Speter		}
18885853Syar		putchar('\n');
18925450Speter	}
19025450Speter
19177385Sphk	if (ifmr.ifm_count > 0 && supmedia) {
19277385Sphk		printf("\tsupported media:\n");
19325450Speter		for (i = 0; i < ifmr.ifm_count; i++) {
19477385Sphk			printf("\t\t");
19577385Sphk			print_media_word_ifconfig(media_list[i]);
19677385Sphk			putchar('\n');
19725450Speter		}
19825450Speter	}
19925450Speter
20025450Speter	free(media_list);
20125450Speter}
20225450Speter
203170531Ssamstruct ifmediareq *
204170531Ssamifmedia_getstate(int s)
20525450Speter{
206140913Sambrisko	static struct ifmediareq *ifmr = NULL;
207140913Sambrisko	int *mwords;
208281236Serj	int xmedia = 1;
20925450Speter
210140913Sambrisko	if (ifmr == NULL) {
211140913Sambrisko		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
212140913Sambrisko		if (ifmr == NULL)
213140913Sambrisko			err(1, "malloc");
21425450Speter
215140913Sambrisko		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
216299873Struckman		(void) strlcpy(ifmr->ifm_name, name,
217140913Sambrisko		    sizeof(ifmr->ifm_name));
218140913Sambrisko
219140913Sambrisko		ifmr->ifm_count = 0;
220140913Sambrisko		ifmr->ifm_ulist = NULL;
221140913Sambrisko
22225450Speter		/*
223140913Sambrisko		 * We must go through the motions of reading all
224140913Sambrisko		 * supported media because we need to know both
225140913Sambrisko		 * the current media type and the top-level type.
22625450Speter		 */
227140913Sambrisko
228281236Serj		if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) {
229281236Serj			xmedia = 0;
230281236Serj		}
231281236Serj		if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
23225450Speter			err(1, "SIOCGIFMEDIA");
233140913Sambrisko		}
234140913Sambrisko
235140913Sambrisko		if (ifmr->ifm_count == 0)
236140913Sambrisko			errx(1, "%s: no media types?", name);
237140913Sambrisko
238140913Sambrisko		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
239140913Sambrisko		if (mwords == NULL)
240140913Sambrisko			err(1, "malloc");
241140913Sambrisko
242140913Sambrisko		ifmr->ifm_ulist = mwords;
243281236Serj		if (xmedia) {
244281236Serj			if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0)
245281236Serj				err(1, "SIOCGIFXMEDIA");
246281236Serj		} else {
247281236Serj			if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
248281236Serj				err(1, "SIOCGIFMEDIA");
249281236Serj		}
25025450Speter	}
25125450Speter
252140913Sambrisko	return ifmr;
253140913Sambrisko}
25425450Speter
255140913Sambriskostatic void
256140913Sambriskosetifmediacallback(int s, void *arg)
257140913Sambrisko{
258140913Sambrisko	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
259140913Sambrisko	static int did_it = 0;
260140913Sambrisko
261140913Sambrisko	if (!did_it) {
262154240Sambrisko		ifr.ifr_media = ifmr->ifm_current;
263140913Sambrisko		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
264140913Sambrisko			err(1, "SIOCSIFMEDIA (media)");
265140913Sambrisko		free(ifmr->ifm_ulist);
266140913Sambrisko		free(ifmr);
267140913Sambrisko		did_it = 1;
268140913Sambrisko	}
269140913Sambrisko}
270140913Sambrisko
271140913Sambriskostatic void
272140913Sambriskosetmedia(const char *val, int d, int s, const struct afswtch *afp)
273140913Sambrisko{
274140913Sambrisko	struct ifmediareq *ifmr;
275140913Sambrisko	int subtype;
276140913Sambrisko
277170531Ssam	ifmr = ifmedia_getstate(s);
278140913Sambrisko
27925450Speter	/*
28025450Speter	 * We are primarily concerned with the top-level type.
28125450Speter	 * However, "current" may be only IFM_NONE, so we just look
28225450Speter	 * for the top-level type in the first "supported type"
28325450Speter	 * entry.
28425450Speter	 *
28525450Speter	 * (I'm assuming that all supported media types for a given
28625450Speter	 * interface will be the same top-level type..)
28725450Speter	 */
288140913Sambrisko	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
28925450Speter
290299873Struckman	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
291221954Smarius	ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
292140913Sambrisko	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
29325450Speter
294140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
295140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
29625450Speter}
29725450Speter
298138593Ssamstatic void
29995005Simpsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
30025450Speter{
30125450Speter
30225450Speter	domediaopt(val, 0, s);
30325450Speter}
30425450Speter
305138593Ssamstatic void
30695005Simpunsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
30725450Speter{
30825450Speter
30925450Speter	domediaopt(val, 1, s);
31025450Speter}
31125450Speter
31225450Speterstatic void
31395005Simpdomediaopt(const char *val, int clear, int s)
31425450Speter{
315140913Sambrisko	struct ifmediareq *ifmr;
316140913Sambrisko	int options;
31725450Speter
318170531Ssam	ifmr = ifmedia_getstate(s);
31925450Speter
320140913Sambrisko	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
32125450Speter
322299873Struckman	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
323140913Sambrisko	ifr.ifr_media = ifmr->ifm_current;
32425450Speter	if (clear)
32525450Speter		ifr.ifr_media &= ~options;
326165359Sjkim	else {
327165359Sjkim		if (options & IFM_HDX) {
328165359Sjkim			ifr.ifr_media &= ~IFM_FDX;
329165359Sjkim			options &= ~IFM_HDX;
330165359Sjkim		}
33125450Speter		ifr.ifr_media |= options;
332165359Sjkim	}
333140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
334140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
33525450Speter}
33625450Speter
337166113Smariusstatic void
338166113Smariussetmediainst(const char *val, int d, int s, const struct afswtch *afp)
339166113Smarius{
340166113Smarius	struct ifmediareq *ifmr;
341166113Smarius	int inst;
342114164Ssam
343170531Ssam	ifmr = ifmedia_getstate(s);
344166113Smarius
345166113Smarius	inst = atoi(val);
346194799Sdelphij	if (inst < 0 || inst > (int)IFM_INST_MAX)
347166113Smarius		errx(1, "invalid media instance: %s", val);
348166113Smarius
349299873Struckman	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
350166113Smarius	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
351166113Smarius
352166113Smarius	ifmr->ifm_current = ifr.ifr_media;
353166113Smarius	callback_register(setifmediacallback, (void *)ifmr);
354166113Smarius}
355166113Smarius
356138593Ssamstatic void
357114164Ssamsetmediamode(const char *val, int d, int s, const struct afswtch *afp)
358114164Ssam{
359140913Sambrisko	struct ifmediareq *ifmr;
360140913Sambrisko	int mode;
361114164Ssam
362170531Ssam	ifmr = ifmedia_getstate(s);
363114164Ssam
364140913Sambrisko	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
365114164Ssam
366299873Struckman	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
367140913Sambrisko	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
368114164Ssam
369140913Sambrisko	ifmr->ifm_current = ifr.ifr_media;
370140913Sambrisko	callback_register(setifmediacallback, (void *)ifmr);
371114164Ssam}
372114164Ssam
37325450Speter/**********************************************************************
37425450Speter * A good chunk of this is duplicated from sys/net/ifmedia.c
37525450Speter **********************************************************************/
37625450Speter
37725450Speterstatic struct ifmedia_description ifm_type_descriptions[] =
37825450Speter    IFM_TYPE_DESCRIPTIONS;
37925450Speter
38025450Speterstatic struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
38125450Speter    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
38225450Speter
38325450Speterstatic struct ifmedia_description ifm_subtype_ethernet_aliases[] =
38425450Speter    IFM_SUBTYPE_ETHERNET_ALIASES;
38525450Speter
38625450Speterstatic struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
38725450Speter    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
38825450Speter
38925450Speterstatic struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
39025450Speter    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
39125450Speter
39225450Speterstatic struct ifmedia_description ifm_subtype_tokenring_aliases[] =
39325450Speter    IFM_SUBTYPE_TOKENRING_ALIASES;
39425450Speter
39525450Speterstatic struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
39625450Speter    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
39725450Speter
39825450Speterstatic struct ifmedia_description ifm_subtype_fddi_descriptions[] =
39925450Speter    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
40025450Speter
40125450Speterstatic struct ifmedia_description ifm_subtype_fddi_aliases[] =
40225450Speter    IFM_SUBTYPE_FDDI_ALIASES;
40325450Speter
40425450Speterstatic struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
40525450Speter    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
40625450Speter
40777217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
40877217Sphk    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
40977217Sphk
41077217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
41177217Sphk    IFM_SUBTYPE_IEEE80211_ALIASES;
41277217Sphk
41377217Sphkstatic struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
41477217Sphk    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
41577217Sphk
416114164Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
417114164Ssam    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
418114164Ssam
419116820Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
420116820Ssam    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
421116820Ssam
422114232Shartistatic struct ifmedia_description ifm_subtype_atm_descriptions[] =
423114232Sharti    IFM_SUBTYPE_ATM_DESCRIPTIONS;
424114232Sharti
425114232Shartistatic struct ifmedia_description ifm_subtype_atm_aliases[] =
426114232Sharti    IFM_SUBTYPE_ATM_ALIASES;
427114232Sharti
428114232Shartistatic struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
429114232Sharti    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
430114232Sharti
43125450Speterstatic struct ifmedia_description ifm_subtype_shared_descriptions[] =
43225450Speter    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
43325450Speter
43425450Speterstatic struct ifmedia_description ifm_subtype_shared_aliases[] =
43525450Speter    IFM_SUBTYPE_SHARED_ALIASES;
43625450Speter
43725450Speterstatic struct ifmedia_description ifm_shared_option_descriptions[] =
43825450Speter    IFM_SHARED_OPTION_DESCRIPTIONS;
43925450Speter
440217013Smariusstatic struct ifmedia_description ifm_shared_option_aliases[] =
441217013Smarius    IFM_SHARED_OPTION_ALIASES;
442217013Smarius
44325450Speterstruct ifmedia_type_to_subtype {
44425450Speter	struct {
44525450Speter		struct ifmedia_description *desc;
44625450Speter		int alias;
44725450Speter	} subtypes[5];
44825450Speter	struct {
44925450Speter		struct ifmedia_description *desc;
45025450Speter		int alias;
451217013Smarius	} options[4];
452114164Ssam	struct {
453114164Ssam		struct ifmedia_description *desc;
454114164Ssam		int alias;
455116820Ssam	} modes[3];
45625450Speter};
45725450Speter
45825450Speter/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
45925450Speterstatic struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
46025450Speter	{
46125450Speter		{
46225450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
46325450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
46425450Speter			{ &ifm_subtype_ethernet_descriptions[0], 0 },
46525450Speter			{ &ifm_subtype_ethernet_aliases[0], 1 },
46625450Speter			{ NULL, 0 },
46725450Speter		},
46825450Speter		{
46925450Speter			{ &ifm_shared_option_descriptions[0], 0 },
470217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
47177217Sphk			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
47225450Speter			{ NULL, 0 },
47325450Speter		},
474114164Ssam		{
475114164Ssam			{ NULL, 0 },
476114164Ssam		},
47725450Speter	},
47825450Speter	{
47925450Speter		{
48025450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
48125450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
48225450Speter			{ &ifm_subtype_tokenring_descriptions[0], 0 },
48325450Speter			{ &ifm_subtype_tokenring_aliases[0], 1 },
48425450Speter			{ NULL, 0 },
48525450Speter		},
48625450Speter		{
48725450Speter			{ &ifm_shared_option_descriptions[0], 0 },
488217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
48977217Sphk			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
49025450Speter			{ NULL, 0 },
49125450Speter		},
492114164Ssam		{
493114164Ssam			{ NULL, 0 },
494114164Ssam		},
49525450Speter	},
49625450Speter	{
49725450Speter		{
49825450Speter			{ &ifm_subtype_shared_descriptions[0], 0 },
49925450Speter			{ &ifm_subtype_shared_aliases[0], 1 },
50025450Speter			{ &ifm_subtype_fddi_descriptions[0], 0 },
50125450Speter			{ &ifm_subtype_fddi_aliases[0], 1 },
50225450Speter			{ NULL, 0 },
50325450Speter		},
50425450Speter		{
50525450Speter			{ &ifm_shared_option_descriptions[0], 0 },
506217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
50777217Sphk			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
50825450Speter			{ NULL, 0 },
50925450Speter		},
510114164Ssam		{
511114164Ssam			{ NULL, 0 },
512114164Ssam		},
51325450Speter	},
51477217Sphk	{
51577217Sphk		{
51677217Sphk			{ &ifm_subtype_shared_descriptions[0], 0 },
51777217Sphk			{ &ifm_subtype_shared_aliases[0], 1 },
51877217Sphk			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
51977217Sphk			{ &ifm_subtype_ieee80211_aliases[0], 1 },
52077217Sphk			{ NULL, 0 },
52177217Sphk		},
52277217Sphk		{
52377217Sphk			{ &ifm_shared_option_descriptions[0], 0 },
524217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
52577217Sphk			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
52677217Sphk			{ NULL, 0 },
52777217Sphk		},
528114164Ssam		{
529114164Ssam			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
530116820Ssam			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
531114164Ssam			{ NULL, 0 },
532114164Ssam		},
53377217Sphk	},
534114232Sharti	{
535114232Sharti		{
536114232Sharti			{ &ifm_subtype_shared_descriptions[0], 0 },
537114232Sharti			{ &ifm_subtype_shared_aliases[0], 1 },
538114232Sharti			{ &ifm_subtype_atm_descriptions[0], 0 },
539114232Sharti			{ &ifm_subtype_atm_aliases[0], 1 },
540114232Sharti			{ NULL, 0 },
541114232Sharti		},
542114232Sharti		{
543114232Sharti			{ &ifm_shared_option_descriptions[0], 0 },
544217013Smarius			{ &ifm_shared_option_aliases[0], 1 },
545114232Sharti			{ &ifm_subtype_atm_option_descriptions[0], 0 },
546114232Sharti			{ NULL, 0 },
547114232Sharti		},
548114232Sharti		{
549114232Sharti			{ NULL, 0 },
550114232Sharti		},
551114232Sharti	},
55225450Speter};
55325450Speter
55425450Speterstatic int
55595005Simpget_media_subtype(int type, const char *val)
55625450Speter{
55725450Speter	struct ifmedia_description *desc;
55825450Speter	struct ifmedia_type_to_subtype *ttos;
55925450Speter	int rval, i;
56025450Speter
56125450Speter	/* Find the top-level interface type. */
56225450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
56325450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
56425450Speter		if (type == desc->ifmt_word)
56525450Speter			break;
56625450Speter	if (desc->ifmt_string == NULL)
56725450Speter		errx(1, "unknown media type 0x%x", type);
56825450Speter
56925450Speter	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
57025450Speter		rval = lookup_media_word(ttos->subtypes[i].desc, val);
57125450Speter		if (rval != -1)
57225450Speter			return (rval);
57325450Speter	}
57425450Speter	errx(1, "unknown media subtype: %s", val);
575114164Ssam	/*NOTREACHED*/
57625450Speter}
57725450Speter
57825450Speterstatic int
579114164Ssamget_media_mode(int type, const char *val)
580114164Ssam{
581114164Ssam	struct ifmedia_description *desc;
582114164Ssam	struct ifmedia_type_to_subtype *ttos;
583114164Ssam	int rval, i;
584114164Ssam
585114164Ssam	/* Find the top-level interface type. */
586114164Ssam	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
587114164Ssam	    desc->ifmt_string != NULL; desc++, ttos++)
588114164Ssam		if (type == desc->ifmt_word)
589114164Ssam			break;
590114164Ssam	if (desc->ifmt_string == NULL)
591114164Ssam		errx(1, "unknown media mode 0x%x", type);
592114164Ssam
593114164Ssam	for (i = 0; ttos->modes[i].desc != NULL; i++) {
594114164Ssam		rval = lookup_media_word(ttos->modes[i].desc, val);
595114164Ssam		if (rval != -1)
596114164Ssam			return (rval);
597114164Ssam	}
598114164Ssam	return -1;
599114164Ssam}
600114164Ssam
601114164Ssamstatic int
60295005Simpget_media_options(int type, const char *val)
60325450Speter{
60425450Speter	struct ifmedia_description *desc;
60525450Speter	struct ifmedia_type_to_subtype *ttos;
60625450Speter	char *optlist, *optptr;
60725450Speter	int option = 0, i, rval = 0;
60825450Speter
60925450Speter	/* We muck with the string, so copy it. */
61025450Speter	optlist = strdup(val);
61125450Speter	if (optlist == NULL)
61225450Speter		err(1, "strdup");
61325450Speter
61425450Speter	/* Find the top-level interface type. */
61525450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
61625450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
61725450Speter		if (type == desc->ifmt_word)
61825450Speter			break;
61925450Speter	if (desc->ifmt_string == NULL)
62025450Speter		errx(1, "unknown media type 0x%x", type);
62125450Speter
62225450Speter	/*
62325450Speter	 * Look up the options in the user-provided comma-separated
62425450Speter	 * list.
62525450Speter	 */
62625450Speter	optptr = optlist;
62725450Speter	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
62825450Speter		for (i = 0; ttos->options[i].desc != NULL; i++) {
62925450Speter			option = lookup_media_word(ttos->options[i].desc, optptr);
63025450Speter			if (option != -1)
63125450Speter				break;
63225450Speter		}
63325450Speter		if (option == 0)
63425450Speter			errx(1, "unknown option: %s", optptr);
63525450Speter		rval |= option;
63625450Speter	}
63725450Speter
63825450Speter	free(optlist);
63925450Speter	return (rval);
64025450Speter}
64125450Speter
64225450Speterstatic int
64395005Simplookup_media_word(struct ifmedia_description *desc, const char *val)
64425450Speter{
64525450Speter
64625450Speter	for (; desc->ifmt_string != NULL; desc++)
64725450Speter		if (strcasecmp(desc->ifmt_string, val) == 0)
64825450Speter			return (desc->ifmt_word);
64925450Speter
65025450Speter	return (-1);
65125450Speter}
65225450Speter
65395005Simpstatic struct ifmedia_description *get_toptype_desc(int ifmw)
65425450Speter{
65525450Speter	struct ifmedia_description *desc;
65677385Sphk
65777385Sphk	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
65877385Sphk		if (IFM_TYPE(ifmw) == desc->ifmt_word)
65977385Sphk			break;
66077385Sphk
66177385Sphk	return desc;
66277385Sphk}
66377385Sphk
66495005Simpstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
66577385Sphk{
66677385Sphk	struct ifmedia_description *desc;
66725450Speter	struct ifmedia_type_to_subtype *ttos;
66825450Speter
66925450Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
67025450Speter	    desc->ifmt_string != NULL; desc++, ttos++)
67125450Speter		if (IFM_TYPE(ifmw) == desc->ifmt_word)
67225450Speter			break;
67377385Sphk
67477385Sphk	return ttos;
67577385Sphk}
67677385Sphk
67795005Simpstatic struct ifmedia_description *get_subtype_desc(int ifmw,
67895005Simp    struct ifmedia_type_to_subtype *ttos)
67977385Sphk{
68077385Sphk	int i;
68177385Sphk	struct ifmedia_description *desc;
68277385Sphk
68377385Sphk	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
68477385Sphk		if (ttos->subtypes[i].alias)
68577385Sphk			continue;
68677385Sphk		for (desc = ttos->subtypes[i].desc;
68777385Sphk		    desc->ifmt_string != NULL; desc++) {
68877385Sphk			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
68977385Sphk				return desc;
69077385Sphk		}
69177385Sphk	}
69277385Sphk
69377385Sphk	return NULL;
69477385Sphk}
69577385Sphk
696114164Ssamstatic struct ifmedia_description *get_mode_desc(int ifmw,
697114164Ssam    struct ifmedia_type_to_subtype *ttos)
698114164Ssam{
699114164Ssam	int i;
700114164Ssam	struct ifmedia_description *desc;
701114164Ssam
702114164Ssam	for (i = 0; ttos->modes[i].desc != NULL; i++) {
703114164Ssam		if (ttos->modes[i].alias)
704114164Ssam			continue;
705114164Ssam		for (desc = ttos->modes[i].desc;
706114164Ssam		    desc->ifmt_string != NULL; desc++) {
707114164Ssam			if (IFM_MODE(ifmw) == desc->ifmt_word)
708114164Ssam				return desc;
709114164Ssam		}
710114164Ssam	}
711114164Ssam
712114164Ssam	return NULL;
713114164Ssam}
714114164Ssam
71577385Sphkstatic void
71695005Simpprint_media_word(int ifmw, int print_toptype)
71777385Sphk{
71877385Sphk	struct ifmedia_description *desc;
71977385Sphk	struct ifmedia_type_to_subtype *ttos;
72077385Sphk	int seen_option = 0, i;
72177385Sphk
72277385Sphk	/* Find the top-level interface type. */
72377385Sphk	desc = get_toptype_desc(ifmw);
72477385Sphk	ttos = get_toptype_ttos(ifmw);
72525450Speter	if (desc->ifmt_string == NULL) {
72625450Speter		printf("<unknown type>");
72725450Speter		return;
72877385Sphk	} else if (print_toptype) {
72977385Sphk		printf("%s", desc->ifmt_string);
73025450Speter	}
73125450Speter
73225450Speter	/*
73325450Speter	 * Don't print the top-level type; it's not like we can
73425450Speter	 * change it, or anything.
73525450Speter	 */
73625450Speter
73725450Speter	/* Find subtype. */
73877385Sphk	desc = get_subtype_desc(ifmw, ttos);
739161536Sthomas	if (desc == NULL) {
740161536Sthomas		printf("<unknown subtype>");
741161536Sthomas		return;
742161536Sthomas	}
74325450Speter
74477385Sphk	if (print_toptype)
74577385Sphk		putchar(' ');
74677385Sphk
74725450Speter	printf("%s", desc->ifmt_string);
74825450Speter
749114164Ssam	if (print_toptype) {
750114164Ssam		desc = get_mode_desc(ifmw, ttos);
751116820Ssam		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
752114164Ssam			printf(" mode %s", desc->ifmt_string);
753114164Ssam	}
754114164Ssam
75525450Speter	/* Find options. */
75625450Speter	for (i = 0; ttos->options[i].desc != NULL; i++) {
75725450Speter		if (ttos->options[i].alias)
75825450Speter			continue;
75925450Speter		for (desc = ttos->options[i].desc;
76025450Speter		    desc->ifmt_string != NULL; desc++) {
76125450Speter			if (ifmw & desc->ifmt_word) {
76225450Speter				if (seen_option == 0)
76325450Speter					printf(" <");
76425450Speter				printf("%s%s", seen_option++ ? "," : "",
76525450Speter				    desc->ifmt_string);
76625450Speter			}
76725450Speter		}
76825450Speter	}
76925450Speter	printf("%s", seen_option ? ">" : "");
770166113Smarius
771166169Smarius	if (print_toptype && IFM_INST(ifmw) != 0)
772166113Smarius		printf(" instance %d", IFM_INST(ifmw));
77325450Speter}
77425450Speter
77577385Sphkstatic void
77695005Simpprint_media_word_ifconfig(int ifmw)
77777385Sphk{
77877385Sphk	struct ifmedia_description *desc;
77977385Sphk	struct ifmedia_type_to_subtype *ttos;
780215259Smarius	int seen_option = 0, i;
78177385Sphk
78277385Sphk	/* Find the top-level interface type. */
78377385Sphk	desc = get_toptype_desc(ifmw);
78477385Sphk	ttos = get_toptype_ttos(ifmw);
78577385Sphk	if (desc->ifmt_string == NULL) {
78677385Sphk		printf("<unknown type>");
78777385Sphk		return;
78877385Sphk	}
78977385Sphk
79077385Sphk	/*
79177385Sphk	 * Don't print the top-level type; it's not like we can
79277385Sphk	 * change it, or anything.
79377385Sphk	 */
79477385Sphk
79577385Sphk	/* Find subtype. */
79677385Sphk	desc = get_subtype_desc(ifmw, ttos);
797161536Sthomas	if (desc == NULL) {
798161536Sthomas		printf("<unknown subtype>");
799161536Sthomas		return;
800161536Sthomas	}
80177385Sphk
80277385Sphk	printf("media %s", desc->ifmt_string);
80377385Sphk
804114164Ssam	desc = get_mode_desc(ifmw, ttos);
805114164Ssam	if (desc != NULL)
806114164Ssam		printf(" mode %s", desc->ifmt_string);
807114164Ssam
80877385Sphk	/* Find options. */
80977385Sphk	for (i = 0; ttos->options[i].desc != NULL; i++) {
81077385Sphk		if (ttos->options[i].alias)
81177385Sphk			continue;
81277385Sphk		for (desc = ttos->options[i].desc;
81377385Sphk		    desc->ifmt_string != NULL; desc++) {
81477385Sphk			if (ifmw & desc->ifmt_word) {
815215259Smarius				if (seen_option == 0)
816215259Smarius					printf(" mediaopt ");
817215259Smarius				printf("%s%s", seen_option++ ? "," : "",
818215259Smarius				    desc->ifmt_string);
81977385Sphk			}
82077385Sphk		}
82177385Sphk	}
822166113Smarius
823166169Smarius	if (IFM_INST(ifmw) != 0)
824166169Smarius		printf(" instance %d", IFM_INST(ifmw));
82577385Sphk}
82677385Sphk
82725450Speter/**********************************************************************
82825450Speter * ...until here.
82925450Speter **********************************************************************/
830138593Ssam
831138593Ssamstatic struct cmd media_cmds[] = {
832138593Ssam	DEF_CMD_ARG("media",	setmedia),
833138593Ssam	DEF_CMD_ARG("mode",	setmediamode),
834138593Ssam	DEF_CMD_ARG("mediaopt",	setmediaopt),
835138593Ssam	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
836166113Smarius	DEF_CMD_ARG("inst",	setmediainst),
837166113Smarius	DEF_CMD_ARG("instance",	setmediainst),
838138593Ssam};
839138593Ssamstatic struct afswtch af_media = {
840138593Ssam	.af_name	= "af_media",
841138593Ssam	.af_af		= AF_UNSPEC,
842139494Ssam	.af_other_status = media_status,
843138593Ssam};
844138593Ssam
845138593Ssamstatic __constructor void
846138593Ssamifmedia_ctor(void)
847138593Ssam{
848194799Sdelphij	size_t i;
849138593Ssam
850288305Sngie	for (i = 0; i < nitems(media_cmds);  i++)
851138593Ssam		cmd_register(&media_cmds[i]);
852138593Ssam	af_register(&af_media);
853138593Ssam}
854