ifmedia.c revision 221954
154359Sroberto/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
2285612Sdelphij/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 221954 2011-05-15 12:51:00Z marius $ */
3285612Sdelphij
454359Sroberto/*
575202Sphk * Copyright (c) 1997 Jason R. Thorpe.
654359Sroberto * All rights reserved.
7285612Sdelphij *
854359Sroberto * Redistribution and use in source and binary forms, with or without
954359Sroberto * modification, are permitted provided that the following conditions
10285612Sdelphij * are met:
11285612Sdelphij * 1. Redistributions of source code must retain the above copyright
12285612Sdelphij *    notice, this list of conditions and the following disclaimer.
13285612Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
14285612Sdelphij *    notice, this list of conditions and the following disclaimer in the
15285612Sdelphij *    documentation and/or other materials provided with the distribution.
16285612Sdelphij * 3. All advertising materials mentioning features or use of this software
17285612Sdelphij *    must display the following acknowledgement:
18285612Sdelphij *      This product includes software developed for the NetBSD Project
1954359Sroberto *	by Jason R. Thorpe.
2054359Sroberto * 4. The name of the author may not be used to endorse or promote products
2154359Sroberto *    derived from this software without specific prior written permission.
2254359Sroberto *
23182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2454359Sroberto * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25285612Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26285612Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27285612Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28285612Sdelphij * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29285612Sdelphij * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30285612Sdelphij * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31289997Sglebius * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32285612Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33285612Sdelphij * SUCH DAMAGE.
34285612Sdelphij */
3554359Sroberto
3654359Sroberto/*
3754359Sroberto * Copyright (c) 1983, 1993
3854359Sroberto *	The Regents of the University of California.  All rights reserved.
3954359Sroberto *
4054359Sroberto * Redistribution and use in source and binary forms, with or without
4182502Sroberto * modification, are permitted provided that the following conditions
42285612Sdelphij * are met:
4382502Sroberto * 1. Redistributions of source code must retain the above copyright
44285612Sdelphij *    notice, this list of conditions and the following disclaimer.
4554359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
4654359Sroberto *    notice, this list of conditions and the following disclaimer in the
47285612Sdelphij *    documentation and/or other materials provided with the distribution.
48285612Sdelphij * 4. Neither the name of the University nor the names of its contributors
4954359Sroberto *    may be used to endorse or promote products derived from this software
50285612Sdelphij *    without specific prior written permission.
5154359Sroberto *
5254359Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5354359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55132455Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56285612Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57132455Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58285612Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59285612Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60285612Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61285612Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62285612Sdelphij * SUCH DAMAGE.
63285612Sdelphij */
64285612Sdelphij
65285612Sdelphij#include <sys/param.h>
66285612Sdelphij#include <sys/ioctl.h>
67285612Sdelphij#include <sys/socket.h>
68285612Sdelphij#include <sys/sysctl.h>
69285612Sdelphij#include <sys/time.h>
70285612Sdelphij
71285612Sdelphij#include <net/if.h>
72285612Sdelphij#include <net/if_dl.h>
73285612Sdelphij#include <net/if_types.h>
74285612Sdelphij#include <net/if_media.h>
75285612Sdelphij#include <net/route.h>
76285612Sdelphij
77294569Sdelphij#include <ctype.h>
7854359Sroberto#include <err.h>
79285612Sdelphij#include <errno.h>
8054359Sroberto#include <fcntl.h>
81285612Sdelphij#include <stdio.h>
82285612Sdelphij#include <stdlib.h>
83285612Sdelphij#include <string.h>
84285612Sdelphij#include <unistd.h>
85285612Sdelphij
86285612Sdelphij#include "ifconfig.h"
87285612Sdelphij
88285612Sdelphijstatic void	domediaopt(const char *, int, int);
89285612Sdelphijstatic int	get_media_subtype(int, const char *);
90285612Sdelphijstatic int	get_media_mode(int, const char *);
91285612Sdelphijstatic int	get_media_options(int, const char *);
92285612Sdelphijstatic int	lookup_media_word(struct ifmedia_description *, const char *);
93285612Sdelphijstatic void	print_media_word(int, int);
94285612Sdelphijstatic void	print_media_word_ifconfig(int);
95285612Sdelphij
96285612Sdelphijstatic struct ifmedia_description *get_toptype_desc(int);
97285612Sdelphijstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int);
98285612Sdelphijstatic struct ifmedia_description *get_subtype_desc(int,
99285612Sdelphij    struct ifmedia_type_to_subtype *ttos);
100285612Sdelphij
101285612Sdelphij#define	IFM_OPMODE(x) \
102285612Sdelphij	((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
103285612Sdelphij	 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
104285612Sdelphij	 IFM_IEEE80211_MBSS))
105285612Sdelphij#define	IFM_IEEE80211_STA	0
106285612Sdelphij
107285612Sdelphijstatic void
108285612Sdelphijmedia_status(int s)
109285612Sdelphij{
110285612Sdelphij	struct ifmediareq ifmr;
111285612Sdelphij	int *media_list, i;
112285612Sdelphij
11354359Sroberto	(void) memset(&ifmr, 0, sizeof(ifmr));
114294569Sdelphij	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
115294569Sdelphij
116285612Sdelphij	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
117285612Sdelphij		/*
118285612Sdelphij		 * Interface doesn't support SIOC{G,S}IFMEDIA.
119285612Sdelphij		 */
120285612Sdelphij		return;
121285612Sdelphij	}
122310419Sdelphij
123310419Sdelphij	if (ifmr.ifm_count == 0) {
124285612Sdelphij		warnx("%s: no media types?", name);
125285612Sdelphij		return;
126285612Sdelphij	}
127285612Sdelphij
128285612Sdelphij	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
129310419Sdelphij	if (media_list == NULL)
130285612Sdelphij		err(1, "malloc");
13154359Sroberto	ifmr.ifm_ulist = media_list;
13254359Sroberto
13354359Sroberto	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
134285612Sdelphij		err(1, "SIOCGIFMEDIA");
135285612Sdelphij
136285612Sdelphij	printf("\tmedia: ");
137285612Sdelphij	print_media_word(ifmr.ifm_current, 1);
138285612Sdelphij	if (ifmr.ifm_active != ifmr.ifm_current) {
139285612Sdelphij		putchar(' ');
140285612Sdelphij		putchar('(');
141285612Sdelphij		print_media_word(ifmr.ifm_active, 0);
142285612Sdelphij		putchar(')');
143285612Sdelphij	}
144285612Sdelphij
145285612Sdelphij	putchar('\n');
146285612Sdelphij
147285612Sdelphij	if (ifmr.ifm_status & IFM_AVALID) {
148285612Sdelphij		printf("\tstatus: ");
149285612Sdelphij		switch (IFM_TYPE(ifmr.ifm_active)) {
150285612Sdelphij		case IFM_ETHER:
151285612Sdelphij		case IFM_ATM:
152285612Sdelphij			if (ifmr.ifm_status & IFM_ACTIVE)
153285612Sdelphij				printf("active");
154285612Sdelphij			else
155285612Sdelphij				printf("no carrier");
156285612Sdelphij			break;
157285612Sdelphij
158285612Sdelphij		case IFM_FDDI:
159285612Sdelphij		case IFM_TOKEN:
160285612Sdelphij			if (ifmr.ifm_status & IFM_ACTIVE)
161285612Sdelphij				printf("inserted");
162285612Sdelphij			else
163285612Sdelphij				printf("no ring");
164285612Sdelphij			break;
165285612Sdelphij
166285612Sdelphij		case IFM_IEEE80211:
167285612Sdelphij			if (ifmr.ifm_status & IFM_ACTIVE) {
168285612Sdelphij				/* NB: only sta mode associates */
169285612Sdelphij				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
170285612Sdelphij					printf("associated");
171285612Sdelphij				else
172285612Sdelphij					printf("running");
173285612Sdelphij			} else
174285612Sdelphij				printf("no carrier");
175285612Sdelphij			break;
176285612Sdelphij		}
177285612Sdelphij		putchar('\n');
178285612Sdelphij	}
179330567Sgordon
180330567Sgordon	if (ifmr.ifm_count > 0 && supmedia) {
181330567Sgordon		printf("\tsupported media:\n");
182330567Sgordon		for (i = 0; i < ifmr.ifm_count; i++) {
183330567Sgordon			printf("\t\t");
184330567Sgordon			print_media_word_ifconfig(media_list[i]);
185330567Sgordon			putchar('\n');
186330567Sgordon		}
187330567Sgordon	}
188330567Sgordon
189330567Sgordon	free(media_list);
190330567Sgordon}
191330567Sgordon
192330567Sgordonstruct ifmediareq *
193330567Sgordonifmedia_getstate(int s)
194330567Sgordon{
195330567Sgordon	static struct ifmediareq *ifmr = NULL;
196330567Sgordon	int *mwords;
197330567Sgordon
198330567Sgordon	if (ifmr == NULL) {
199330567Sgordon		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
200330567Sgordon		if (ifmr == NULL)
201330567Sgordon			err(1, "malloc");
202330567Sgordon
203330567Sgordon		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
204330567Sgordon		(void) strncpy(ifmr->ifm_name, name,
205330567Sgordon		    sizeof(ifmr->ifm_name));
206330567Sgordon
207330567Sgordon		ifmr->ifm_count = 0;
208330567Sgordon		ifmr->ifm_ulist = NULL;
209330567Sgordon
210285612Sdelphij		/*
211285612Sdelphij		 * We must go through the motions of reading all
212330567Sgordon		 * supported media because we need to know both
213330567Sgordon		 * the current media type and the top-level type.
214330567Sgordon		 */
215330567Sgordon
216330567Sgordon		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
217330567Sgordon			err(1, "SIOCGIFMEDIA");
218330567Sgordon		}
219330567Sgordon
220330567Sgordon		if (ifmr->ifm_count == 0)
221330567Sgordon			errx(1, "%s: no media types?", name);
222330567Sgordon
223330567Sgordon		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
224330567Sgordon		if (mwords == NULL)
225330567Sgordon			err(1, "malloc");
226330567Sgordon
227330567Sgordon		ifmr->ifm_ulist = mwords;
228330567Sgordon		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
229330567Sgordon			err(1, "SIOCGIFMEDIA");
230330567Sgordon	}
231285612Sdelphij
232285612Sdelphij	return ifmr;
233285612Sdelphij}
234285612Sdelphij
235285612Sdelphijstatic void
236285612Sdelphijsetifmediacallback(int s, void *arg)
237285612Sdelphij{
238285612Sdelphij	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
239285612Sdelphij	static int did_it = 0;
240285612Sdelphij
241285612Sdelphij	if (!did_it) {
242285612Sdelphij		ifr.ifr_media = ifmr->ifm_current;
243285612Sdelphij		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
244285612Sdelphij			err(1, "SIOCSIFMEDIA (media)");
245285612Sdelphij		free(ifmr->ifm_ulist);
246285612Sdelphij		free(ifmr);
247285612Sdelphij		did_it = 1;
248285612Sdelphij	}
249285612Sdelphij}
250285612Sdelphij
251285612Sdelphijstatic void
252285612Sdelphijsetmedia(const char *val, int d, int s, const struct afswtch *afp)
253285612Sdelphij{
254285612Sdelphij	struct ifmediareq *ifmr;
255285612Sdelphij	int subtype;
256285612Sdelphij
257285612Sdelphij	ifmr = ifmedia_getstate(s);
258285612Sdelphij
259285612Sdelphij	/*
260285612Sdelphij	 * We are primarily concerned with the top-level type.
261285612Sdelphij	 * However, "current" may be only IFM_NONE, so we just look
262285612Sdelphij	 * for the top-level type in the first "supported type"
263285612Sdelphij	 * entry.
264285612Sdelphij	 *
265285612Sdelphij	 * (I'm assuming that all supported media types for a given
266285612Sdelphij	 * interface will be the same top-level type..)
267285612Sdelphij	 */
268285612Sdelphij	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
269285612Sdelphij
270285612Sdelphij	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
271285612Sdelphij	ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
272285612Sdelphij	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
273285612Sdelphij
274285612Sdelphij	ifmr->ifm_current = ifr.ifr_media;
275285612Sdelphij	callback_register(setifmediacallback, (void *)ifmr);
276285612Sdelphij}
277285612Sdelphij
278285612Sdelphijstatic void
279285612Sdelphijsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
280285612Sdelphij{
281285612Sdelphij
282285612Sdelphij	domediaopt(val, 0, s);
283285612Sdelphij}
284285612Sdelphij
285285612Sdelphijstatic void
286285612Sdelphijunsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
287285612Sdelphij{
288285612Sdelphij
289285612Sdelphij	domediaopt(val, 1, s);
290285612Sdelphij}
291285612Sdelphij
292285612Sdelphijstatic void
293285612Sdelphijdomediaopt(const char *val, int clear, int s)
294285612Sdelphij{
295285612Sdelphij	struct ifmediareq *ifmr;
296285612Sdelphij	int options;
297285612Sdelphij
298285612Sdelphij	ifmr = ifmedia_getstate(s);
299285612Sdelphij
300285612Sdelphij	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
301285612Sdelphij
302285612Sdelphij	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
303285612Sdelphij	ifr.ifr_media = ifmr->ifm_current;
304285612Sdelphij	if (clear)
305285612Sdelphij		ifr.ifr_media &= ~options;
306285612Sdelphij	else {
307285612Sdelphij		if (options & IFM_HDX) {
308285612Sdelphij			ifr.ifr_media &= ~IFM_FDX;
309285612Sdelphij			options &= ~IFM_HDX;
310285612Sdelphij		}
311285612Sdelphij		ifr.ifr_media |= options;
312285612Sdelphij	}
313285612Sdelphij	ifmr->ifm_current = ifr.ifr_media;
314285612Sdelphij	callback_register(setifmediacallback, (void *)ifmr);
315285612Sdelphij}
316285612Sdelphij
317285612Sdelphijstatic void
318285612Sdelphijsetmediainst(const char *val, int d, int s, const struct afswtch *afp)
319285612Sdelphij{
320285612Sdelphij	struct ifmediareq *ifmr;
321285612Sdelphij	int inst;
322285612Sdelphij
323285612Sdelphij	ifmr = ifmedia_getstate(s);
324285612Sdelphij
325285612Sdelphij	inst = atoi(val);
326285612Sdelphij	if (inst < 0 || inst > (int)IFM_INST_MAX)
327285612Sdelphij		errx(1, "invalid media instance: %s", val);
328285612Sdelphij
329285612Sdelphij	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
330285612Sdelphij	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
331285612Sdelphij
332285612Sdelphij	ifmr->ifm_current = ifr.ifr_media;
33382502Sroberto	callback_register(setifmediacallback, (void *)ifmr);
33482502Sroberto}
33554359Sroberto
336285612Sdelphijstatic void
33754359Srobertosetmediamode(const char *val, int d, int s, const struct afswtch *afp)
33854359Sroberto{
33954359Sroberto	struct ifmediareq *ifmr;
34054359Sroberto	int mode;
34154359Sroberto
342285612Sdelphij	ifmr = ifmedia_getstate(s);
34354359Sroberto
34454359Sroberto	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
345285612Sdelphij
34654359Sroberto	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
347285612Sdelphij	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
348285612Sdelphij
349285612Sdelphij	ifmr->ifm_current = ifr.ifr_media;
350285612Sdelphij	callback_register(setifmediacallback, (void *)ifmr);
351285612Sdelphij}
352285612Sdelphij
353285612Sdelphij/**********************************************************************
354285612Sdelphij * A good chunk of this is duplicated from sys/net/ifmedia.c
355285612Sdelphij **********************************************************************/
356285612Sdelphij
357285612Sdelphijstatic struct ifmedia_description ifm_type_descriptions[] =
358285612Sdelphij    IFM_TYPE_DESCRIPTIONS;
359285612Sdelphij
360285612Sdelphijstatic struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
361285612Sdelphij    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
362285612Sdelphij
363285612Sdelphijstatic struct ifmedia_description ifm_subtype_ethernet_aliases[] =
364285612Sdelphij    IFM_SUBTYPE_ETHERNET_ALIASES;
365285612Sdelphij
366285612Sdelphijstatic struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
367285612Sdelphij    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
368285612Sdelphij
369285612Sdelphijstatic struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
370285612Sdelphij    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
371285612Sdelphij
372285612Sdelphijstatic struct ifmedia_description ifm_subtype_tokenring_aliases[] =
373285612Sdelphij    IFM_SUBTYPE_TOKENRING_ALIASES;
374285612Sdelphij
375285612Sdelphijstatic struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
376285612Sdelphij    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
377285612Sdelphij
378285612Sdelphijstatic struct ifmedia_description ifm_subtype_fddi_descriptions[] =
379285612Sdelphij    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
380285612Sdelphij
381330567Sgordonstatic struct ifmedia_description ifm_subtype_fddi_aliases[] =
382330567Sgordon    IFM_SUBTYPE_FDDI_ALIASES;
383330567Sgordon
384330567Sgordonstatic struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
385330567Sgordon    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
386330567Sgordon
387330567Sgordonstatic struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
388330567Sgordon    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
389330567Sgordon
390330567Sgordonstatic struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
391330567Sgordon    IFM_SUBTYPE_IEEE80211_ALIASES;
392330567Sgordon
393330567Sgordonstatic struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
394330567Sgordon    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
395330567Sgordon
396330567Sgordonstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
397330567Sgordon    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
398330567Sgordon
399330567Sgordonstruct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
400330567Sgordon    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
401330567Sgordon
402330567Sgordonstatic struct ifmedia_description ifm_subtype_atm_descriptions[] =
403330567Sgordon    IFM_SUBTYPE_ATM_DESCRIPTIONS;
404330567Sgordon
405330567Sgordonstatic struct ifmedia_description ifm_subtype_atm_aliases[] =
406330567Sgordon    IFM_SUBTYPE_ATM_ALIASES;
407330567Sgordon
408330567Sgordonstatic struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
409330567Sgordon    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
410330567Sgordon
411330567Sgordonstatic struct ifmedia_description ifm_subtype_shared_descriptions[] =
412330567Sgordon    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
413330567Sgordon
414330567Sgordonstatic struct ifmedia_description ifm_subtype_shared_aliases[] =
415330567Sgordon    IFM_SUBTYPE_SHARED_ALIASES;
416330567Sgordon
417330567Sgordonstatic struct ifmedia_description ifm_shared_option_descriptions[] =
418330567Sgordon    IFM_SHARED_OPTION_DESCRIPTIONS;
419330567Sgordon
420330567Sgordonstatic struct ifmedia_description ifm_shared_option_aliases[] =
421330567Sgordon    IFM_SHARED_OPTION_ALIASES;
422330567Sgordon
423330567Sgordonstruct ifmedia_type_to_subtype {
424330567Sgordon	struct {
425330567Sgordon		struct ifmedia_description *desc;
426330567Sgordon		int alias;
427330567Sgordon	} subtypes[5];
428330567Sgordon	struct {
429289997Sglebius		struct ifmedia_description *desc;
430330567Sgordon		int alias;
431330567Sgordon	} options[4];
432289997Sglebius	struct {
433285612Sdelphij		struct ifmedia_description *desc;
434285612Sdelphij		int alias;
435285612Sdelphij	} modes[3];
436285612Sdelphij};
437285612Sdelphij
438285612Sdelphij/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
439285612Sdelphijstatic struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
440285612Sdelphij	{
441285612Sdelphij		{
442285612Sdelphij			{ &ifm_subtype_shared_descriptions[0], 0 },
443330567Sgordon			{ &ifm_subtype_shared_aliases[0], 1 },
44454359Sroberto			{ &ifm_subtype_ethernet_descriptions[0], 0 },
44554359Sroberto			{ &ifm_subtype_ethernet_aliases[0], 1 },
446285612Sdelphij			{ NULL, 0 },
44754359Sroberto		},
44854359Sroberto		{
44982502Sroberto			{ &ifm_shared_option_descriptions[0], 0 },
45082502Sroberto			{ &ifm_shared_option_aliases[0], 1 },
45154359Sroberto			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
452285612Sdelphij			{ NULL, 0 },
45382502Sroberto		},
45454359Sroberto		{
45554359Sroberto			{ NULL, 0 },
45654359Sroberto		},
45754359Sroberto	},
45854359Sroberto	{
45954359Sroberto		{
46054359Sroberto			{ &ifm_subtype_shared_descriptions[0], 0 },
46154359Sroberto			{ &ifm_subtype_shared_aliases[0], 1 },
46254359Sroberto			{ &ifm_subtype_tokenring_descriptions[0], 0 },
463285612Sdelphij			{ &ifm_subtype_tokenring_aliases[0], 1 },
464285612Sdelphij			{ NULL, 0 },
46554359Sroberto		},
466285612Sdelphij		{
46754359Sroberto			{ &ifm_shared_option_descriptions[0], 0 },
46854359Sroberto			{ &ifm_shared_option_aliases[0], 1 },
46982502Sroberto			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
470182007Sroberto			{ NULL, 0 },
47154359Sroberto		},
472285612Sdelphij		{
473285612Sdelphij			{ NULL, 0 },
474285612Sdelphij		},
475285612Sdelphij	},
476285612Sdelphij	{
477285612Sdelphij		{
478132455Sroberto			{ &ifm_subtype_shared_descriptions[0], 0 },
479285612Sdelphij			{ &ifm_subtype_shared_aliases[0], 1 },
480285612Sdelphij			{ &ifm_subtype_fddi_descriptions[0], 0 },
481132455Sroberto			{ &ifm_subtype_fddi_aliases[0], 1 },
482285612Sdelphij			{ NULL, 0 },
483132455Sroberto		},
484132455Sroberto		{
485285612Sdelphij			{ &ifm_shared_option_descriptions[0], 0 },
48654359Sroberto			{ &ifm_shared_option_aliases[0], 1 },
48754359Sroberto			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
48854359Sroberto			{ NULL, 0 },
48954359Sroberto		},
49054359Sroberto		{
49154359Sroberto			{ NULL, 0 },
49254359Sroberto		},
493285612Sdelphij	},
49482502Sroberto	{
49582502Sroberto		{
49682502Sroberto			{ &ifm_subtype_shared_descriptions[0], 0 },
497285612Sdelphij			{ &ifm_subtype_shared_aliases[0], 1 },
49882502Sroberto			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
49982502Sroberto			{ &ifm_subtype_ieee80211_aliases[0], 1 },
50082502Sroberto			{ NULL, 0 },
50182502Sroberto		},
50282502Sroberto		{
50382502Sroberto			{ &ifm_shared_option_descriptions[0], 0 },
50482502Sroberto			{ &ifm_shared_option_aliases[0], 1 },
50582502Sroberto			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
50682502Sroberto			{ NULL, 0 },
50782502Sroberto		},
50882502Sroberto		{
509285612Sdelphij			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
51082502Sroberto			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
51182502Sroberto			{ NULL, 0 },
51282502Sroberto		},
51382502Sroberto	},
514285612Sdelphij	{
51582502Sroberto		{
516182007Sroberto			{ &ifm_subtype_shared_descriptions[0], 0 },
51782502Sroberto			{ &ifm_subtype_shared_aliases[0], 1 },
51882502Sroberto			{ &ifm_subtype_atm_descriptions[0], 0 },
51982502Sroberto			{ &ifm_subtype_atm_aliases[0], 1 },
52082502Sroberto			{ NULL, 0 },
52182502Sroberto		},
52282502Sroberto		{
523285612Sdelphij			{ &ifm_shared_option_descriptions[0], 0 },
524285612Sdelphij			{ &ifm_shared_option_aliases[0], 1 },
52582502Sroberto			{ &ifm_subtype_atm_option_descriptions[0], 0 },
52682502Sroberto			{ NULL, 0 },
52782502Sroberto		},
528285612Sdelphij		{
52982502Sroberto			{ NULL, 0 },
53082502Sroberto		},
531182007Sroberto	},
532285612Sdelphij};
533285612Sdelphij
534285612Sdelphijstatic int
535285612Sdelphijget_media_subtype(int type, const char *val)
536285612Sdelphij{
537285612Sdelphij	struct ifmedia_description *desc;
538285612Sdelphij	struct ifmedia_type_to_subtype *ttos;
539285612Sdelphij	int rval, i;
540285612Sdelphij
541285612Sdelphij	/* Find the top-level interface type. */
542285612Sdelphij	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
543285612Sdelphij	    desc->ifmt_string != NULL; desc++, ttos++)
544285612Sdelphij		if (type == desc->ifmt_word)
545285612Sdelphij			break;
546285612Sdelphij	if (desc->ifmt_string == NULL)
547285612Sdelphij		errx(1, "unknown media type 0x%x", type);
548285612Sdelphij
549285612Sdelphij	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
550285612Sdelphij		rval = lookup_media_word(ttos->subtypes[i].desc, val);
551285612Sdelphij		if (rval != -1)
552285612Sdelphij			return (rval);
553285612Sdelphij	}
554285612Sdelphij	errx(1, "unknown media subtype: %s", val);
555285612Sdelphij	/*NOTREACHED*/
55654359Sroberto}
55754359Sroberto
55854359Srobertostatic int
55954359Srobertoget_media_mode(int type, const char *val)
56054359Sroberto{
56154359Sroberto	struct ifmedia_description *desc;
562285612Sdelphij	struct ifmedia_type_to_subtype *ttos;
56354359Sroberto	int rval, i;
56454359Sroberto
565285612Sdelphij	/* Find the top-level interface type. */
56654359Sroberto	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
56754359Sroberto	    desc->ifmt_string != NULL; desc++, ttos++)
568285612Sdelphij		if (type == desc->ifmt_word)
569285612Sdelphij			break;
57082502Sroberto	if (desc->ifmt_string == NULL)
57154359Sroberto		errx(1, "unknown media mode 0x%x", type);
57254359Sroberto
57354359Sroberto	for (i = 0; ttos->modes[i].desc != NULL; i++) {
57454359Sroberto		rval = lookup_media_word(ttos->modes[i].desc, val);
57554359Sroberto		if (rval != -1)
576285612Sdelphij			return (rval);
577285612Sdelphij	}
57854359Sroberto	return -1;
579182007Sroberto}
58054359Sroberto
58154359Srobertostatic int
58254359Srobertoget_media_options(int type, const char *val)
58354359Sroberto{
584285612Sdelphij	struct ifmedia_description *desc;
58554359Sroberto	struct ifmedia_type_to_subtype *ttos;
58682502Sroberto	char *optlist, *optptr;
58782502Sroberto	int option = 0, i, rval = 0;
58882502Sroberto
58982502Sroberto	/* We muck with the string, so copy it. */
59082502Sroberto	optlist = strdup(val);
59182502Sroberto	if (optlist == NULL)
59254359Sroberto		err(1, "strdup");
593285612Sdelphij
59454359Sroberto	/* Find the top-level interface type. */
59554359Sroberto	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
59654359Sroberto	    desc->ifmt_string != NULL; desc++, ttos++)
597285612Sdelphij		if (type == desc->ifmt_word)
598132455Sroberto			break;
599285612Sdelphij	if (desc->ifmt_string == NULL)
600285612Sdelphij		errx(1, "unknown media type 0x%x", type);
601182007Sroberto
602285612Sdelphij	/*
603132455Sroberto	 * Look up the options in the user-provided comma-separated
604285612Sdelphij	 * list.
60554359Sroberto	 */
60654359Sroberto	optptr = optlist;
60754359Sroberto	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
60854359Sroberto		for (i = 0; ttos->options[i].desc != NULL; i++) {
60954359Sroberto			option = lookup_media_word(ttos->options[i].desc, optptr);
61054359Sroberto			if (option != -1)
61154359Sroberto				break;
61254359Sroberto		}
613285612Sdelphij		if (option == 0)
61482502Sroberto			errx(1, "unknown option: %s", optptr);
61582502Sroberto		rval |= option;
61682502Sroberto	}
61782502Sroberto
61882502Sroberto	free(optlist);
61982502Sroberto	return (rval);
62082502Sroberto}
62182502Sroberto
62282502Srobertostatic int
62382502Srobertolookup_media_word(struct ifmedia_description *desc, const char *val)
62482502Sroberto{
62582502Sroberto
62682502Sroberto	for (; desc->ifmt_string != NULL; desc++)
62782502Sroberto		if (strcasecmp(desc->ifmt_string, val) == 0)
62882502Sroberto			return (desc->ifmt_word);
62954359Sroberto
63054359Sroberto	return (-1);
63154359Sroberto}
63254359Sroberto
63354359Srobertostatic struct ifmedia_description *get_toptype_desc(int ifmw)
63454359Sroberto{
635285612Sdelphij	struct ifmedia_description *desc;
63654359Sroberto
63782502Sroberto	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
63854359Sroberto		if (IFM_TYPE(ifmw) == desc->ifmt_word)
63954359Sroberto			break;
64054359Sroberto
64154359Sroberto	return desc;
64254359Sroberto}
64354359Sroberto
64454359Srobertostatic struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
64554359Sroberto{
64654359Sroberto	struct ifmedia_description *desc;
64754359Sroberto	struct ifmedia_type_to_subtype *ttos;
64854359Sroberto
64954359Sroberto	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
65054359Sroberto	    desc->ifmt_string != NULL; desc++, ttos++)
65154359Sroberto		if (IFM_TYPE(ifmw) == desc->ifmt_word)
652285612Sdelphij			break;
653285612Sdelphij
654285612Sdelphij	return ttos;
655285612Sdelphij}
656285612Sdelphij
65754359Srobertostatic struct ifmedia_description *get_subtype_desc(int ifmw,
65854359Sroberto    struct ifmedia_type_to_subtype *ttos)
65982502Sroberto{
66054359Sroberto	int i;
66154359Sroberto	struct ifmedia_description *desc;
66254359Sroberto
66382502Sroberto	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
66454359Sroberto		if (ttos->subtypes[i].alias)
66554359Sroberto			continue;
666285612Sdelphij		for (desc = ttos->subtypes[i].desc;
66754359Sroberto		    desc->ifmt_string != NULL; desc++) {
66854359Sroberto			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
669285612Sdelphij				return desc;
670285612Sdelphij		}
67154359Sroberto	}
67254359Sroberto
67354359Sroberto	return NULL;
67454359Sroberto}
67554359Sroberto
67654359Srobertostatic struct ifmedia_description *get_mode_desc(int ifmw,
67782502Sroberto    struct ifmedia_type_to_subtype *ttos)
67882502Sroberto{
67982502Sroberto	int i;
68082502Sroberto	struct ifmedia_description *desc;
68154359Sroberto
68254359Sroberto	for (i = 0; ttos->modes[i].desc != NULL; i++) {
683285612Sdelphij		if (ttos->modes[i].alias)
68454359Sroberto			continue;
68554359Sroberto		for (desc = ttos->modes[i].desc;
68654359Sroberto		    desc->ifmt_string != NULL; desc++) {
68754359Sroberto			if (IFM_MODE(ifmw) == desc->ifmt_word)
68854359Sroberto				return desc;
68954359Sroberto		}
69054359Sroberto	}
69154359Sroberto
69254359Sroberto	return NULL;
69354359Sroberto}
69454359Sroberto
69554359Srobertostatic void
69682502Srobertoprint_media_word(int ifmw, int print_toptype)
69782502Sroberto{
69882502Sroberto	struct ifmedia_description *desc;
69954359Sroberto	struct ifmedia_type_to_subtype *ttos;
700285612Sdelphij	int seen_option = 0, i;
701285612Sdelphij
702285612Sdelphij	/* Find the top-level interface type. */
70354359Sroberto	desc = get_toptype_desc(ifmw);
704285612Sdelphij	ttos = get_toptype_ttos(ifmw);
70554359Sroberto	if (desc->ifmt_string == NULL) {
70654359Sroberto		printf("<unknown type>");
707285612Sdelphij		return;
708285612Sdelphij	} else if (print_toptype) {
70954359Sroberto		printf("%s", desc->ifmt_string);
71054359Sroberto	}
71154359Sroberto
712285612Sdelphij	/*
713285612Sdelphij	 * Don't print the top-level type; it's not like we can
714285612Sdelphij	 * change it, or anything.
71554359Sroberto	 */
716182007Sroberto
717285612Sdelphij	/* Find subtype. */
718285612Sdelphij	desc = get_subtype_desc(ifmw, ttos);
719285612Sdelphij	if (desc == NULL) {
72054359Sroberto		printf("<unknown subtype>");
72154359Sroberto		return;
722285612Sdelphij	}
723285612Sdelphij
72454359Sroberto	if (print_toptype)
725182007Sroberto		putchar(' ');
726182007Sroberto
727285612Sdelphij	printf("%s", desc->ifmt_string);
728285612Sdelphij
729285612Sdelphij	if (print_toptype) {
730285612Sdelphij		desc = get_mode_desc(ifmw, ttos);
731285612Sdelphij		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
732285612Sdelphij			printf(" mode %s", desc->ifmt_string);
73354359Sroberto	}
73454359Sroberto
735182007Sroberto	/* Find options. */
736182007Sroberto	for (i = 0; ttos->options[i].desc != NULL; i++) {
73756746Sroberto		if (ttos->options[i].alias)
738285612Sdelphij			continue;
73956746Sroberto		for (desc = ttos->options[i].desc;
740285612Sdelphij		    desc->ifmt_string != NULL; desc++) {
74182502Sroberto			if (ifmw & desc->ifmt_word) {
742106166Sroberto				if (seen_option == 0)
743106166Sroberto					printf(" <");
744106166Sroberto				printf("%s%s", seen_option++ ? "," : "",
745106427Sroberto				    desc->ifmt_string);
746106427Sroberto			}
747285612Sdelphij		}
748285612Sdelphij	}
74954359Sroberto	printf("%s", seen_option ? ">" : "");
750285612Sdelphij
75154359Sroberto	if (print_toptype && IFM_INST(ifmw) != 0)
75254359Sroberto		printf(" instance %d", IFM_INST(ifmw));
75354359Sroberto}
75454359Sroberto
75554359Srobertostatic void
75682502Srobertoprint_media_word_ifconfig(int ifmw)
75754359Sroberto{
75854359Sroberto	struct ifmedia_description *desc;
75954359Sroberto	struct ifmedia_type_to_subtype *ttos;
76054359Sroberto	int seen_option = 0, i;
76154359Sroberto
76254359Sroberto	/* Find the top-level interface type. */
76354359Sroberto	desc = get_toptype_desc(ifmw);
76454359Sroberto	ttos = get_toptype_ttos(ifmw);
76554359Sroberto	if (desc->ifmt_string == NULL) {
76654359Sroberto		printf("<unknown type>");
76754359Sroberto		return;
76854359Sroberto	}
76954359Sroberto
77054359Sroberto	/*
771285612Sdelphij	 * Don't print the top-level type; it's not like we can
772285612Sdelphij	 * change it, or anything.
77354359Sroberto	 */
77454359Sroberto
775285612Sdelphij	/* Find subtype. */
776285612Sdelphij	desc = get_subtype_desc(ifmw, ttos);
77754359Sroberto	if (desc == NULL) {
778285612Sdelphij		printf("<unknown subtype>");
77954359Sroberto		return;
78054359Sroberto	}
781285612Sdelphij
78254359Sroberto	printf("media %s", desc->ifmt_string);
78354359Sroberto
78454359Sroberto	desc = get_mode_desc(ifmw, ttos);
78582502Sroberto	if (desc != NULL)
78654359Sroberto		printf(" mode %s", desc->ifmt_string);
78754359Sroberto
78854359Sroberto	/* Find options. */
78954359Sroberto	for (i = 0; ttos->options[i].desc != NULL; i++) {
79054359Sroberto		if (ttos->options[i].alias)
79154359Sroberto			continue;
79254359Sroberto		for (desc = ttos->options[i].desc;
79354359Sroberto		    desc->ifmt_string != NULL; desc++) {
79482502Sroberto			if (ifmw & desc->ifmt_word) {
795285612Sdelphij				if (seen_option == 0)
796285612Sdelphij					printf(" mediaopt ");
79754359Sroberto				printf("%s%s", seen_option++ ? "," : "",
79854359Sroberto				    desc->ifmt_string);
79954359Sroberto			}
800285612Sdelphij		}
80154359Sroberto	}
802285612Sdelphij
80354359Sroberto	if (IFM_INST(ifmw) != 0)
80454359Sroberto		printf(" instance %d", IFM_INST(ifmw));
80554359Sroberto}
80654359Sroberto
80782502Sroberto/**********************************************************************
80854359Sroberto * ...until here.
80954359Sroberto **********************************************************************/
81054359Sroberto
811285612Sdelphijstatic struct cmd media_cmds[] = {
81254359Sroberto	DEF_CMD_ARG("media",	setmedia),
81354359Sroberto	DEF_CMD_ARG("mode",	setmediamode),
81454359Sroberto	DEF_CMD_ARG("mediaopt",	setmediaopt),
81554359Sroberto	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
81654359Sroberto	DEF_CMD_ARG("inst",	setmediainst),
81754359Sroberto	DEF_CMD_ARG("instance",	setmediainst),
81854359Sroberto};
819285612Sdelphijstatic struct afswtch af_media = {
820285612Sdelphij	.af_name	= "af_media",
821285612Sdelphij	.af_af		= AF_UNSPEC,
822285612Sdelphij	.af_other_status = media_status,
82354359Sroberto};
82454359Sroberto
82554359Srobertostatic __constructor void
82654359Srobertoifmedia_ctor(void)
82754359Sroberto{
82854359Sroberto#define	N(a)	(sizeof(a) / sizeof(a[0]))
829285612Sdelphij	size_t i;
83054359Sroberto
83154359Sroberto	for (i = 0; i < N(media_cmds);  i++)
83254359Sroberto		cmd_register(&media_cmds[i]);
83354359Sroberto	af_register(&af_media);
83454359Sroberto#undef N
83554359Sroberto}
83654359Sroberto