|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* $NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $ */ ! 23: ! 24: /* ! 25: * Copyright (c) 1997 ! 26: * Jonathan Stone and Jason R. Thorpe. All rights reserved. ! 27: * ! 28: * This software is derived from information provided by Matt Thomas. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by Jonathan Stone ! 41: * and Jason R. Thorpe for the NetBSD Project. ! 42: * 4. The names of the authors may not be used to endorse or promote products ! 43: * derived from this software without specific prior written permission. ! 44: * ! 45: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR ! 46: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ! 47: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! 48: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ! 49: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ! 50: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ! 51: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED ! 52: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! 53: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 54: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 55: * SUCH DAMAGE. ! 56: */ ! 57: ! 58: /* ! 59: * BSD/OS-compatible network interface media selection. ! 60: * ! 61: * Where it is safe to do so, this code strays slightly from the BSD/OS ! 62: * design. Software which uses the API (device drivers, basically) ! 63: * shouldn't notice any difference. ! 64: * ! 65: * Many thanks to Matt Thomas for providing the information necessary ! 66: * to implement this interface. ! 67: */ ! 68: ! 69: #include <sys/param.h> ! 70: #include <sys/systm.h> ! 71: #include <sys/socket.h> ! 72: #include <sys/sockio.h> ! 73: #include <sys/malloc.h> ! 74: ! 75: #include <net/if.h> ! 76: #include <net/if_media.h> ! 77: ! 78: /* ! 79: * Compile-time options: ! 80: * IFMEDIA_DEBUG: ! 81: * turn on implementation-level debug printfs. ! 82: * Useful for debugging newly-ported drivers. ! 83: */ ! 84: ! 85: static struct ifmedia_entry *ifmedia_match __P((struct ifmedia *ifm, ! 86: int flags, int mask)); ! 87: ! 88: #ifdef IFMEDIA_DEBUG ! 89: int ifmedia_debug = 0; ! 90: static void ifmedia_printword __P((int)); ! 91: #endif ! 92: ! 93: /* ! 94: * Initialize if_media struct for a specific interface instance. ! 95: */ ! 96: void ! 97: ifmedia_init(ifm, dontcare_mask, change_callback, status_callback) ! 98: struct ifmedia *ifm; ! 99: int dontcare_mask; ! 100: ifm_change_cb_t change_callback; ! 101: ifm_stat_cb_t status_callback; ! 102: { ! 103: ! 104: LIST_INIT(&ifm->ifm_list); ! 105: ifm->ifm_cur = NULL; ! 106: ifm->ifm_media = 0; ! 107: ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */ ! 108: ifm->ifm_change = change_callback; ! 109: ifm->ifm_status = status_callback; ! 110: } ! 111: ! 112: /* ! 113: * Add a media configuration to the list of supported media ! 114: * for a specific interface instance. ! 115: */ ! 116: void ! 117: ifmedia_add(ifm, mword, data, aux) ! 118: struct ifmedia *ifm; ! 119: int mword; ! 120: int data; ! 121: void *aux; ! 122: { ! 123: register struct ifmedia_entry *entry; ! 124: ! 125: #ifdef IFMEDIA_DEBUG ! 126: if (ifmedia_debug) { ! 127: if (ifm == NULL) { ! 128: printf("ifmedia_add: null ifm\n"); ! 129: return; ! 130: } ! 131: printf("Adding entry for "); ! 132: ifmedia_printword(mword); ! 133: } ! 134: #endif ! 135: ! 136: entry = _MALLOC(sizeof(*entry), M_IFADDR, M_NOWAIT); ! 137: if (entry == NULL) ! 138: panic("ifmedia_add: can't malloc entry"); ! 139: ! 140: entry->ifm_media = mword; ! 141: entry->ifm_data = data; ! 142: entry->ifm_aux = aux; ! 143: ! 144: LIST_INSERT_HEAD(&ifm->ifm_list, entry, ifm_list); ! 145: } ! 146: ! 147: /* ! 148: * Add an array of media configurations to the list of ! 149: * supported media for a specific interface instance. ! 150: */ ! 151: void ! 152: ifmedia_list_add(ifm, lp, count) ! 153: struct ifmedia *ifm; ! 154: struct ifmedia_entry *lp; ! 155: int count; ! 156: { ! 157: int i; ! 158: ! 159: for (i = 0; i < count; i++) ! 160: ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data, ! 161: lp[i].ifm_aux); ! 162: } ! 163: ! 164: /* ! 165: * Set the default active media. ! 166: * ! 167: * Called by device-specific code which is assumed to have already ! 168: * selected the default media in hardware. We do _not_ call the ! 169: * media-change callback. ! 170: */ ! 171: void ! 172: ifmedia_set(ifm, target) ! 173: struct ifmedia *ifm; ! 174: int target; ! 175: ! 176: { ! 177: struct ifmedia_entry *match; ! 178: ! 179: match = ifmedia_match(ifm, target, ifm->ifm_mask); ! 180: ! 181: if (match == NULL) { ! 182: printf("ifmedia_set: no match for 0x%x/0x%x\n", ! 183: target, ~ifm->ifm_mask); ! 184: panic("ifmedia_set"); ! 185: } ! 186: ifm->ifm_cur = match; ! 187: ! 188: #ifdef IFMEDIA_DEBUG ! 189: if (ifmedia_debug) { ! 190: printf("ifmedia_set: target "); ! 191: ifmedia_printword(target); ! 192: printf("ifmedia_set: setting to "); ! 193: ifmedia_printword(ifm->ifm_cur->ifm_media); ! 194: } ! 195: #endif ! 196: } ! 197: ! 198: /* ! 199: * Device-independent media ioctl support function. ! 200: */ ! 201: int ! 202: ifmedia_ioctl(ifp, ifr, ifm, cmd) ! 203: struct ifnet *ifp; ! 204: struct ifreq *ifr; ! 205: struct ifmedia *ifm; ! 206: u_long cmd; ! 207: { ! 208: struct ifmedia_entry *match; ! 209: struct ifmediareq *ifmr = (struct ifmediareq *) ifr; ! 210: int error = 0, sticky; ! 211: ! 212: if (ifp == NULL || ifr == NULL || ifm == NULL) ! 213: return(EINVAL); ! 214: ! 215: switch (cmd) { ! 216: ! 217: /* ! 218: * Set the current media. ! 219: */ ! 220: case SIOCSIFMEDIA: ! 221: { ! 222: struct ifmedia_entry *oldentry; ! 223: int oldmedia; ! 224: int newmedia = ifr->ifr_media; ! 225: ! 226: match = ifmedia_match(ifm, newmedia, ifm->ifm_mask); ! 227: if (match == NULL) { ! 228: #ifdef IFMEDIA_DEBUG ! 229: if (ifmedia_debug) { ! 230: printf( ! 231: "ifmedia_ioctl: no media found for 0x%x\n", ! 232: newmedia); ! 233: } ! 234: #endif ! 235: return (ENXIO); ! 236: } ! 237: ! 238: /* ! 239: * If no change, we're done. ! 240: * XXX Automedia may invole software intervention. ! 241: * Keep going in case the the connected media changed. ! 242: * Similarly, if best match changed (kernel debugger?). ! 243: */ ! 244: if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) && ! 245: (newmedia == ifm->ifm_media) && ! 246: (match == ifm->ifm_cur)) ! 247: return 0; ! 248: ! 249: /* ! 250: * We found a match, now make the driver switch to it. ! 251: * Make sure to preserve our old media type in case the ! 252: * driver can't switch. ! 253: */ ! 254: #ifdef IFMEDIA_DEBUG ! 255: if (ifmedia_debug) { ! 256: printf("ifmedia_ioctl: switching %s to ", ! 257: ifp->if_xname); ! 258: ifmedia_printword(match->ifm_media); ! 259: } ! 260: #endif ! 261: oldentry = ifm->ifm_cur; ! 262: oldmedia = ifm->ifm_media; ! 263: ifm->ifm_cur = match; ! 264: ifm->ifm_media = newmedia; ! 265: error = (*ifm->ifm_change)(ifp); ! 266: if (error) { ! 267: ifm->ifm_cur = oldentry; ! 268: ifm->ifm_media = oldmedia; ! 269: } ! 270: break; ! 271: } ! 272: ! 273: /* ! 274: * Get list of available media and current media on interface. ! 275: */ ! 276: case SIOCGIFMEDIA: ! 277: { ! 278: struct ifmedia_entry *ep; ! 279: int *kptr, count; ! 280: ! 281: kptr = NULL; /* XXX gcc */ ! 282: ! 283: ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? ! 284: ifm->ifm_cur->ifm_media : IFM_NONE; ! 285: ifmr->ifm_mask = ifm->ifm_mask; ! 286: ifmr->ifm_status = 0; ! 287: (*ifm->ifm_status)(ifp, ifmr); ! 288: ! 289: count = 0; ! 290: ep = ifm->ifm_list.lh_first; ! 291: ! 292: if (ifmr->ifm_count != 0) { ! 293: kptr = (int *) _MALLOC(ifmr->ifm_count * sizeof(int), ! 294: M_TEMP, M_WAITOK); ! 295: ! 296: /* ! 297: * Get the media words from the interface's list. ! 298: */ ! 299: for (; ep != NULL && count < ifmr->ifm_count; ! 300: ep = ep->ifm_list.le_next, count++) ! 301: kptr[count] = ep->ifm_media; ! 302: ! 303: if (ep != NULL) ! 304: error = E2BIG; /* oops! */ ! 305: } ! 306: ! 307: /* ! 308: * If there are more interfaces on the list, count ! 309: * them. This allows the caller to set ifmr->ifm_count ! 310: * to 0 on the first call to know how much space to ! 311: * callocate. ! 312: */ ! 313: for (; ep != NULL; ep = ep->ifm_list.le_next) ! 314: count++; ! 315: ! 316: /* ! 317: * We do the copyout on E2BIG, because that's ! 318: * just our way of telling userland that there ! 319: * are more. This is the behavior I've observed ! 320: * under BSD/OS 3.0 ! 321: */ ! 322: sticky = error; ! 323: if ((error == 0 || error == E2BIG) && ifmr->ifm_count != 0) { ! 324: error = copyout((caddr_t)kptr, ! 325: (caddr_t)ifmr->ifm_ulist, ! 326: ifmr->ifm_count * sizeof(int)); ! 327: } ! 328: ! 329: if (error == 0) ! 330: error = sticky; ! 331: ! 332: if (ifmr->ifm_count != 0) ! 333: FREE(kptr, M_TEMP); ! 334: ! 335: ifmr->ifm_count = count; ! 336: break; ! 337: } ! 338: ! 339: default: ! 340: return (EINVAL); ! 341: } ! 342: ! 343: return (error); ! 344: } ! 345: ! 346: /* ! 347: * Find media entry matching a given ifm word. ! 348: * ! 349: */ ! 350: static struct ifmedia_entry * ! 351: ifmedia_match(ifm, target, mask) ! 352: struct ifmedia *ifm; ! 353: int target; ! 354: int mask; ! 355: { ! 356: struct ifmedia_entry *match, *next; ! 357: ! 358: match = NULL; ! 359: mask = ~mask; ! 360: ! 361: for (next = ifm->ifm_list.lh_first; next != NULL; ! 362: next = next->ifm_list.le_next) { ! 363: if ((next->ifm_media & mask) == (target & mask)) { ! 364: #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC) ! 365: if (match) { ! 366: printf("ifmedia_match: multiple match for " ! 367: "0x%x/0x%x\n", target, mask); ! 368: } ! 369: #endif ! 370: match = next; ! 371: } ! 372: } ! 373: ! 374: return match; ! 375: } ! 376: ! 377: #ifdef IFMEDIA_DEBUG ! 378: struct ifmedia_description ifm_type_descriptions[] = ! 379: IFM_TYPE_DESCRIPTIONS; ! 380: ! 381: struct ifmedia_description ifm_subtype_ethernet_descriptions[] = ! 382: IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; ! 383: ! 384: struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = ! 385: IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; ! 386: ! 387: struct ifmedia_description ifm_subtype_tokenring_descriptions[] = ! 388: IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; ! 389: ! 390: struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = ! 391: IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; ! 392: ! 393: struct ifmedia_description ifm_subtype_fddi_descriptions[] = ! 394: IFM_SUBTYPE_FDDI_DESCRIPTIONS; ! 395: ! 396: struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = ! 397: IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; ! 398: ! 399: struct ifmedia_description ifm_subtype_shared_descriptions[] = ! 400: IFM_SUBTYPE_SHARED_DESCRIPTIONS; ! 401: ! 402: struct ifmedia_description ifm_shared_option_descriptions[] = ! 403: IFM_SHARED_OPTION_DESCRIPTIONS; ! 404: ! 405: struct ifmedia_type_to_subtype { ! 406: struct ifmedia_description *subtypes; ! 407: struct ifmedia_description *options; ! 408: }; ! 409: ! 410: /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ ! 411: struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { ! 412: { ! 413: &ifm_subtype_ethernet_descriptions[0], ! 414: &ifm_subtype_ethernet_option_descriptions[0] ! 415: }, ! 416: { ! 417: &ifm_subtype_tokenring_descriptions[0], ! 418: &ifm_subtype_tokenring_option_descriptions[0] ! 419: }, ! 420: { ! 421: &ifm_subtype_fddi_descriptions[0], ! 422: &ifm_subtype_fddi_option_descriptions[0] ! 423: }, ! 424: }; ! 425: ! 426: /* ! 427: * print a media word. ! 428: */ ! 429: static void ! 430: ifmedia_printword(ifmw) ! 431: int ifmw; ! 432: { ! 433: struct ifmedia_description *desc; ! 434: struct ifmedia_type_to_subtype *ttos; ! 435: int seen_option = 0; ! 436: ! 437: /* Find the top-level interface type. */ ! 438: for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; ! 439: desc->ifmt_string != NULL; desc++, ttos++) ! 440: if (IFM_TYPE(ifmw) == desc->ifmt_word) ! 441: break; ! 442: if (desc->ifmt_string == NULL) { ! 443: printf("<unknown type>\n"); ! 444: return; ! 445: } ! 446: printf(desc->ifmt_string); ! 447: ! 448: /* ! 449: * Check for the shared subtype descriptions first, then the ! 450: * type-specific ones. ! 451: */ ! 452: for (desc = ifm_subtype_shared_descriptions; ! 453: desc->ifmt_string != NULL; desc++) ! 454: if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) ! 455: goto got_subtype; ! 456: ! 457: for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++) ! 458: if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) ! 459: break; ! 460: if (desc->ifmt_string == NULL) { ! 461: printf(" <unknown subtype>\n"); ! 462: return; ! 463: } ! 464: ! 465: got_subtype: ! 466: printf(" %s", desc->ifmt_string); ! 467: ! 468: /* ! 469: * Look for shared options. ! 470: */ ! 471: for (desc = ifm_shared_option_descriptions; ! 472: desc->ifmt_string != NULL; desc++) { ! 473: if (ifmw & desc->ifmt_word) { ! 474: if (seen_option == 0) ! 475: printf(" <"); ! 476: printf("%s%s", seen_option++ ? "," : "", ! 477: desc->ifmt_string); ! 478: } ! 479: } ! 480: ! 481: /* ! 482: * Look for subtype-specific options. ! 483: */ ! 484: for (desc = ttos->options; desc->ifmt_string != NULL; desc++) { ! 485: if (ifmw & desc->ifmt_word) { ! 486: if (seen_option == 0) ! 487: printf(" <"); ! 488: printf("%s%s", seen_option++ ? "," : "", ! 489: desc->ifmt_string); ! 490: } ! 491: } ! 492: printf("%s\n", seen_option ? ">" : ""); ! 493: } ! 494: #endif /* IFMEDIA_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.