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