Annotation of sys/net/if_media.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_media.c,v 1.16 2005/07/28 02:15:15 brad Exp $ */
! 2: /* $NetBSD: if_media.c,v 1.10 2000/03/13 23:52:39 soren Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 10: * NASA Ames Research Center.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40:
! 41: /*
! 42: * Copyright (c) 1997
! 43: * Jonathan Stone and Jason R. Thorpe. All rights reserved.
! 44: *
! 45: * This software is derived from information provided by Matt Thomas.
! 46: *
! 47: * Redistribution and use in source and binary forms, with or without
! 48: * modification, are permitted provided that the following conditions
! 49: * are met:
! 50: * 1. Redistributions of source code must retain the above copyright
! 51: * notice, this list of conditions and the following disclaimer.
! 52: * 2. Redistributions in binary form must reproduce the above copyright
! 53: * notice, this list of conditions and the following disclaimer in the
! 54: * documentation and/or other materials provided with the distribution.
! 55: * 3. All advertising materials mentioning features or use of this software
! 56: * must display the following acknowledgement:
! 57: * This product includes software developed by Jonathan Stone
! 58: * and Jason R. Thorpe for the NetBSD Project.
! 59: * 4. The names of the authors may not be used to endorse or promote products
! 60: * derived from this software without specific prior written permission.
! 61: *
! 62: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
! 63: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 64: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 65: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 66: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
! 67: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 68: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
! 69: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! 70: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 72: * SUCH DAMAGE.
! 73: */
! 74:
! 75: /*
! 76: * BSD/OS-compatible network interface media selection.
! 77: *
! 78: * Where it is safe to do so, this code strays slightly from the BSD/OS
! 79: * design. Software which uses the API (device drivers, basically)
! 80: * shouldn't notice any difference.
! 81: *
! 82: * Many thanks to Matt Thomas for providing the information necessary
! 83: * to implement this interface.
! 84: */
! 85:
! 86: #include <sys/param.h>
! 87: #include <sys/systm.h>
! 88: #include <sys/errno.h>
! 89: #include <sys/ioctl.h>
! 90: #include <sys/socket.h>
! 91: #include <sys/malloc.h>
! 92:
! 93: #include <net/if.h>
! 94: #include <net/if_media.h>
! 95: #include <net/netisr.h>
! 96:
! 97: /*
! 98: * Compile-time options:
! 99: * IFMEDIA_DEBUG:
! 100: * turn on implementation-level debug printfs.
! 101: * Useful for debugging newly-ported drivers.
! 102: */
! 103:
! 104: #ifdef IFMEDIA_DEBUG
! 105: int ifmedia_debug = 0;
! 106: static void ifmedia_printword(int);
! 107: #endif
! 108:
! 109: /*
! 110: * Initialize if_media struct for a specific interface instance.
! 111: */
! 112: void
! 113: ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
! 114: ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
! 115: {
! 116: TAILQ_INIT(&ifm->ifm_list);
! 117: ifm->ifm_cur = NULL;
! 118: ifm->ifm_media = 0;
! 119: ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */
! 120: ifm->ifm_change = change_callback;
! 121: ifm->ifm_status = status_callback;
! 122: }
! 123:
! 124: /*
! 125: * Add a media configuration to the list of supported media
! 126: * for a specific interface instance.
! 127: */
! 128: void
! 129: ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux)
! 130: {
! 131: struct ifmedia_entry *entry;
! 132:
! 133: #ifdef IFMEDIA_DEBUG
! 134: if (ifmedia_debug) {
! 135: if (ifm == NULL) {
! 136: printf("ifmedia_add: null ifm\n");
! 137: return;
! 138: }
! 139: printf("Adding entry for ");
! 140: ifmedia_printword(mword);
! 141: }
! 142: #endif
! 143:
! 144: entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT);
! 145: if (entry == NULL)
! 146: panic("ifmedia_add: can't malloc entry");
! 147:
! 148: entry->ifm_media = mword;
! 149: entry->ifm_data = data;
! 150: entry->ifm_aux = aux;
! 151:
! 152: TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list);
! 153: }
! 154:
! 155: /*
! 156: * Add an array of media configurations to the list of
! 157: * supported media for a specific interface instance.
! 158: */
! 159: void
! 160: ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count)
! 161: {
! 162: int i;
! 163:
! 164: for (i = 0; i < count; i++)
! 165: ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
! 166: lp[i].ifm_aux);
! 167: }
! 168:
! 169: /*
! 170: * Set the default active media.
! 171: *
! 172: * Called by device-specific code which is assumed to have already
! 173: * selected the default media in hardware. We do _not_ call the
! 174: * media-change callback.
! 175: */
! 176: void
! 177: ifmedia_set(struct ifmedia *ifm, int target)
! 178: {
! 179: struct ifmedia_entry *match;
! 180:
! 181: match = ifmedia_match(ifm, target, ifm->ifm_mask);
! 182:
! 183: /*
! 184: * If we didn't find the requested media, then we try to fall
! 185: * back to target-type (IFM_ETHER, e.g.) | IFM_NONE. If that's
! 186: * not on the list, then we add it and set the media to it.
! 187: *
! 188: * Since ifmedia_set is almost always called with IFM_AUTO or
! 189: * with a known-good media, this really should only occur if we:
! 190: *
! 191: * a) didn't find any PHYs, or
! 192: * b) didn't find an autoselect option on the PHY when the
! 193: * parent ethernet driver expected to.
! 194: *
! 195: * In either case, it makes sense to select no media.
! 196: */
! 197: if (match == NULL) {
! 198: printf("ifmedia_set: no match for 0x%x/0x%x\n",
! 199: target, ~ifm->ifm_mask);
! 200: target = (target & IFM_NMASK) | IFM_NONE;
! 201: match = ifmedia_match(ifm, target, ifm->ifm_mask);
! 202: if (match == NULL) {
! 203: ifmedia_add(ifm, target, 0, NULL);
! 204: match = ifmedia_match(ifm, target, ifm->ifm_mask);
! 205: if (match == NULL) {
! 206: panic("ifmedia_set failed");
! 207: }
! 208: }
! 209: }
! 210: ifm->ifm_cur = match;
! 211:
! 212: #ifdef IFMEDIA_DEBUG
! 213: if (ifmedia_debug) {
! 214: printf("ifmedia_set: target ");
! 215: ifmedia_printword(target);
! 216: printf("ifmedia_set: setting to ");
! 217: ifmedia_printword(ifm->ifm_cur->ifm_media);
! 218: }
! 219: #endif
! 220: }
! 221:
! 222: /*
! 223: * Device-independent media ioctl support function.
! 224: */
! 225: int
! 226: ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
! 227: u_long cmd)
! 228: {
! 229: struct ifmedia_entry *match;
! 230: struct ifmediareq *ifmr = (struct ifmediareq *) ifr;
! 231: int error = 0;
! 232:
! 233: if (ifp == NULL || ifr == NULL || ifm == NULL)
! 234: return (EINVAL);
! 235:
! 236: switch (cmd) {
! 237:
! 238: /*
! 239: * Set the current media.
! 240: */
! 241: case SIOCSIFMEDIA:
! 242: {
! 243: struct ifmedia_entry *oldentry;
! 244: u_int oldmedia;
! 245: u_int newmedia = ifr->ifr_media;
! 246:
! 247: match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
! 248: if (match == NULL) {
! 249: #ifdef IFMEDIA_DEBUG
! 250: if (ifmedia_debug) {
! 251: printf(
! 252: "ifmedia_ioctl: no media found for 0x%x\n",
! 253: newmedia);
! 254: }
! 255: #endif
! 256: return (EINVAL);
! 257: }
! 258:
! 259: /*
! 260: * If no change, we're done.
! 261: * XXX Automedia may involve software intervention.
! 262: * Keep going in case the connected media changed.
! 263: * Similarly, if best match changed (kernel debugger?).
! 264: */
! 265: if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
! 266: (newmedia == ifm->ifm_media) &&
! 267: (match == ifm->ifm_cur))
! 268: return 0;
! 269:
! 270: /*
! 271: * We found a match, now make the driver switch to it.
! 272: * Make sure to preserve our old media type in case the
! 273: * driver can't switch.
! 274: */
! 275: #ifdef IFMEDIA_DEBUG
! 276: if (ifmedia_debug) {
! 277: printf("ifmedia_ioctl: switching %s to ",
! 278: ifp->if_xname);
! 279: ifmedia_printword(match->ifm_media);
! 280: }
! 281: #endif
! 282: oldentry = ifm->ifm_cur;
! 283: oldmedia = ifm->ifm_media;
! 284: ifm->ifm_cur = match;
! 285: ifm->ifm_media = newmedia;
! 286: error = (*ifm->ifm_change)(ifp);
! 287: if (error) {
! 288: ifm->ifm_cur = oldentry;
! 289: ifm->ifm_media = oldmedia;
! 290: }
! 291: break;
! 292: }
! 293:
! 294: /*
! 295: * Get list of available media and current media on interface.
! 296: */
! 297: case SIOCGIFMEDIA:
! 298: {
! 299: struct ifmedia_entry *ep;
! 300: size_t nwords;
! 301:
! 302: if(ifmr->ifm_count < 0)
! 303: return (EINVAL);
! 304:
! 305: ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
! 306: ifm->ifm_cur->ifm_media : IFM_NONE;
! 307: ifmr->ifm_mask = ifm->ifm_mask;
! 308: ifmr->ifm_status = 0;
! 309: (*ifm->ifm_status)(ifp, ifmr);
! 310:
! 311: /*
! 312: * Count them so we know a-priori how much is the max we'll
! 313: * need.
! 314: */
! 315: ep = TAILQ_FIRST(&ifm->ifm_list);
! 316: for (nwords = 0; ep != NULL; ep = TAILQ_NEXT(ep, ifm_list))
! 317: nwords++;
! 318:
! 319: if (ifmr->ifm_count != 0) {
! 320: size_t count;
! 321: size_t minwords = nwords > (size_t)ifmr->ifm_count
! 322: ? (size_t)ifmr->ifm_count
! 323: : nwords;
! 324: int *kptr = (int *)malloc(minwords * sizeof(int),
! 325: M_TEMP, M_WAITOK);
! 326: /*
! 327: * Get the media words from the interface's list.
! 328: */
! 329: ep = TAILQ_FIRST(&ifm->ifm_list);
! 330: for (count = 0; ep != NULL && count < minwords;
! 331: ep = TAILQ_NEXT(ep, ifm_list), count++)
! 332: kptr[count] = ep->ifm_media;
! 333:
! 334: error = copyout(kptr, ifmr->ifm_ulist,
! 335: minwords * sizeof(int));
! 336: if (error == 0 && ep != NULL)
! 337: error = E2BIG; /* oops! */
! 338: free(kptr, M_TEMP);
! 339: }
! 340: ifmr->ifm_count = nwords;
! 341: break;
! 342: }
! 343:
! 344: default:
! 345: return (EINVAL);
! 346: }
! 347:
! 348: return (error);
! 349: }
! 350:
! 351: /*
! 352: * Find media entry matching a given ifm word.
! 353: */
! 354: struct ifmedia_entry *
! 355: ifmedia_match(struct ifmedia *ifm, u_int target, u_int mask)
! 356: {
! 357: struct ifmedia_entry *match, *next;
! 358:
! 359: match = NULL;
! 360: mask = ~mask;
! 361:
! 362: for (next = TAILQ_FIRST(&ifm->ifm_list); next != NULL;
! 363: next = TAILQ_NEXT(next, ifm_list)) {
! 364: if ((next->ifm_media & mask) == (target & mask)) {
! 365: if (match) {
! 366: #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
! 367: printf("ifmedia_match: multiple match for "
! 368: "0x%x/0x%x, selected instance %d\n",
! 369: target, mask, IFM_INST(match->ifm_media));
! 370: #endif
! 371: break;
! 372: }
! 373: match = next;
! 374: }
! 375: }
! 376:
! 377: return match;
! 378: }
! 379:
! 380: /*
! 381: * Delete all media for a given instance.
! 382: */
! 383: void
! 384: ifmedia_delete_instance(struct ifmedia *ifm, u_int inst)
! 385: {
! 386: struct ifmedia_entry *ife, *nife;
! 387:
! 388: for (ife = TAILQ_FIRST(&ifm->ifm_list); ife != NULL;
! 389: ife = nife) {
! 390: nife = TAILQ_NEXT(ife, ifm_list);
! 391: if (inst == IFM_INST_ANY ||
! 392: inst == IFM_INST(ife->ifm_media)) {
! 393: TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list);
! 394: free(ife, M_IFADDR);
! 395: }
! 396: }
! 397: }
! 398:
! 399: /*
! 400: * Compute the interface `baudrate' from the media, for the interface
! 401: * metrics (used by routing daemons).
! 402: */
! 403: struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
! 404: IFM_BAUDRATE_DESCRIPTIONS;
! 405:
! 406: int
! 407: ifmedia_baudrate(int mword)
! 408: {
! 409: int i;
! 410:
! 411: for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
! 412: if ((mword & (IFM_NMASK|IFM_TMASK)) ==
! 413: ifmedia_baudrate_descriptions[i].ifmb_word)
! 414: return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
! 415: }
! 416:
! 417: /* Not known. */
! 418: return (0);
! 419: }
! 420:
! 421: #ifdef IFMEDIA_DEBUG
! 422:
! 423: struct ifmedia_description ifm_type_descriptions[] =
! 424: IFM_TYPE_DESCRIPTIONS;
! 425:
! 426: struct ifmedia_description ifm_subtype_descriptions[] =
! 427: IFM_SUBTYPE_DESCRIPTIONS;
! 428:
! 429: struct ifmedia_description ifm_option_descriptions[] =
! 430: IFM_OPTION_DESCRIPTIONS;
! 431:
! 432: /*
! 433: * print a media word.
! 434: */
! 435: static void
! 436: ifmedia_printword(int ifmw)
! 437: {
! 438: struct ifmedia_description *desc;
! 439: int seen_option = 0;
! 440:
! 441: /* Print the top-level interface type. */
! 442: for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
! 443: desc++) {
! 444: if (IFM_TYPE(ifmw) == desc->ifmt_word)
! 445: break;
! 446: }
! 447: if (desc->ifmt_string == NULL)
! 448: printf("<unknown type> ");
! 449: else
! 450: printf("%s ", desc->ifmt_string);
! 451:
! 452: /* Print the subtype. */
! 453: for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
! 454: desc++) {
! 455: if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
! 456: IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifmw))
! 457: break;
! 458: }
! 459: if (desc->ifmt_string == NULL)
! 460: printf("<unknown subtype>");
! 461: else
! 462: printf("%s", desc->ifmt_string);
! 463:
! 464: /* Print any options. */
! 465: for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
! 466: desc++) {
! 467: if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
! 468: (ifmw & desc->ifmt_word) != 0 &&
! 469: (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
! 470: if (seen_option == 0)
! 471: printf(" <");
! 472: printf("%s%s", seen_option ? "," : "",
! 473: desc->ifmt_string);
! 474: seen_option |= IFM_OPTIONS(desc->ifmt_word);
! 475: }
! 476: }
! 477: printf("%s\n", seen_option ? ">" : "");
! 478: }
! 479:
! 480: #endif /* IFMEDIA_DEBUG */
CVSweb