ifmedia.c revision 170531
1221167Sgnn/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
2221167Sgnn/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 170531 2007-06-11 03:56:33Z sam $ */
3221167Sgnn
4221167Sgnn/*
5221167Sgnn * Copyright (c) 1997 Jason R. Thorpe.
6221167Sgnn * All rights reserved.
7221167Sgnn *
8221167Sgnn * Redistribution and use in source and binary forms, with or without
9221167Sgnn * modification, are permitted provided that the following conditions
10221167Sgnn * are met:
11221167Sgnn * 1. Redistributions of source code must retain the above copyright
12221167Sgnn *    notice, this list of conditions and the following disclaimer.
13221167Sgnn * 2. Redistributions in binary form must reproduce the above copyright
14221167Sgnn *    notice, this list of conditions and the following disclaimer in the
15221167Sgnn *    documentation and/or other materials provided with the distribution.
16221167Sgnn * 3. All advertising materials mentioning features or use of this software
17221167Sgnn *    must display the following acknowledgement:
18221167Sgnn *      This product includes software developed for the NetBSD Project
19221167Sgnn *	by Jason R. Thorpe.
20221167Sgnn * 4. The name of the author may not be used to endorse or promote products
21221167Sgnn *    derived from this software without specific prior written permission.
22221167Sgnn *
23221167Sgnn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24221167Sgnn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25221167Sgnn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26221167Sgnn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27221167Sgnn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28221167Sgnn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29221167Sgnn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30221167Sgnn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31221167Sgnn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32221167Sgnn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33221167Sgnn * SUCH DAMAGE.
34221167Sgnn */
35221167Sgnn
36221167Sgnn/*
37221167Sgnn * Copyright (c) 1983, 1993
38221167Sgnn *	The Regents of the University of California.  All rights reserved.
39221167Sgnn *
40221167Sgnn * Redistribution and use in source and binary forms, with or without
41221167Sgnn * modification, are permitted provided that the following conditions
42221167Sgnn * are met:
43221167Sgnn * 1. Redistributions of source code must retain the above copyright
44221167Sgnn *    notice, this list of conditions and the following disclaimer.
45221167Sgnn * 2. Redistributions in binary form must reproduce the above copyright
46221167Sgnn *    notice, this list of conditions and the following disclaimer in the
47221167Sgnn *    documentation and/or other materials provided with the distribution.
48221167Sgnn * 3. All advertising materials mentioning features or use of this software
49221167Sgnn *    must display the following acknowledgement:
50221167Sgnn *	This product includes software developed by the University of
51221167Sgnn *	California, Berkeley and its contributors.
52221167Sgnn * 4. Neither the name of the University nor the names of its contributors
53221167Sgnn *    may be used to endorse or promote products derived from this software
54221167Sgnn *    without specific prior written permission.
55221167Sgnn *
56221167Sgnn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57221167Sgnn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58221167Sgnn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59221167Sgnn * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60221167Sgnn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61221167Sgnn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62221167Sgnn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63221167Sgnn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64221167Sgnn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65221167Sgnn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66221167Sgnn * SUCH DAMAGE.
67221167Sgnn */
68221167Sgnn
69221167Sgnn#include <sys/param.h>
70221167Sgnn#include <sys/ioctl.h>
71221167Sgnn#include <sys/socket.h>
72221167Sgnn#include <sys/sysctl.h>
73221167Sgnn#include <sys/time.h>
74221167Sgnn
75221167Sgnn#include <net/if.h>
76221167Sgnn#include <net/if_dl.h>
77221167Sgnn#include <net/if_types.h>
78221167Sgnn#include <net/if_media.h>
79221167Sgnn#include <net/route.h>
80221167Sgnn
81221167Sgnn#include <ctype.h>
82221167Sgnn#include <err.h>
83221167Sgnn#include <errno.h>
84221167Sgnn#include <fcntl.h>
85221167Sgnn#include <stdio.h>
86221167Sgnn#include <stdlib.h>
87221167Sgnn#include <string.h>
88221167Sgnn#include <unistd.h>
89221167Sgnn
90221167Sgnn#include "ifconfig.h"
91221167Sgnn
92221167Sgnnstatic void	domediaopt(const char *, int, int);
93221167Sgnnstatic int	get_media_subtype(int, const char *);
94221167Sgnnstatic int	get_media_mode(int, const char *);
95221167Sgnnstatic int	get_media_options(int, const char *);
96221167Sgnnstatic int	lookup_media_word(struct ifmedia_description *, const char *);
97221167Sgnnstatic void	print_media_word(int, int);
98221167Sgnnstatic void	print_media_word_ifconfig(int);
99221167Sgnn
100221167Sgnnstatic struct ifmedia_description *get_toptype_desc(int);
101221167Sgnnstatic struct ifmedia_type_to_subtype *get_toptype_ttos(int);
102221167Sgnnstatic struct ifmedia_description *get_subtype_desc(int,
103221167Sgnn    struct ifmedia_type_to_subtype *ttos);
104221167Sgnn
105221167Sgnnstatic void
106221167Sgnnmedia_status(int s)
107221167Sgnn{
108221167Sgnn	struct ifmediareq ifmr;
109221167Sgnn	int *media_list, i;
110221167Sgnn
111221167Sgnn	(void) memset(&ifmr, 0, sizeof(ifmr));
112221167Sgnn	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
113221167Sgnn
114221167Sgnn	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
115221167Sgnn		/*
116221167Sgnn		 * Interface doesn't support SIOC{G,S}IFMEDIA.
117221167Sgnn		 */
118221167Sgnn		return;
119221167Sgnn	}
120221167Sgnn
121221167Sgnn	if (ifmr.ifm_count == 0) {
122221167Sgnn		warnx("%s: no media types?", name);
123221167Sgnn		return;
124221167Sgnn	}
125221167Sgnn
126221167Sgnn	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
127221167Sgnn	if (media_list == NULL)
128221167Sgnn		err(1, "malloc");
129221167Sgnn	ifmr.ifm_ulist = media_list;
130221167Sgnn
131221167Sgnn	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
132221167Sgnn		err(1, "SIOCGIFMEDIA");
133221167Sgnn
134221167Sgnn	printf("\tmedia: ");
135221167Sgnn	print_media_word(ifmr.ifm_current, 1);
136221167Sgnn	if (ifmr.ifm_active != ifmr.ifm_current) {
137221167Sgnn		putchar(' ');
138221167Sgnn		putchar('(');
139221167Sgnn		print_media_word(ifmr.ifm_active, 0);
140221167Sgnn		putchar(')');
141221167Sgnn	}
142221167Sgnn
143221167Sgnn	putchar('\n');
144221167Sgnn
145221167Sgnn	if (ifmr.ifm_status & IFM_AVALID) {
146221167Sgnn		printf("\tstatus: ");
147221167Sgnn		switch (IFM_TYPE(ifmr.ifm_active)) {
148221167Sgnn		case IFM_ETHER:
149221167Sgnn		case IFM_ATM:
150221167Sgnn			if (ifmr.ifm_status & IFM_ACTIVE)
151221167Sgnn				printf("active");
152221167Sgnn			else
153221167Sgnn				printf("no carrier");
154221167Sgnn			break;
155221167Sgnn
156221167Sgnn		case IFM_FDDI:
157221167Sgnn		case IFM_TOKEN:
158221167Sgnn			if (ifmr.ifm_status & IFM_ACTIVE)
159221167Sgnn				printf("inserted");
160221167Sgnn			else
161221167Sgnn				printf("no ring");
162221167Sgnn			break;
163221167Sgnn
164221167Sgnn		case IFM_IEEE80211:
165221167Sgnn			/* XXX: Different value for adhoc? */
166221167Sgnn			if (ifmr.ifm_status & IFM_ACTIVE)
167221167Sgnn				printf("associated");
168221167Sgnn			else
169221167Sgnn				printf("no carrier");
170221167Sgnn			break;
171221167Sgnn		}
172221167Sgnn		putchar('\n');
173221167Sgnn	}
174221167Sgnn
175221167Sgnn	if (ifmr.ifm_count > 0 && supmedia) {
176221167Sgnn		printf("\tsupported media:\n");
177221167Sgnn		for (i = 0; i < ifmr.ifm_count; i++) {
178221167Sgnn			printf("\t\t");
179221167Sgnn			print_media_word_ifconfig(media_list[i]);
180221167Sgnn			putchar('\n');
181221167Sgnn		}
182221167Sgnn	}
183221167Sgnn
184221167Sgnn	free(media_list);
185221167Sgnn}
186221167Sgnn
187221167Sgnnstruct ifmediareq *
188221167Sgnnifmedia_getstate(int s)
189221167Sgnn{
190221167Sgnn	static struct ifmediareq *ifmr = NULL;
191221167Sgnn	int *mwords;
192221167Sgnn
193221167Sgnn	if (ifmr == NULL) {
194221167Sgnn		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
195221167Sgnn		if (ifmr == NULL)
196221167Sgnn			err(1, "malloc");
197221167Sgnn
198221167Sgnn		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
199221167Sgnn		(void) strncpy(ifmr->ifm_name, name,
200221167Sgnn		    sizeof(ifmr->ifm_name));
201221167Sgnn
202221167Sgnn		ifmr->ifm_count = 0;
203221167Sgnn		ifmr->ifm_ulist = NULL;
204221167Sgnn
205221167Sgnn		/*
206221167Sgnn		 * We must go through the motions of reading all
207221167Sgnn		 * supported media because we need to know both
208221167Sgnn		 * the current media type and the top-level type.
209221167Sgnn		 */
210221167Sgnn
211221167Sgnn		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
212221167Sgnn			err(1, "SIOCGIFMEDIA");
213221167Sgnn		}
214221167Sgnn
215221167Sgnn		if (ifmr->ifm_count == 0)
216221167Sgnn			errx(1, "%s: no media types?", name);
217221167Sgnn
218221167Sgnn		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
219221167Sgnn		if (mwords == NULL)
220221167Sgnn			err(1, "malloc");
221221167Sgnn
222221167Sgnn		ifmr->ifm_ulist = mwords;
223221167Sgnn		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
224221167Sgnn			err(1, "SIOCGIFMEDIA");
225221167Sgnn	}
226221167Sgnn
227221167Sgnn	return ifmr;
228221167Sgnn}
229221167Sgnn
230221167Sgnnstatic void
231221167Sgnnsetifmediacallback(int s, void *arg)
232221167Sgnn{
233221167Sgnn	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
234221167Sgnn	static int did_it = 0;
235221167Sgnn
236221167Sgnn	if (!did_it) {
237221167Sgnn		ifr.ifr_media = ifmr->ifm_current;
238221167Sgnn		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
239221167Sgnn			err(1, "SIOCSIFMEDIA (media)");
240221167Sgnn		free(ifmr->ifm_ulist);
241221167Sgnn		free(ifmr);
242221167Sgnn		did_it = 1;
243221167Sgnn	}
244221167Sgnn}
245221167Sgnn
246221167Sgnnstatic void
247221167Sgnnsetmedia(const char *val, int d, int s, const struct afswtch *afp)
248221167Sgnn{
249221167Sgnn	struct ifmediareq *ifmr;
250221167Sgnn	int subtype;
251221167Sgnn
252221167Sgnn	ifmr = ifmedia_getstate(s);
253221167Sgnn
254221167Sgnn	/*
255221167Sgnn	 * We are primarily concerned with the top-level type.
256221167Sgnn	 * However, "current" may be only IFM_NONE, so we just look
257221167Sgnn	 * for the top-level type in the first "supported type"
258221167Sgnn	 * entry.
259221167Sgnn	 *
260221167Sgnn	 * (I'm assuming that all supported media types for a given
261221167Sgnn	 * interface will be the same top-level type..)
262221167Sgnn	 */
263221167Sgnn	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
264221167Sgnn
265221167Sgnn	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
266221167Sgnn	ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
267221167Sgnn	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
268221167Sgnn
269221167Sgnn	if ((ifr.ifr_media & IFM_TMASK) == 0) {
270221167Sgnn		ifr.ifr_media &= ~IFM_GMASK;
271221167Sgnn	}
272221167Sgnn
273221167Sgnn	ifmr->ifm_current = ifr.ifr_media;
274221167Sgnn	callback_register(setifmediacallback, (void *)ifmr);
275221167Sgnn}
276221167Sgnn
277221167Sgnnstatic void
278221167Sgnnsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
279221167Sgnn{
280221167Sgnn
281221167Sgnn	domediaopt(val, 0, s);
282221167Sgnn}
283221167Sgnn
284221167Sgnnstatic void
285221167Sgnnunsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
286221167Sgnn{
287221167Sgnn
288221167Sgnn	domediaopt(val, 1, s);
289221167Sgnn}
290221167Sgnn
291221167Sgnnstatic void
292221167Sgnndomediaopt(const char *val, int clear, int s)
293221167Sgnn{
294221167Sgnn	struct ifmediareq *ifmr;
295221167Sgnn	int options;
296221167Sgnn
297221167Sgnn	ifmr = ifmedia_getstate(s);
298221167Sgnn
299221167Sgnn	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
300221167Sgnn
301221167Sgnn	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
302221167Sgnn	ifr.ifr_media = ifmr->ifm_current;
303221167Sgnn	if (clear)
304221167Sgnn		ifr.ifr_media &= ~options;
305221167Sgnn	else {
306221167Sgnn		if (options & IFM_HDX) {
307221167Sgnn			ifr.ifr_media &= ~IFM_FDX;
308221167Sgnn			options &= ~IFM_HDX;
309221167Sgnn		}
310221167Sgnn		ifr.ifr_media |= options;
311221167Sgnn	}
312221167Sgnn	ifmr->ifm_current = ifr.ifr_media;
313221167Sgnn	callback_register(setifmediacallback, (void *)ifmr);
314221167Sgnn}
315221167Sgnn
316221167Sgnnstatic void
317221167Sgnnsetmediainst(const char *val, int d, int s, const struct afswtch *afp)
318221167Sgnn{
319221167Sgnn	struct ifmediareq *ifmr;
320221167Sgnn	int inst;
321221167Sgnn
322221167Sgnn	ifmr = ifmedia_getstate(s);
323221167Sgnn
324221167Sgnn	inst = atoi(val);
325221167Sgnn	if (inst < 0 || inst > IFM_INST_MAX)
326221167Sgnn		errx(1, "invalid media instance: %s", val);
327221167Sgnn
328221167Sgnn	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
329221167Sgnn	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
330221167Sgnn
331221167Sgnn	ifmr->ifm_current = ifr.ifr_media;
332221167Sgnn	callback_register(setifmediacallback, (void *)ifmr);
333221167Sgnn}
334221167Sgnn
335221167Sgnnstatic void
336221167Sgnnsetmediamode(const char *val, int d, int s, const struct afswtch *afp)
337221167Sgnn{
338221167Sgnn	struct ifmediareq *ifmr;
339221167Sgnn	int mode;
340221167Sgnn
341221167Sgnn	ifmr = ifmedia_getstate(s);
342221167Sgnn
343221167Sgnn	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
344221167Sgnn
345221167Sgnn	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
346221167Sgnn	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
347221167Sgnn
348221167Sgnn	ifmr->ifm_current = ifr.ifr_media;
349221167Sgnn	callback_register(setifmediacallback, (void *)ifmr);
350221167Sgnn}
351221167Sgnn
352221167Sgnn/**********************************************************************
353221167Sgnn * A good chunk of this is duplicated from sys/net/ifmedia.c
354221167Sgnn **********************************************************************/
355221167Sgnn
356221167Sgnnstatic struct ifmedia_description ifm_type_descriptions[] =
357221167Sgnn    IFM_TYPE_DESCRIPTIONS;
358221167Sgnn
359221167Sgnnstatic struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
360221167Sgnn    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
361221167Sgnn
362221167Sgnnstatic struct ifmedia_description ifm_subtype_ethernet_aliases[] =
363221167Sgnn    IFM_SUBTYPE_ETHERNET_ALIASES;
364221167Sgnn
365221167Sgnnstatic struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
366221167Sgnn    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
367221167Sgnn
368221167Sgnnstatic struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
369221167Sgnn    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
370221167Sgnn
371221167Sgnnstatic struct ifmedia_description ifm_subtype_tokenring_aliases[] =
372221167Sgnn    IFM_SUBTYPE_TOKENRING_ALIASES;
373221167Sgnn
374221167Sgnnstatic struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
375221167Sgnn    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
376221167Sgnn
377221167Sgnnstatic struct ifmedia_description ifm_subtype_fddi_descriptions[] =
378221167Sgnn    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
379221167Sgnn
380221167Sgnnstatic struct ifmedia_description ifm_subtype_fddi_aliases[] =
381221167Sgnn    IFM_SUBTYPE_FDDI_ALIASES;
382221167Sgnn
383221167Sgnnstatic struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
384221167Sgnn    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
385221167Sgnn
386221167Sgnnstatic struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
387221167Sgnn    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
388221167Sgnn
389221167Sgnnstatic struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
390221167Sgnn    IFM_SUBTYPE_IEEE80211_ALIASES;
391221167Sgnn
392221167Sgnnstatic struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
393221167Sgnn    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
394221167Sgnn
395298955Spfgstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
396221167Sgnn    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
397221167Sgnn
398221167Sgnnstruct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
399221167Sgnn    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
400221167Sgnn
401221167Sgnnstatic struct ifmedia_description ifm_subtype_atm_descriptions[] =
402221167Sgnn    IFM_SUBTYPE_ATM_DESCRIPTIONS;
403221167Sgnn
404221167Sgnnstatic struct ifmedia_description ifm_subtype_atm_aliases[] =
405221167Sgnn    IFM_SUBTYPE_ATM_ALIASES;
406221167Sgnn
407221167Sgnnstatic struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
408221167Sgnn    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
409221167Sgnn
410221167Sgnnstatic struct ifmedia_description ifm_subtype_shared_descriptions[] =
411221167Sgnn    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
412221167Sgnn
413221167Sgnnstatic struct ifmedia_description ifm_subtype_shared_aliases[] =
414221167Sgnn    IFM_SUBTYPE_SHARED_ALIASES;
415221167Sgnn
416221167Sgnnstatic struct ifmedia_description ifm_shared_option_descriptions[] =
417221167Sgnn    IFM_SHARED_OPTION_DESCRIPTIONS;
418221167Sgnn
419221167Sgnnstruct ifmedia_type_to_subtype {
420221167Sgnn	struct {
421221167Sgnn		struct ifmedia_description *desc;
422221167Sgnn		int alias;
423221167Sgnn	} subtypes[5];
424221167Sgnn	struct {
425221167Sgnn		struct ifmedia_description *desc;
426221167Sgnn		int alias;
427221167Sgnn	} options[3];
428221167Sgnn	struct {
429221167Sgnn		struct ifmedia_description *desc;
430221167Sgnn		int alias;
431221167Sgnn	} modes[3];
432221167Sgnn};
433221167Sgnn
434221167Sgnn/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
435221167Sgnnstatic struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
436221167Sgnn	{
437221167Sgnn		{
438221167Sgnn			{ &ifm_subtype_shared_descriptions[0], 0 },
439221167Sgnn			{ &ifm_subtype_shared_aliases[0], 1 },
440221167Sgnn			{ &ifm_subtype_ethernet_descriptions[0], 0 },
441221167Sgnn			{ &ifm_subtype_ethernet_aliases[0], 1 },
442221167Sgnn			{ NULL, 0 },
443221167Sgnn		},
444221167Sgnn		{
445221167Sgnn			{ &ifm_shared_option_descriptions[0], 0 },
446221167Sgnn			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
447221167Sgnn			{ NULL, 0 },
448221167Sgnn		},
449221167Sgnn		{
450221167Sgnn			{ NULL, 0 },
451221167Sgnn		},
452221167Sgnn	},
453221167Sgnn	{
454221167Sgnn		{
455221167Sgnn			{ &ifm_subtype_shared_descriptions[0], 0 },
456221167Sgnn			{ &ifm_subtype_shared_aliases[0], 1 },
457221167Sgnn			{ &ifm_subtype_tokenring_descriptions[0], 0 },
458221167Sgnn			{ &ifm_subtype_tokenring_aliases[0], 1 },
459221167Sgnn			{ NULL, 0 },
460221167Sgnn		},
461221167Sgnn		{
462221167Sgnn			{ &ifm_shared_option_descriptions[0], 0 },
463221167Sgnn			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
464221167Sgnn			{ NULL, 0 },
465221167Sgnn		},
466221167Sgnn		{
467221167Sgnn			{ NULL, 0 },
468221167Sgnn		},
469221167Sgnn	},
470221167Sgnn	{
471221167Sgnn		{
472221167Sgnn			{ &ifm_subtype_shared_descriptions[0], 0 },
473221167Sgnn			{ &ifm_subtype_shared_aliases[0], 1 },
474221167Sgnn			{ &ifm_subtype_fddi_descriptions[0], 0 },
475221167Sgnn			{ &ifm_subtype_fddi_aliases[0], 1 },
476221167Sgnn			{ NULL, 0 },
477221167Sgnn		},
478221167Sgnn		{
479221167Sgnn			{ &ifm_shared_option_descriptions[0], 0 },
480221167Sgnn			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
481221167Sgnn			{ NULL, 0 },
482221167Sgnn		},
483221167Sgnn		{
484221167Sgnn			{ NULL, 0 },
485221167Sgnn		},
486221167Sgnn	},
487221167Sgnn	{
488221167Sgnn		{
489221167Sgnn			{ &ifm_subtype_shared_descriptions[0], 0 },
490221167Sgnn			{ &ifm_subtype_shared_aliases[0], 1 },
491298955Spfg			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
492221167Sgnn			{ &ifm_subtype_ieee80211_aliases[0], 1 },
493221167Sgnn			{ NULL, 0 },
494221167Sgnn		},
495221167Sgnn		{
496221167Sgnn			{ &ifm_shared_option_descriptions[0], 0 },
497221167Sgnn			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
498221167Sgnn			{ NULL, 0 },
499221167Sgnn		},
500221167Sgnn		{
501221167Sgnn			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
502221167Sgnn			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
503221167Sgnn			{ NULL, 0 },
504221167Sgnn		},
505221167Sgnn	},
506221167Sgnn	{
507221167Sgnn		{
508221167Sgnn			{ &ifm_subtype_shared_descriptions[0], 0 },
509221167Sgnn			{ &ifm_subtype_shared_aliases[0], 1 },
510221167Sgnn			{ &ifm_subtype_atm_descriptions[0], 0 },
511221167Sgnn			{ &ifm_subtype_atm_aliases[0], 1 },
512221167Sgnn			{ NULL, 0 },
513221167Sgnn		},
514221167Sgnn		{
515221167Sgnn			{ &ifm_shared_option_descriptions[0], 0 },
516221167Sgnn			{ &ifm_subtype_atm_option_descriptions[0], 0 },
517221167Sgnn			{ NULL, 0 },
518221167Sgnn		},
519221167Sgnn		{
520221167Sgnn			{ NULL, 0 },
521221167Sgnn		},
522221167Sgnn	},
523221167Sgnn};
524221167Sgnn
525221167Sgnnstatic int
526221167Sgnnget_media_subtype(int type, const char *val)
527221167Sgnn{
528221167Sgnn	struct ifmedia_description *desc;
529221167Sgnn	struct ifmedia_type_to_subtype *ttos;
530221167Sgnn	int rval, i;
531221167Sgnn
532221167Sgnn	/* Find the top-level interface type. */
533221167Sgnn	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
534221167Sgnn	    desc->ifmt_string != NULL; desc++, ttos++)
535221167Sgnn		if (type == desc->ifmt_word)
536221167Sgnn			break;
537221167Sgnn	if (desc->ifmt_string == NULL)
538221167Sgnn		errx(1, "unknown media type 0x%x", type);
539221167Sgnn
540221167Sgnn	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
541221167Sgnn		rval = lookup_media_word(ttos->subtypes[i].desc, val);
542221167Sgnn		if (rval != -1)
543221167Sgnn			return (rval);
544221167Sgnn	}
545221167Sgnn	errx(1, "unknown media subtype: %s", val);
546221167Sgnn	/*NOTREACHED*/
547221167Sgnn}
548221167Sgnn
549221167Sgnnstatic int
550221167Sgnnget_media_mode(int type, const char *val)
551221167Sgnn{
552221167Sgnn	struct ifmedia_description *desc;
553221167Sgnn	struct ifmedia_type_to_subtype *ttos;
554221167Sgnn	int rval, i;
555221167Sgnn
556221167Sgnn	/* Find the top-level interface type. */
557221167Sgnn	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
558221167Sgnn	    desc->ifmt_string != NULL; desc++, ttos++)
559221167Sgnn		if (type == desc->ifmt_word)
560221167Sgnn			break;
561221167Sgnn	if (desc->ifmt_string == NULL)
562221167Sgnn		errx(1, "unknown media mode 0x%x", type);
563221167Sgnn
564221167Sgnn	for (i = 0; ttos->modes[i].desc != NULL; i++) {
565221167Sgnn		rval = lookup_media_word(ttos->modes[i].desc, val);
566221167Sgnn		if (rval != -1)
567221167Sgnn			return (rval);
568221167Sgnn	}
569221167Sgnn	return -1;
570221167Sgnn}
571221167Sgnn
572221167Sgnnstatic int
573221167Sgnnget_media_options(int type, const char *val)
574221167Sgnn{
575221167Sgnn	struct ifmedia_description *desc;
576221167Sgnn	struct ifmedia_type_to_subtype *ttos;
577221167Sgnn	char *optlist, *optptr;
578221167Sgnn	int option = 0, i, rval = 0;
579221167Sgnn
580221167Sgnn	/* We muck with the string, so copy it. */
581221167Sgnn	optlist = strdup(val);
582221167Sgnn	if (optlist == NULL)
583221167Sgnn		err(1, "strdup");
584221167Sgnn
585221167Sgnn	/* Find the top-level interface type. */
586221167Sgnn	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
587221167Sgnn	    desc->ifmt_string != NULL; desc++, ttos++)
588221167Sgnn		if (type == desc->ifmt_word)
589221167Sgnn			break;
590221167Sgnn	if (desc->ifmt_string == NULL)
591221167Sgnn		errx(1, "unknown media type 0x%x", type);
592221167Sgnn
593221167Sgnn	/*
594221167Sgnn	 * Look up the options in the user-provided comma-separated
595221167Sgnn	 * list.
596221167Sgnn	 */
597221167Sgnn	optptr = optlist;
598221167Sgnn	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
599		for (i = 0; ttos->options[i].desc != NULL; i++) {
600			option = lookup_media_word(ttos->options[i].desc, optptr);
601			if (option != -1)
602				break;
603		}
604		if (option == 0)
605			errx(1, "unknown option: %s", optptr);
606		rval |= option;
607	}
608
609	free(optlist);
610	return (rval);
611}
612
613static int
614lookup_media_word(struct ifmedia_description *desc, const char *val)
615{
616
617	for (; desc->ifmt_string != NULL; desc++)
618		if (strcasecmp(desc->ifmt_string, val) == 0)
619			return (desc->ifmt_word);
620
621	return (-1);
622}
623
624static struct ifmedia_description *get_toptype_desc(int ifmw)
625{
626	struct ifmedia_description *desc;
627
628	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
629		if (IFM_TYPE(ifmw) == desc->ifmt_word)
630			break;
631
632	return desc;
633}
634
635static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
636{
637	struct ifmedia_description *desc;
638	struct ifmedia_type_to_subtype *ttos;
639
640	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
641	    desc->ifmt_string != NULL; desc++, ttos++)
642		if (IFM_TYPE(ifmw) == desc->ifmt_word)
643			break;
644
645	return ttos;
646}
647
648static struct ifmedia_description *get_subtype_desc(int ifmw,
649    struct ifmedia_type_to_subtype *ttos)
650{
651	int i;
652	struct ifmedia_description *desc;
653
654	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
655		if (ttos->subtypes[i].alias)
656			continue;
657		for (desc = ttos->subtypes[i].desc;
658		    desc->ifmt_string != NULL; desc++) {
659			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
660				return desc;
661		}
662	}
663
664	return NULL;
665}
666
667static struct ifmedia_description *get_mode_desc(int ifmw,
668    struct ifmedia_type_to_subtype *ttos)
669{
670	int i;
671	struct ifmedia_description *desc;
672
673	for (i = 0; ttos->modes[i].desc != NULL; i++) {
674		if (ttos->modes[i].alias)
675			continue;
676		for (desc = ttos->modes[i].desc;
677		    desc->ifmt_string != NULL; desc++) {
678			if (IFM_MODE(ifmw) == desc->ifmt_word)
679				return desc;
680		}
681	}
682
683	return NULL;
684}
685
686static void
687print_media_word(int ifmw, int print_toptype)
688{
689	struct ifmedia_description *desc;
690	struct ifmedia_type_to_subtype *ttos;
691	int seen_option = 0, i;
692
693	/* Find the top-level interface type. */
694	desc = get_toptype_desc(ifmw);
695	ttos = get_toptype_ttos(ifmw);
696	if (desc->ifmt_string == NULL) {
697		printf("<unknown type>");
698		return;
699	} else if (print_toptype) {
700		printf("%s", desc->ifmt_string);
701	}
702
703	/*
704	 * Don't print the top-level type; it's not like we can
705	 * change it, or anything.
706	 */
707
708	/* Find subtype. */
709	desc = get_subtype_desc(ifmw, ttos);
710	if (desc == NULL) {
711		printf("<unknown subtype>");
712		return;
713	}
714
715	if (print_toptype)
716		putchar(' ');
717
718	printf("%s", desc->ifmt_string);
719
720	if (print_toptype) {
721		desc = get_mode_desc(ifmw, ttos);
722		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
723			printf(" mode %s", desc->ifmt_string);
724	}
725
726	/* Find options. */
727	for (i = 0; ttos->options[i].desc != NULL; i++) {
728		if (ttos->options[i].alias)
729			continue;
730		for (desc = ttos->options[i].desc;
731		    desc->ifmt_string != NULL; desc++) {
732			if (ifmw & desc->ifmt_word) {
733				if (seen_option == 0)
734					printf(" <");
735				printf("%s%s", seen_option++ ? "," : "",
736				    desc->ifmt_string);
737			}
738		}
739	}
740	printf("%s", seen_option ? ">" : "");
741
742	if (print_toptype && IFM_INST(ifmw) != 0)
743		printf(" instance %d", IFM_INST(ifmw));
744}
745
746static void
747print_media_word_ifconfig(int ifmw)
748{
749	struct ifmedia_description *desc;
750	struct ifmedia_type_to_subtype *ttos;
751	int i;
752
753	/* Find the top-level interface type. */
754	desc = get_toptype_desc(ifmw);
755	ttos = get_toptype_ttos(ifmw);
756	if (desc->ifmt_string == NULL) {
757		printf("<unknown type>");
758		return;
759	}
760
761	/*
762	 * Don't print the top-level type; it's not like we can
763	 * change it, or anything.
764	 */
765
766	/* Find subtype. */
767	desc = get_subtype_desc(ifmw, ttos);
768	if (desc == NULL) {
769		printf("<unknown subtype>");
770		return;
771	}
772
773	printf("media %s", desc->ifmt_string);
774
775	desc = get_mode_desc(ifmw, ttos);
776	if (desc != NULL)
777		printf(" mode %s", desc->ifmt_string);
778
779	/* Find options. */
780	for (i = 0; ttos->options[i].desc != NULL; i++) {
781		if (ttos->options[i].alias)
782			continue;
783		for (desc = ttos->options[i].desc;
784		    desc->ifmt_string != NULL; desc++) {
785			if (ifmw & desc->ifmt_word) {
786				printf(" mediaopt %s", desc->ifmt_string);
787			}
788		}
789	}
790
791	if (IFM_INST(ifmw) != 0)
792		printf(" instance %d", IFM_INST(ifmw));
793}
794
795/**********************************************************************
796 * ...until here.
797 **********************************************************************/
798
799static struct cmd media_cmds[] = {
800	DEF_CMD_ARG("media",	setmedia),
801	DEF_CMD_ARG("mode",	setmediamode),
802	DEF_CMD_ARG("mediaopt",	setmediaopt),
803	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
804	DEF_CMD_ARG("inst",	setmediainst),
805	DEF_CMD_ARG("instance",	setmediainst),
806};
807static struct afswtch af_media = {
808	.af_name	= "af_media",
809	.af_af		= AF_UNSPEC,
810	.af_other_status = media_status,
811};
812
813static __constructor void
814ifmedia_ctor(void)
815{
816#define	N(a)	(sizeof(a) / sizeof(a[0]))
817	int i;
818
819	for (i = 0; i < N(media_cmds);  i++)
820		cmd_register(&media_cmds[i]);
821	af_register(&af_media);
822#undef N
823}
824