[BACK]Return to if_media.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/if_media.c, Revision 1.1.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