125428Speter/*	$NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $	*/
250477Speter/* $FreeBSD: stable/11/sys/net/if_media.c 331643 2018-03-27 18:52:27Z dim $ */
325428Speter
4139823Simp/*-
525428Speter * Copyright (c) 1997
625428Speter *	Jonathan Stone and Jason R. Thorpe.  All rights reserved.
725428Speter *
825428Speter * This software is derived from information provided by Matt Thomas.
925428Speter *
1025428Speter * Redistribution and use in source and binary forms, with or without
1125428Speter * modification, are permitted provided that the following conditions
1225428Speter * are met:
1325428Speter * 1. Redistributions of source code must retain the above copyright
1425428Speter *    notice, this list of conditions and the following disclaimer.
1525428Speter * 2. Redistributions in binary form must reproduce the above copyright
1625428Speter *    notice, this list of conditions and the following disclaimer in the
1725428Speter *    documentation and/or other materials provided with the distribution.
1825428Speter * 3. All advertising materials mentioning features or use of this software
1925428Speter *    must display the following acknowledgement:
2025428Speter *      This product includes software developed by Jonathan Stone
2125428Speter *	and Jason R. Thorpe for the NetBSD Project.
2225428Speter * 4. The names of the authors may not be used to endorse or promote products
2325428Speter *    derived from this software without specific prior written permission.
2425428Speter *
2525428Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
2625428Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2725428Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2825428Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2925428Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
3025428Speter * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3125428Speter * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3225428Speter * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3325428Speter * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3425428Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3525428Speter * SUCH DAMAGE.
3625428Speter */
3725428Speter
3825428Speter/*
3925428Speter * BSD/OS-compatible network interface media selection.
4025428Speter *
4125428Speter * Where it is safe to do so, this code strays slightly from the BSD/OS
4225428Speter * design.  Software which uses the API (device drivers, basically)
4325428Speter * shouldn't notice any difference.
4425428Speter *
4525428Speter * Many thanks to Matt Thomas for providing the information necessary
4625428Speter * to implement this interface.
4725428Speter */
4825428Speter
49281824Sglebius#include "opt_ifmedia.h"
50281824Sglebius
5125428Speter#include <sys/param.h>
5225428Speter#include <sys/systm.h>
5325428Speter#include <sys/socket.h>
5425431Speter#include <sys/sockio.h>
5525428Speter#include <sys/malloc.h>
56153723Ssam#include <sys/module.h>
57153723Ssam#include <sys/sysctl.h>
5825428Speter
5925428Speter#include <net/if.h>
6025428Speter#include <net/if_media.h>
6125428Speter
6225428Speter/*
6325428Speter * Compile-time options:
6425428Speter * IFMEDIA_DEBUG:
6525428Speter *	turn on implementation-level debug printfs.
6625428Speter * 	Useful for debugging newly-ported  drivers.
6725428Speter */
6825428Speter
6992725Salfredstatic struct ifmedia_entry *ifmedia_match(struct ifmedia *ifm,
7092725Salfred    int flags, int mask);
7125428Speter
7225428Speter#ifdef IFMEDIA_DEBUG
73281236Serj#include <net/if_var.h>
7425428Speterint	ifmedia_debug = 0;
75153723SsamSYSCTL_INT(_debug, OID_AUTO, ifmedia, CTLFLAG_RW, &ifmedia_debug,
76153723Ssam	    0, "if_media debugging msgs");
7792725Salfredstatic	void ifmedia_printword(int);
7825428Speter#endif
7925428Speter
8025428Speter/*
8125428Speter * Initialize if_media struct for a specific interface instance.
8225428Speter */
8325428Spetervoid
8425428Speterifmedia_init(ifm, dontcare_mask, change_callback, status_callback)
8525428Speter	struct ifmedia *ifm;
8625428Speter	int dontcare_mask;
8725428Speter	ifm_change_cb_t change_callback;
8825428Speter	ifm_stat_cb_t status_callback;
8925428Speter{
9025428Speter
9125428Speter	LIST_INIT(&ifm->ifm_list);
9225428Speter	ifm->ifm_cur = NULL;
9325428Speter	ifm->ifm_media = 0;
9425428Speter	ifm->ifm_mask = dontcare_mask;		/* IF don't-care bits */
9525428Speter	ifm->ifm_change = change_callback;
9625428Speter	ifm->ifm_status = status_callback;
9725428Speter}
9825428Speter
9945720Spetervoid
10045720Speterifmedia_removeall(ifm)
10145720Speter	struct ifmedia *ifm;
10245720Speter{
10345720Speter	struct ifmedia_entry *entry;
10445720Speter
10545720Speter	for (entry = LIST_FIRST(&ifm->ifm_list); entry;
10645720Speter	     entry = LIST_FIRST(&ifm->ifm_list)) {
10745720Speter		LIST_REMOVE(entry, ifm_list);
10845720Speter		free(entry, M_IFADDR);
10945720Speter	}
110313388Srstone	ifm->ifm_cur = NULL;
11145720Speter}
11245720Speter
11325428Speter/*
11425428Speter * Add a media configuration to the list of supported media
11525428Speter * for a specific interface instance.
11625428Speter */
11725428Spetervoid
11825428Speterifmedia_add(ifm, mword, data, aux)
11925428Speter	struct ifmedia *ifm;
12025428Speter	int mword;
12125428Speter	int data;
12225428Speter	void *aux;
12325428Speter{
124331643Sdim	struct ifmedia_entry *entry;
12525428Speter
12625428Speter#ifdef IFMEDIA_DEBUG
12725428Speter	if (ifmedia_debug) {
12825428Speter		if (ifm == NULL) {
12925428Speter			printf("ifmedia_add: null ifm\n");
13025428Speter			return;
13125428Speter		}
13225428Speter		printf("Adding entry for ");
13325428Speter		ifmedia_printword(mword);
13425428Speter	}
13525428Speter#endif
13625428Speter
13725428Speter	entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT);
13825428Speter	if (entry == NULL)
13925428Speter		panic("ifmedia_add: can't malloc entry");
14025428Speter
14125428Speter	entry->ifm_media = mword;
14225428Speter	entry->ifm_data = data;
14325428Speter	entry->ifm_aux = aux;
14425428Speter
14525428Speter	LIST_INSERT_HEAD(&ifm->ifm_list, entry, ifm_list);
14625428Speter}
14725428Speter
14825428Speter/*
14925428Speter * Add an array of media configurations to the list of
15025428Speter * supported media for a specific interface instance.
15125428Speter */
15225428Spetervoid
15325428Speterifmedia_list_add(ifm, lp, count)
15425428Speter	struct ifmedia *ifm;
15525428Speter	struct ifmedia_entry *lp;
15625428Speter	int count;
15725428Speter{
15825428Speter	int i;
15925428Speter
16025428Speter	for (i = 0; i < count; i++)
16125428Speter		ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
16225428Speter		    lp[i].ifm_aux);
16325428Speter}
16425428Speter
16525428Speter/*
16625428Speter * Set the default active media.
16725428Speter *
16825428Speter * Called by device-specific code which is assumed to have already
16925428Speter * selected the default media in hardware.  We do _not_ call the
17025428Speter * media-change callback.
17125428Speter */
17225428Spetervoid
17325428Speterifmedia_set(ifm, target)
17425428Speter	struct ifmedia *ifm;
17525428Speter	int target;
17625428Speter
17725428Speter{
17825428Speter	struct ifmedia_entry *match;
17925428Speter
18025428Speter	match = ifmedia_match(ifm, target, ifm->ifm_mask);
18125428Speter
18225428Speter	if (match == NULL) {
18325428Speter		printf("ifmedia_set: no match for 0x%x/0x%x\n",
18425428Speter		    target, ~ifm->ifm_mask);
18525428Speter		panic("ifmedia_set");
18625428Speter	}
18725428Speter	ifm->ifm_cur = match;
18825428Speter
18925428Speter#ifdef IFMEDIA_DEBUG
19025428Speter	if (ifmedia_debug) {
19125428Speter		printf("ifmedia_set: target ");
19225428Speter		ifmedia_printword(target);
19325428Speter		printf("ifmedia_set: setting to ");
19425428Speter		ifmedia_printword(ifm->ifm_cur->ifm_media);
19525428Speter	}
19625428Speter#endif
19725428Speter}
19825428Speter
19925428Speter/*
200281236Serj * Given a media word, return one suitable for an application
201281236Serj * using the original encoding.
202281236Serj */
203281236Serjstatic int
204281236Serjcompat_media(int media)
205281236Serj{
206281236Serj
207281236Serj	if (IFM_TYPE(media) == IFM_ETHER && IFM_SUBTYPE(media) > IFM_OTHER) {
208281236Serj		media &= ~(IFM_ETH_XTYPE|IFM_TMASK);
209281236Serj		media |= IFM_OTHER;
210281236Serj	}
211281236Serj	return (media);
212281236Serj}
213281236Serj
214281236Serj/*
21525428Speter * Device-independent media ioctl support function.
21625428Speter */
21725428Speterint
21825428Speterifmedia_ioctl(ifp, ifr, ifm, cmd)
21925428Speter	struct ifnet *ifp;
22025428Speter	struct ifreq *ifr;
22125428Speter	struct ifmedia *ifm;
22225428Speter	u_long cmd;
22325428Speter{
22425428Speter	struct ifmedia_entry *match;
22525428Speter	struct ifmediareq *ifmr = (struct ifmediareq *) ifr;
226279592Sglebius	int error = 0;
22725428Speter
22825428Speter	if (ifp == NULL || ifr == NULL || ifm == NULL)
22925428Speter		return(EINVAL);
23025428Speter
23125428Speter	switch (cmd) {
23225428Speter
23325428Speter	/*
23425428Speter	 * Set the current media.
23525428Speter	 */
23625428Speter	case  SIOCSIFMEDIA:
23725428Speter	{
23825428Speter		struct ifmedia_entry *oldentry;
23925428Speter		int oldmedia;
24025428Speter		int newmedia = ifr->ifr_media;
24125428Speter
24225428Speter		match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
24325428Speter		if (match == NULL) {
24425428Speter#ifdef IFMEDIA_DEBUG
24525428Speter			if (ifmedia_debug) {
24625428Speter				printf(
24725428Speter				    "ifmedia_ioctl: no media found for 0x%x\n",
24825428Speter				    newmedia);
24925428Speter			}
25025428Speter#endif
25125428Speter			return (ENXIO);
25225428Speter		}
25325428Speter
25425428Speter		/*
25525428Speter		 * If no change, we're done.
25625428Speter		 * XXX Automedia may invole software intervention.
257218909Sbrucec		 *     Keep going in case the connected media changed.
25825428Speter		 *     Similarly, if best match changed (kernel debugger?).
25925428Speter		 */
26025428Speter		if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
26125428Speter		    (newmedia == ifm->ifm_media) &&
26225428Speter		    (match == ifm->ifm_cur))
26325428Speter			return 0;
26425428Speter
26525428Speter		/*
26625428Speter		 * We found a match, now make the driver switch to it.
26725428Speter		 * Make sure to preserve our old media type in case the
26825428Speter		 * driver can't switch.
26925428Speter		 */
27025428Speter#ifdef IFMEDIA_DEBUG
27125428Speter		if (ifmedia_debug) {
272121816Sbrooks			printf("ifmedia_ioctl: switching %s to ",
273121816Sbrooks			    ifp->if_xname);
27425428Speter			ifmedia_printword(match->ifm_media);
27525428Speter		}
27625428Speter#endif
27725428Speter		oldentry = ifm->ifm_cur;
27825428Speter		oldmedia = ifm->ifm_media;
27925428Speter		ifm->ifm_cur = match;
28025428Speter		ifm->ifm_media = newmedia;
28125428Speter		error = (*ifm->ifm_change)(ifp);
28225428Speter		if (error) {
28325428Speter			ifm->ifm_cur = oldentry;
28425428Speter			ifm->ifm_media = oldmedia;
28525428Speter		}
28625428Speter		break;
28725428Speter	}
28825428Speter
28925428Speter	/*
29025428Speter	 * Get list of available media and current media on interface.
29125428Speter	 */
29225428Speter	case  SIOCGIFMEDIA:
293281236Serj	case  SIOCGIFXMEDIA:
29425428Speter	{
29525428Speter		struct ifmedia_entry *ep;
296279592Sglebius		int i;
29725428Speter
298279592Sglebius		if (ifmr->ifm_count < 0)
299279592Sglebius			return (EINVAL);
30025428Speter
301281236Serj		if (cmd == SIOCGIFMEDIA) {
302281236Serj			ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
303281236Serj			    compat_media(ifm->ifm_cur->ifm_media) : IFM_NONE;
304281236Serj		} else {
305281236Serj			ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
306281236Serj			    ifm->ifm_cur->ifm_media : IFM_NONE;
307281236Serj		}
30825428Speter		ifmr->ifm_mask = ifm->ifm_mask;
30925428Speter		ifmr->ifm_status = 0;
31025428Speter		(*ifm->ifm_status)(ifp, ifmr);
31125428Speter
31273078Salfred		/*
31373078Salfred		 * If there are more interfaces on the list, count
31473078Salfred		 * them.  This allows the caller to set ifmr->ifm_count
31573078Salfred		 * to 0 on the first call to know how much space to
31673079Salfred		 * allocate.
31773078Salfred		 */
318279592Sglebius		i = 0;
31973078Salfred		LIST_FOREACH(ep, &ifm->ifm_list, ifm_list)
320279592Sglebius			if (i++ < ifmr->ifm_count) {
321279592Sglebius				error = copyout(&ep->ifm_media,
322279592Sglebius				    ifmr->ifm_ulist + i - 1, sizeof(int));
323279592Sglebius				if (error)
324279592Sglebius					break;
325279592Sglebius			}
326279592Sglebius		if (error == 0 && i > ifmr->ifm_count)
327279592Sglebius			error = ifmr->ifm_count ? E2BIG : 0;
328279592Sglebius		ifmr->ifm_count = i;
32925428Speter		break;
33025428Speter	}
33125428Speter
33225428Speter	default:
33325428Speter		return (EINVAL);
33425428Speter	}
33525428Speter
33625428Speter	return (error);
33725428Speter}
33825428Speter
33925428Speter/*
34025428Speter * Find media entry matching a given ifm word.
34125428Speter *
34225428Speter */
34333181Seivindstatic struct ifmedia_entry *
34425428Speterifmedia_match(ifm, target, mask)
34525428Speter	struct ifmedia *ifm;
34625428Speter	int target;
34725428Speter	int mask;
34825428Speter{
34925428Speter	struct ifmedia_entry *match, *next;
35025428Speter
35125428Speter	match = NULL;
35225428Speter	mask = ~mask;
35325428Speter
35472012Sphk	LIST_FOREACH(next, &ifm->ifm_list, ifm_list) {
35525428Speter		if ((next->ifm_media & mask) == (target & mask)) {
35625428Speter#if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
35725428Speter			if (match) {
35825428Speter				printf("ifmedia_match: multiple match for "
35925428Speter				    "0x%x/0x%x\n", target, mask);
36025428Speter			}
36125428Speter#endif
36225428Speter			match = next;
36325428Speter		}
36425428Speter	}
36525428Speter
36625428Speter	return match;
36725428Speter}
36825428Speter
369155669Sglebius/*
370155669Sglebius * Compute the interface `baudrate' from the media, for the interface
371155669Sglebius * metrics (used by routing daemons).
372155669Sglebius */
373155669Sglebiusstatic const struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
374155669Sglebius    IFM_BAUDRATE_DESCRIPTIONS;
375155669Sglebius
376155669Sglebiusuint64_t
377155669Sglebiusifmedia_baudrate(int mword)
378155669Sglebius{
379155669Sglebius	int i;
380155669Sglebius
381155669Sglebius	for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
382281236Serj		if (IFM_TYPE_MATCH(mword, ifmedia_baudrate_descriptions[i].ifmb_word))
383155669Sglebius			return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
384155669Sglebius	}
385155669Sglebius
386155669Sglebius	/* Not known. */
387155669Sglebius	return (0);
388155669Sglebius}
389155669Sglebius
39025428Speter#ifdef IFMEDIA_DEBUG
39125428Speterstruct ifmedia_description ifm_type_descriptions[] =
39225428Speter    IFM_TYPE_DESCRIPTIONS;
39325428Speter
39425428Speterstruct ifmedia_description ifm_subtype_ethernet_descriptions[] =
39525428Speter    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
39625428Speter
39725428Speterstruct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
39825428Speter    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
39925428Speter
40025428Speterstruct ifmedia_description ifm_subtype_tokenring_descriptions[] =
40125428Speter    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
40225428Speter
40325428Speterstruct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
40425428Speter    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
40525428Speter
40625428Speterstruct ifmedia_description ifm_subtype_fddi_descriptions[] =
40725428Speter    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
40825428Speter
40925428Speterstruct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
41025428Speter    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
41125428Speter
41277217Sphkstruct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
41377217Sphk    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
41477217Sphk
41577217Sphkstruct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
41677217Sphk    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
41777217Sphk
418114163Ssamstruct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
419114163Ssam    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
420114163Ssam
421114232Shartistruct ifmedia_description ifm_subtype_atm_descriptions[] =
422114232Sharti    IFM_SUBTYPE_ATM_DESCRIPTIONS;
423114232Sharti
424114232Shartistruct ifmedia_description ifm_subtype_atm_option_descriptions[] =
425114232Sharti    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
426114232Sharti
42725428Speterstruct ifmedia_description ifm_subtype_shared_descriptions[] =
42825428Speter    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
42925428Speter
43025428Speterstruct ifmedia_description ifm_shared_option_descriptions[] =
43125428Speter    IFM_SHARED_OPTION_DESCRIPTIONS;
43225428Speter
43325428Speterstruct ifmedia_type_to_subtype {
43425428Speter	struct ifmedia_description *subtypes;
43525428Speter	struct ifmedia_description *options;
436114163Ssam	struct ifmedia_description *modes;
43725428Speter};
43825428Speter
43925428Speter/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
44025428Speterstruct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
44125428Speter	{
44225428Speter	  &ifm_subtype_ethernet_descriptions[0],
443114163Ssam	  &ifm_subtype_ethernet_option_descriptions[0],
444114163Ssam	  NULL,
44525428Speter	},
44625428Speter	{
44725428Speter	  &ifm_subtype_tokenring_descriptions[0],
448114163Ssam	  &ifm_subtype_tokenring_option_descriptions[0],
449114163Ssam	  NULL,
45025428Speter	},
45125428Speter	{
45225428Speter	  &ifm_subtype_fddi_descriptions[0],
453114163Ssam	  &ifm_subtype_fddi_option_descriptions[0],
454114163Ssam	  NULL,
45525428Speter	},
45677217Sphk	{
45777217Sphk	  &ifm_subtype_ieee80211_descriptions[0],
458114163Ssam	  &ifm_subtype_ieee80211_option_descriptions[0],
459114163Ssam	  &ifm_subtype_ieee80211_mode_descriptions[0]
46077217Sphk	},
461114232Sharti	{
462114232Sharti	  &ifm_subtype_atm_descriptions[0],
463114232Sharti	  &ifm_subtype_atm_option_descriptions[0],
464114232Sharti	  NULL,
465114232Sharti	},
46625428Speter};
46725428Speter
46825428Speter/*
46925428Speter * print a media word.
47025428Speter */
47125428Speterstatic void
47225428Speterifmedia_printword(ifmw)
47325428Speter	int ifmw;
47425428Speter{
47525428Speter	struct ifmedia_description *desc;
47625428Speter	struct ifmedia_type_to_subtype *ttos;
47725428Speter	int seen_option = 0;
47825428Speter
47925428Speter	/* Find the top-level interface type. */
48025428Speter	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
48125428Speter	    desc->ifmt_string != NULL; desc++, ttos++)
48225428Speter		if (IFM_TYPE(ifmw) == desc->ifmt_word)
48325428Speter			break;
48425428Speter	if (desc->ifmt_string == NULL) {
48525428Speter		printf("<unknown type>\n");
48625428Speter		return;
48725428Speter	}
488281236Serj	printf("%s", desc->ifmt_string);
48925428Speter
490114163Ssam	/* Any mode. */
491114163Ssam	for (desc = ttos->modes; desc && desc->ifmt_string != NULL; desc++)
492114163Ssam		if (IFM_MODE(ifmw) == desc->ifmt_word) {
493114163Ssam			if (desc->ifmt_string != NULL)
494114163Ssam				printf(" mode %s", desc->ifmt_string);
495114163Ssam			break;
496114163Ssam		}
497114163Ssam
49825428Speter	/*
49925428Speter	 * Check for the shared subtype descriptions first, then the
50025428Speter	 * type-specific ones.
50125428Speter	 */
50225428Speter	for (desc = ifm_subtype_shared_descriptions;
50325428Speter	    desc->ifmt_string != NULL; desc++)
50425428Speter		if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
50525428Speter			goto got_subtype;
50625428Speter
50725428Speter	for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++)
50825428Speter		if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
50925428Speter			break;
51025428Speter	if (desc->ifmt_string == NULL) {
51125428Speter		printf(" <unknown subtype>\n");
51225428Speter		return;
51325428Speter	}
51425428Speter
51525428Speter got_subtype:
51625428Speter	printf(" %s", desc->ifmt_string);
51725428Speter
51825428Speter	/*
51925428Speter	 * Look for shared options.
52025428Speter	 */
52125428Speter	for (desc = ifm_shared_option_descriptions;
52225428Speter	    desc->ifmt_string != NULL; desc++) {
52325428Speter		if (ifmw & desc->ifmt_word) {
52425428Speter			if (seen_option == 0)
52525428Speter				printf(" <");
52625428Speter			printf("%s%s", seen_option++ ? "," : "",
52725428Speter			    desc->ifmt_string);
52825428Speter		}
52925428Speter	}
53025428Speter
53125428Speter	/*
53225428Speter	 * Look for subtype-specific options.
53325428Speter	 */
53425428Speter	for (desc = ttos->options; desc->ifmt_string != NULL; desc++) {
53525428Speter		if (ifmw & desc->ifmt_word) {
53625428Speter			if (seen_option == 0)
53725428Speter				printf(" <");
53825428Speter			printf("%s%s", seen_option++ ? "," : "",
53925428Speter			    desc->ifmt_string);
54025428Speter		}
54125428Speter	}
54225428Speter	printf("%s\n", seen_option ? ">" : "");
54325428Speter}
54425428Speter#endif /* IFMEDIA_DEBUG */
545