[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     ! 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