if_media.c revision 218909
1109998Smarkm/*	$NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $	*/
2296341Sdelphij/* $FreeBSD: head/sys/net/if_media.c 218909 2011-02-21 09:01:34Z brucec $ */
3296341Sdelphij
4296341Sdelphij/*-
5296341Sdelphij * Copyright (c) 1997
6109998Smarkm *	Jonathan Stone and Jason R. Thorpe.  All rights reserved.
7296341Sdelphij *
8296341Sdelphij * This software is derived from information provided by Matt Thomas.
9296341Sdelphij *
10296341Sdelphij * Redistribution and use in source and binary forms, with or without
11296341Sdelphij * modification, are permitted provided that the following conditions
12109998Smarkm * are met:
13109998Smarkm * 1. Redistributions of source code must retain the above copyright
14109998Smarkm *    notice, this list of conditions and the following disclaimer.
15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
16109998Smarkm *    notice, this list of conditions and the following disclaimer in the
17109998Smarkm *    documentation and/or other materials provided with the distribution.
18109998Smarkm * 3. All advertising materials mentioning features or use of this software
19109998Smarkm *    must display the following acknowledgement:
20109998Smarkm *      This product includes software developed by Jonathan Stone
21296341Sdelphij *	and Jason R. Thorpe for the NetBSD Project.
22109998Smarkm * 4. The names of the authors may not be used to endorse or promote products
23109998Smarkm *    derived from this software without specific prior written permission.
24109998Smarkm *
25109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
26109998Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27109998Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28109998Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29109998Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30109998Smarkm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32109998Smarkm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33109998Smarkm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34109998Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35109998Smarkm * SUCH DAMAGE.
36109998Smarkm */
37109998Smarkm
38109998Smarkm/*
39109998Smarkm * BSD/OS-compatible network interface media selection.
40109998Smarkm *
41109998Smarkm * Where it is safe to do so, this code strays slightly from the BSD/OS
42109998Smarkm * design.  Software which uses the API (device drivers, basically)
43109998Smarkm * shouldn't notice any difference.
44109998Smarkm *
45109998Smarkm * Many thanks to Matt Thomas for providing the information necessary
46109998Smarkm * to implement this interface.
47109998Smarkm */
48109998Smarkm
49109998Smarkm#include <sys/param.h>
50109998Smarkm#include <sys/systm.h>
51109998Smarkm#include <sys/socket.h>
52109998Smarkm#include <sys/sockio.h>
53109998Smarkm#include <sys/malloc.h>
54109998Smarkm#include <sys/module.h>
55109998Smarkm#include <sys/sysctl.h>
56109998Smarkm
57109998Smarkm#include <net/if.h>
58109998Smarkm#include <net/if_media.h>
59109998Smarkm
60109998Smarkm/*
61109998Smarkm * Compile-time options:
62109998Smarkm * IFMEDIA_DEBUG:
63109998Smarkm *	turn on implementation-level debug printfs.
64109998Smarkm * 	Useful for debugging newly-ported  drivers.
65109998Smarkm */
66109998Smarkm
67109998Smarkmstatic struct ifmedia_entry *ifmedia_match(struct ifmedia *ifm,
68109998Smarkm    int flags, int mask);
69109998Smarkm
70109998Smarkm#ifdef IFMEDIA_DEBUG
71109998Smarkmint	ifmedia_debug = 0;
72109998SmarkmSYSCTL_INT(_debug, OID_AUTO, ifmedia, CTLFLAG_RW, &ifmedia_debug,
73109998Smarkm	    0, "if_media debugging msgs");
74109998Smarkmstatic	void ifmedia_printword(int);
75109998Smarkm#endif
76109998Smarkm
77109998Smarkm/*
78109998Smarkm * Initialize if_media struct for a specific interface instance.
79109998Smarkm */
80296341Sdelphijvoid
81296341Sdelphijifmedia_init(ifm, dontcare_mask, change_callback, status_callback)
82296341Sdelphij	struct ifmedia *ifm;
83109998Smarkm	int dontcare_mask;
84109998Smarkm	ifm_change_cb_t change_callback;
85296341Sdelphij	ifm_stat_cb_t status_callback;
86296341Sdelphij{
87296341Sdelphij
88296341Sdelphij	LIST_INIT(&ifm->ifm_list);
89109998Smarkm	ifm->ifm_cur = NULL;
90296341Sdelphij	ifm->ifm_media = 0;
91296341Sdelphij	ifm->ifm_mask = dontcare_mask;		/* IF don't-care bits */
92296341Sdelphij	ifm->ifm_change = change_callback;
93296341Sdelphij	ifm->ifm_status = status_callback;
94296341Sdelphij}
95296341Sdelphij
96109998Smarkmvoid
97109998Smarkmifmedia_removeall(ifm)
98296341Sdelphij	struct ifmedia *ifm;
99296341Sdelphij{
100296341Sdelphij	struct ifmedia_entry *entry;
101296341Sdelphij
102109998Smarkm	for (entry = LIST_FIRST(&ifm->ifm_list); entry;
103109998Smarkm	     entry = LIST_FIRST(&ifm->ifm_list)) {
104296341Sdelphij		LIST_REMOVE(entry, ifm_list);
105296341Sdelphij		free(entry, M_IFADDR);
106296341Sdelphij	}
107109998Smarkm}
108109998Smarkm
109296341Sdelphij/*
110296341Sdelphij * Add a media configuration to the list of supported media
111296341Sdelphij * for a specific interface instance.
112109998Smarkm */
113109998Smarkmvoid
114296341Sdelphijifmedia_add(ifm, mword, data, aux)
115296341Sdelphij	struct ifmedia *ifm;
116296341Sdelphij	int mword;
117109998Smarkm	int data;
118109998Smarkm	void *aux;
119296341Sdelphij{
120296341Sdelphij	register struct ifmedia_entry *entry;
121296341Sdelphij
122296341Sdelphij#ifdef IFMEDIA_DEBUG
123296341Sdelphij	if (ifmedia_debug) {
124109998Smarkm		if (ifm == NULL) {
125109998Smarkm			printf("ifmedia_add: null ifm\n");
126296341Sdelphij			return;
127296341Sdelphij		}
128296341Sdelphij		printf("Adding entry for ");
129296341Sdelphij		ifmedia_printword(mword);
130109998Smarkm	}
131109998Smarkm#endif
132109998Smarkm
133109998Smarkm	entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT);
134296341Sdelphij	if (entry == NULL)
135296341Sdelphij		panic("ifmedia_add: can't malloc entry");
136296341Sdelphij
137109998Smarkm	entry->ifm_media = mword;
138109998Smarkm	entry->ifm_data = data;
139296341Sdelphij	entry->ifm_aux = aux;
140296341Sdelphij
141296341Sdelphij	LIST_INSERT_HEAD(&ifm->ifm_list, entry, ifm_list);
142109998Smarkm}
143109998Smarkm
144296341Sdelphij/*
145296341Sdelphij * Add an array of media configurations to the list of
146296341Sdelphij * supported media for a specific interface instance.
147109998Smarkm */
148109998Smarkmvoid
149296341Sdelphijifmedia_list_add(ifm, lp, count)
150296341Sdelphij	struct ifmedia *ifm;
151296341Sdelphij	struct ifmedia_entry *lp;
152296341Sdelphij	int count;
153109998Smarkm{
154109998Smarkm	int i;
155296341Sdelphij
156296341Sdelphij	for (i = 0; i < count; i++)
157296341Sdelphij		ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
158109998Smarkm		    lp[i].ifm_aux);
159109998Smarkm}
160296341Sdelphij
161296341Sdelphij/*
162296341Sdelphij * Set the default active media.
163109998Smarkm *
164109998Smarkm * Called by device-specific code which is assumed to have already
165296341Sdelphij * selected the default media in hardware.  We do _not_ call the
166296341Sdelphij * media-change callback.
167296341Sdelphij */
168109998Smarkmvoid
169109998Smarkmifmedia_set(ifm, target)
170296341Sdelphij	struct ifmedia *ifm;
171296341Sdelphij	int target;
172296341Sdelphij
173296341Sdelphij{
174296341Sdelphij	struct ifmedia_entry *match;
175109998Smarkm
176109998Smarkm	match = ifmedia_match(ifm, target, ifm->ifm_mask);
177296341Sdelphij
178296341Sdelphij	if (match == NULL) {
179296341Sdelphij		printf("ifmedia_set: no match for 0x%x/0x%x\n",
180109998Smarkm		    target, ~ifm->ifm_mask);
181109998Smarkm		panic("ifmedia_set");
182109998Smarkm	}
183109998Smarkm	ifm->ifm_cur = match;
184296341Sdelphij
185296341Sdelphij#ifdef IFMEDIA_DEBUG
186296341Sdelphij	if (ifmedia_debug) {
187109998Smarkm		printf("ifmedia_set: target ");
188109998Smarkm		ifmedia_printword(target);
189296341Sdelphij		printf("ifmedia_set: setting to ");
190296341Sdelphij		ifmedia_printword(ifm->ifm_cur->ifm_media);
191296341Sdelphij	}
192296341Sdelphij#endif
193109998Smarkm}
194296341Sdelphij
195296341Sdelphij/*
196296341Sdelphij * Device-independent media ioctl support function.
197296341Sdelphij */
198296341Sdelphijint
199296341Sdelphijifmedia_ioctl(ifp, ifr, ifm, cmd)
200109998Smarkm	struct ifnet *ifp;
201296341Sdelphij	struct ifreq *ifr;
202296341Sdelphij	struct ifmedia *ifm;
203296341Sdelphij	u_long cmd;
204296341Sdelphij{
205296341Sdelphij	struct ifmedia_entry *match;
206296341Sdelphij	struct ifmediareq *ifmr = (struct ifmediareq *) ifr;
207109998Smarkm	int error = 0, sticky;
208109998Smarkm
209296341Sdelphij	if (ifp == NULL || ifr == NULL || ifm == NULL)
210296341Sdelphij		return(EINVAL);
211296341Sdelphij
212109998Smarkm	switch (cmd) {
213109998Smarkm
214296341Sdelphij	/*
215296341Sdelphij	 * Set the current media.
216296341Sdelphij	 */
217109998Smarkm	case  SIOCSIFMEDIA:
218296341Sdelphij	{
219296341Sdelphij		struct ifmedia_entry *oldentry;
220296341Sdelphij		int oldmedia;
221296341Sdelphij		int newmedia = ifr->ifr_media;
222296341Sdelphij
223296341Sdelphij		match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
224109998Smarkm		if (match == NULL) {
225296341Sdelphij#ifdef IFMEDIA_DEBUG
226296341Sdelphij			if (ifmedia_debug) {
227296341Sdelphij				printf(
228296341Sdelphij				    "ifmedia_ioctl: no media found for 0x%x\n",
229296341Sdelphij				    newmedia);
230296341Sdelphij			}
231109998Smarkm#endif
232109998Smarkm			return (ENXIO);
233296341Sdelphij		}
234296341Sdelphij
235296341Sdelphij		/*
236296341Sdelphij		 * If no change, we're done.
237109998Smarkm		 * XXX Automedia may invole software intervention.
238109998Smarkm		 *     Keep going in case the connected media changed.
239109998Smarkm		 *     Similarly, if best match changed (kernel debugger?).
240109998Smarkm		 */
241296341Sdelphij		if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
242296341Sdelphij		    (newmedia == ifm->ifm_media) &&
243296341Sdelphij		    (match == ifm->ifm_cur))
244109998Smarkm			return 0;
245109998Smarkm
246296341Sdelphij		/*
247296341Sdelphij		 * We found a match, now make the driver switch to it.
248296341Sdelphij		 * Make sure to preserve our old media type in case the
249109998Smarkm		 * driver can't switch.
250296341Sdelphij		 */
251296341Sdelphij#ifdef IFMEDIA_DEBUG
252296341Sdelphij		if (ifmedia_debug) {
253296341Sdelphij			printf("ifmedia_ioctl: switching %s to ",
254296341Sdelphij			    ifp->if_xname);
255109998Smarkm			ifmedia_printword(match->ifm_media);
256296341Sdelphij		}
257296341Sdelphij#endif
258296341Sdelphij		oldentry = ifm->ifm_cur;
259296341Sdelphij		oldmedia = ifm->ifm_media;
260296341Sdelphij		ifm->ifm_cur = match;
261109998Smarkm		ifm->ifm_media = newmedia;
262109998Smarkm		error = (*ifm->ifm_change)(ifp);
263296341Sdelphij		if (error) {
264296341Sdelphij			ifm->ifm_cur = oldentry;
265296341Sdelphij			ifm->ifm_media = oldmedia;
266109998Smarkm		}
267109998Smarkm		break;
268296341Sdelphij	}
269296341Sdelphij
270296341Sdelphij	/*
271109998Smarkm	 * Get list of available media and current media on interface.
272296341Sdelphij	 */
273296341Sdelphij	case  SIOCGIFMEDIA:
274296341Sdelphij	{
275296341Sdelphij		struct ifmedia_entry *ep;
276296341Sdelphij		int *kptr, count;
277109998Smarkm		int usermax;	/* user requested max */
278296341Sdelphij
279296341Sdelphij		kptr = NULL;		/* XXX gcc */
280296341Sdelphij
281296341Sdelphij		ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
282296341Sdelphij		    ifm->ifm_cur->ifm_media : IFM_NONE;
283109998Smarkm		ifmr->ifm_mask = ifm->ifm_mask;
284109998Smarkm		ifmr->ifm_status = 0;
285296341Sdelphij		(*ifm->ifm_status)(ifp, ifmr);
286296341Sdelphij
287296341Sdelphij		count = 0;
288109998Smarkm		usermax = 0;
289109998Smarkm
290238405Sjkim		/*
291160814Ssimon		 * If there are more interfaces on the list, count
292296341Sdelphij		 * them.  This allows the caller to set ifmr->ifm_count
293296341Sdelphij		 * to 0 on the first call to know how much space to
294296341Sdelphij		 * allocate.
295296341Sdelphij		 */
296109998Smarkm		LIST_FOREACH(ep, &ifm->ifm_list, ifm_list)
297296341Sdelphij			usermax++;
298296341Sdelphij
299296341Sdelphij		/*
300296341Sdelphij		 * Don't allow the user to ask for too many
301296341Sdelphij		 * or a negative number.
302296341Sdelphij		 */
303296341Sdelphij		if (ifmr->ifm_count > usermax)
304296341Sdelphij			ifmr->ifm_count = usermax;
305296341Sdelphij		else if (ifmr->ifm_count < 0)
306296341Sdelphij			return (EINVAL);
307296341Sdelphij
308296341Sdelphij		if (ifmr->ifm_count != 0) {
309296341Sdelphij			kptr = (int *)malloc(ifmr->ifm_count * sizeof(int),
310296341Sdelphij			    M_TEMP, M_NOWAIT);
311296341Sdelphij
312296341Sdelphij			if (kptr == NULL)
313296341Sdelphij				return (ENOMEM);
314296341Sdelphij			/*
315296341Sdelphij			 * Get the media words from the interface's list.
316296341Sdelphij			 */
317296341Sdelphij			ep = LIST_FIRST(&ifm->ifm_list);
318296341Sdelphij			for (; ep != NULL && count < ifmr->ifm_count;
319296341Sdelphij			    ep = LIST_NEXT(ep, ifm_list), count++)
320296341Sdelphij				kptr[count] = ep->ifm_media;
321296341Sdelphij
322296341Sdelphij			if (ep != NULL)
323296341Sdelphij				error = E2BIG;	/* oops! */
324296341Sdelphij		} else {
325296341Sdelphij			count = usermax;
326296341Sdelphij		}
327296341Sdelphij
328296341Sdelphij		/*
329296341Sdelphij		 * We do the copyout on E2BIG, because that's
330296341Sdelphij		 * just our way of telling userland that there
331296341Sdelphij		 * are more.  This is the behavior I've observed
332238405Sjkim		 * under BSD/OS 3.0
333109998Smarkm		 */
334109998Smarkm		sticky = error;
335109998Smarkm		if ((error == 0 || error == E2BIG) && ifmr->ifm_count != 0) {
336296341Sdelphij			error = copyout((caddr_t)kptr,
337296341Sdelphij			    (caddr_t)ifmr->ifm_ulist,
338296341Sdelphij			    ifmr->ifm_count * sizeof(int));
339296341Sdelphij		}
340109998Smarkm
341109998Smarkm		if (error == 0)
342296341Sdelphij			error = sticky;
343296341Sdelphij
344296341Sdelphij		if (ifmr->ifm_count != 0)
345296341Sdelphij			free(kptr, M_TEMP);
346296341Sdelphij
347296341Sdelphij		ifmr->ifm_count = count;
348296341Sdelphij		break;
349296341Sdelphij	}
350296341Sdelphij
351296341Sdelphij	default:
352296341Sdelphij		return (EINVAL);
353296341Sdelphij	}
354296341Sdelphij
355296341Sdelphij	return (error);
356296341Sdelphij}
357296341Sdelphij
358296341Sdelphij/*
359296341Sdelphij * Find media entry matching a given ifm word.
360296341Sdelphij *
361296341Sdelphij */
362296341Sdelphijstatic struct ifmedia_entry *
363296341Sdelphijifmedia_match(ifm, target, mask)
364296341Sdelphij	struct ifmedia *ifm;
365296341Sdelphij	int target;
366296341Sdelphij	int mask;
367296341Sdelphij{
368296341Sdelphij	struct ifmedia_entry *match, *next;
369296341Sdelphij
370296341Sdelphij	match = NULL;
371296341Sdelphij	mask = ~mask;
372296341Sdelphij
373296341Sdelphij	LIST_FOREACH(next, &ifm->ifm_list, ifm_list) {
374296341Sdelphij		if ((next->ifm_media & mask) == (target & mask)) {
375109998Smarkm#if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
376109998Smarkm			if (match) {
377109998Smarkm				printf("ifmedia_match: multiple match for "
378109998Smarkm				    "0x%x/0x%x\n", target, mask);
379296341Sdelphij			}
380296341Sdelphij#endif
381296341Sdelphij			match = next;
382109998Smarkm		}
383109998Smarkm	}
384109998Smarkm
385109998Smarkm	return match;
386296341Sdelphij}
387296341Sdelphij
388296341Sdelphij/*
389296341Sdelphij * Compute the interface `baudrate' from the media, for the interface
390109998Smarkm * metrics (used by routing daemons).
391296341Sdelphij */
392296341Sdelphijstatic const struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
393109998Smarkm    IFM_BAUDRATE_DESCRIPTIONS;
394109998Smarkm
395109998Smarkmuint64_t
396109998Smarkmifmedia_baudrate(int mword)
397109998Smarkm{
398109998Smarkm	int i;
399109998Smarkm
400109998Smarkm	for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
401109998Smarkm		if ((mword & (IFM_NMASK|IFM_TMASK)) ==
402109998Smarkm		    ifmedia_baudrate_descriptions[i].ifmb_word)
403109998Smarkm			return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
404109998Smarkm	}
405109998Smarkm
406296341Sdelphij	/* Not known. */
407296341Sdelphij	return (0);
408296341Sdelphij}
409296341Sdelphij
410296341Sdelphij#ifdef IFMEDIA_DEBUG
411296341Sdelphijstruct ifmedia_description ifm_type_descriptions[] =
412296341Sdelphij    IFM_TYPE_DESCRIPTIONS;
413296341Sdelphij
414109998Smarkmstruct ifmedia_description ifm_subtype_ethernet_descriptions[] =
415296341Sdelphij    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
416296341Sdelphij
417296341Sdelphijstruct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
418296341Sdelphij    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
419296341Sdelphij
420296341Sdelphijstruct ifmedia_description ifm_subtype_tokenring_descriptions[] =
421296341Sdelphij    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
422296341Sdelphij
423296341Sdelphijstruct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
424296341Sdelphij    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
425296341Sdelphij
426296341Sdelphijstruct ifmedia_description ifm_subtype_fddi_descriptions[] =
427296341Sdelphij    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
428296341Sdelphij
429296341Sdelphijstruct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
430296341Sdelphij    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
431296341Sdelphij
432296341Sdelphijstruct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
433296341Sdelphij    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
434296341Sdelphij
435296341Sdelphijstruct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
436296341Sdelphij    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
437109998Smarkm
438296341Sdelphijstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
439296341Sdelphij    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
440109998Smarkm
441109998Smarkmstruct ifmedia_description ifm_subtype_atm_descriptions[] =
442109998Smarkm    IFM_SUBTYPE_ATM_DESCRIPTIONS;
443296341Sdelphij
444296341Sdelphijstruct ifmedia_description ifm_subtype_atm_option_descriptions[] =
445296341Sdelphij    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
446296341Sdelphij
447296341Sdelphijstruct ifmedia_description ifm_subtype_shared_descriptions[] =
448296341Sdelphij    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
449296341Sdelphij
450296341Sdelphijstruct ifmedia_description ifm_shared_option_descriptions[] =
451296341Sdelphij    IFM_SHARED_OPTION_DESCRIPTIONS;
452296341Sdelphij
453296341Sdelphijstruct ifmedia_type_to_subtype {
454109998Smarkm	struct ifmedia_description *subtypes;
455109998Smarkm	struct ifmedia_description *options;
456296341Sdelphij	struct ifmedia_description *modes;
457296341Sdelphij};
458296341Sdelphij
459109998Smarkm/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
460296341Sdelphijstruct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
461296341Sdelphij	{
462296341Sdelphij	  &ifm_subtype_ethernet_descriptions[0],
463296341Sdelphij	  &ifm_subtype_ethernet_option_descriptions[0],
464296341Sdelphij	  NULL,
465296341Sdelphij	},
466296341Sdelphij	{
467296341Sdelphij	  &ifm_subtype_tokenring_descriptions[0],
468296341Sdelphij	  &ifm_subtype_tokenring_option_descriptions[0],
469296341Sdelphij	  NULL,
470296341Sdelphij	},
471296341Sdelphij	{
472296341Sdelphij	  &ifm_subtype_fddi_descriptions[0],
473296341Sdelphij	  &ifm_subtype_fddi_option_descriptions[0],
474296341Sdelphij	  NULL,
475296341Sdelphij	},
476296341Sdelphij	{
477296341Sdelphij	  &ifm_subtype_ieee80211_descriptions[0],
478296341Sdelphij	  &ifm_subtype_ieee80211_option_descriptions[0],
479296341Sdelphij	  &ifm_subtype_ieee80211_mode_descriptions[0]
480296341Sdelphij	},
481296341Sdelphij	{
482296341Sdelphij	  &ifm_subtype_atm_descriptions[0],
483296341Sdelphij	  &ifm_subtype_atm_option_descriptions[0],
484296341Sdelphij	  NULL,
485296341Sdelphij	},
486296341Sdelphij};
487109998Smarkm
488109998Smarkm/*
489296341Sdelphij * print a media word.
490296341Sdelphij */
491296341Sdelphijstatic void
492296341Sdelphijifmedia_printword(ifmw)
493296341Sdelphij	int ifmw;
494109998Smarkm{
495296341Sdelphij	struct ifmedia_description *desc;
496296341Sdelphij	struct ifmedia_type_to_subtype *ttos;
497296341Sdelphij	int seen_option = 0;
498296341Sdelphij
499296341Sdelphij	/* Find the top-level interface type. */
500296341Sdelphij	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
501296341Sdelphij	    desc->ifmt_string != NULL; desc++, ttos++)
502296341Sdelphij		if (IFM_TYPE(ifmw) == desc->ifmt_word)
503296341Sdelphij			break;
504296341Sdelphij	if (desc->ifmt_string == NULL) {
505296341Sdelphij		printf("<unknown type>\n");
506296341Sdelphij		return;
507296341Sdelphij	}
508109998Smarkm	printf(desc->ifmt_string);
509109998Smarkm
510296341Sdelphij	/* Any mode. */
511296341Sdelphij	for (desc = ttos->modes; desc && desc->ifmt_string != NULL; desc++)
512296341Sdelphij		if (IFM_MODE(ifmw) == desc->ifmt_word) {
513296341Sdelphij			if (desc->ifmt_string != NULL)
514109998Smarkm				printf(" mode %s", desc->ifmt_string);
515296341Sdelphij			break;
516296341Sdelphij		}
517296341Sdelphij
518296341Sdelphij	/*
519296341Sdelphij	 * Check for the shared subtype descriptions first, then the
520296341Sdelphij	 * type-specific ones.
521296341Sdelphij	 */
522296341Sdelphij	for (desc = ifm_subtype_shared_descriptions;
523296341Sdelphij	    desc->ifmt_string != NULL; desc++)
524296341Sdelphij		if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
525109998Smarkm			goto got_subtype;
526296341Sdelphij
527296341Sdelphij	for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++)
528296341Sdelphij		if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
529296341Sdelphij			break;
530109998Smarkm	if (desc->ifmt_string == NULL) {
531296341Sdelphij		printf(" <unknown subtype>\n");
532296341Sdelphij		return;
533296341Sdelphij	}
534296341Sdelphij
535296341Sdelphij got_subtype:
536296341Sdelphij	printf(" %s", desc->ifmt_string);
537109998Smarkm
538296341Sdelphij	/*
539296341Sdelphij	 * Look for shared options.
540296341Sdelphij	 */
541296341Sdelphij	for (desc = ifm_shared_option_descriptions;
542296341Sdelphij	    desc->ifmt_string != NULL; desc++) {
543296341Sdelphij		if (ifmw & desc->ifmt_word) {
544296341Sdelphij			if (seen_option == 0)
545296341Sdelphij				printf(" <");
546296341Sdelphij			printf("%s%s", seen_option++ ? "," : "",
547296341Sdelphij			    desc->ifmt_string);
548296341Sdelphij		}
549296341Sdelphij	}
550296341Sdelphij
551296341Sdelphij	/*
552296341Sdelphij	 * Look for subtype-specific options.
553296341Sdelphij	 */
554296341Sdelphij	for (desc = ttos->options; desc->ifmt_string != NULL; desc++) {
555296341Sdelphij		if (ifmw & desc->ifmt_word) {
556296341Sdelphij			if (seen_option == 0)
557296341Sdelphij				printf(" <");
558296341Sdelphij			printf("%s%s", seen_option++ ? "," : "",
559296341Sdelphij			    desc->ifmt_string);
560296341Sdelphij		}
561296341Sdelphij	}
562296341Sdelphij	printf("%s\n", seen_option ? ">" : "");
563296341Sdelphij}
564296341Sdelphij#endif /* IFMEDIA_DEBUG */
565296341Sdelphij