[BACK]Return to ieee80211.c CVS log [TXT][DIR] Up to [local] / sys / net80211

Annotation of sys/net80211/ieee80211.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ieee80211.c,v 1.24 2007/07/03 20:25:32 damien Exp $   */
        !             2: /*     $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $    */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2001 Atsushi Onoe
        !             6:  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. The name of the author may not be used to endorse or promote products
        !            18:  *    derived from this software without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            21:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            22:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            23:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            24:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            25:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            26:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            27:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            29:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            30:  */
        !            31:
        !            32: /*
        !            33:  * IEEE 802.11 generic handler
        !            34:  */
        !            35:
        !            36: #include "bpfilter.h"
        !            37:
        !            38: #include <sys/param.h>
        !            39: #include <sys/systm.h>
        !            40: #include <sys/mbuf.h>
        !            41: #include <sys/kernel.h>
        !            42: #include <sys/socket.h>
        !            43: #include <sys/sockio.h>
        !            44: #include <sys/endian.h>
        !            45: #include <sys/errno.h>
        !            46: #include <sys/proc.h>
        !            47: #include <sys/sysctl.h>
        !            48:
        !            49: #include <net/if.h>
        !            50: #include <net/if_dl.h>
        !            51: #include <net/if_media.h>
        !            52: #include <net/if_arp.h>
        !            53: #include <net/if_llc.h>
        !            54:
        !            55: #if NBPFILTER > 0
        !            56: #include <net/bpf.h>
        !            57: #endif
        !            58:
        !            59: #ifdef INET
        !            60: #include <netinet/in.h>
        !            61: #include <netinet/if_ether.h>
        !            62: #endif
        !            63:
        !            64: #include <net80211/ieee80211_var.h>
        !            65:
        !            66: #ifdef IEEE80211_DEBUG
        !            67: int    ieee80211_debug = 0;
        !            68: #endif
        !            69:
        !            70: int ieee80211_cache_size = IEEE80211_CACHE_SIZE;
        !            71:
        !            72: struct ieee80211com_head ieee80211com_head =
        !            73:     LIST_HEAD_INITIALIZER(ieee80211com_head);
        !            74:
        !            75: void ieee80211_setbasicrates(struct ieee80211com *);
        !            76: int ieee80211_findrate(struct ieee80211com *, enum ieee80211_phymode, int);
        !            77:
        !            78: void
        !            79: ieee80211_ifattach(struct ifnet *ifp)
        !            80: {
        !            81:        struct ieee80211com *ic = (void *)ifp;
        !            82:        struct ieee80211_channel *c;
        !            83:        int i;
        !            84:
        !            85:        memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr,
        !            86:                ETHER_ADDR_LEN);
        !            87:        ether_ifattach(ifp);
        !            88:
        !            89:        ifp->if_output = ieee80211_output;
        !            90:
        !            91: #if NBPFILTER > 0
        !            92:        bpfattach(&ic->ic_rawbpf, ifp, DLT_IEEE802_11,
        !            93:            sizeof(struct ieee80211_frame_addr4));
        !            94: #endif
        !            95:        ieee80211_crypto_attach(ifp);
        !            96:
        !            97:        /*
        !            98:         * Fill in 802.11 available channel set, mark
        !            99:         * all available channels as active, and pick
        !           100:         * a default channel if not already specified.
        !           101:         */
        !           102:        memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
        !           103:        ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO;
        !           104:        for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
        !           105:                c = &ic->ic_channels[i];
        !           106:                if (c->ic_flags) {
        !           107:                        /*
        !           108:                         * Verify driver passed us valid data.
        !           109:                         */
        !           110:                        if (i != ieee80211_chan2ieee(ic, c)) {
        !           111:                                printf("%s: bad channel ignored; "
        !           112:                                        "freq %u flags %x number %u\n",
        !           113:                                        ifp->if_xname, c->ic_freq, c->ic_flags,
        !           114:                                        i);
        !           115:                                c->ic_flags = 0;        /* NB: remove */
        !           116:                                continue;
        !           117:                        }
        !           118:                        setbit(ic->ic_chan_avail, i);
        !           119:                        /*
        !           120:                         * Identify mode capabilities.
        !           121:                         */
        !           122:                        if (IEEE80211_IS_CHAN_A(c))
        !           123:                                ic->ic_modecaps |= 1<<IEEE80211_MODE_11A;
        !           124:                        if (IEEE80211_IS_CHAN_B(c))
        !           125:                                ic->ic_modecaps |= 1<<IEEE80211_MODE_11B;
        !           126:                        if (IEEE80211_IS_CHAN_PUREG(c))
        !           127:                                ic->ic_modecaps |= 1<<IEEE80211_MODE_11G;
        !           128:                        if (IEEE80211_IS_CHAN_FHSS(c))
        !           129:                                ic->ic_modecaps |= 1<<IEEE80211_MODE_FH;
        !           130:                        if (IEEE80211_IS_CHAN_T(c))
        !           131:                                ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO;
        !           132:                }
        !           133:        }
        !           134:        /* validate ic->ic_curmode */
        !           135:        if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0)
        !           136:                ic->ic_curmode = IEEE80211_MODE_AUTO;
        !           137:        ic->ic_des_chan = IEEE80211_CHAN_ANYC;  /* any channel is ok */
        !           138:        ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED;
        !           139:
        !           140:        /* IEEE 802.11 defines a MTU >= 2290 */
        !           141:        ifp->if_capabilities |= IFCAP_VLAN_MTU;
        !           142:
        !           143:        ieee80211_setbasicrates(ic);
        !           144:        (void) ieee80211_setmode(ic, ic->ic_curmode);
        !           145:
        !           146:        if (ic->ic_lintval == 0)
        !           147:                ic->ic_lintval = 100;           /* default sleep */
        !           148:        ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
        !           149:        ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
        !           150:
        !           151:        LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
        !           152:        ieee80211_node_attach(ifp);
        !           153:        ieee80211_proto_attach(ifp);
        !           154:
        !           155:        if_addgroup(ifp, "wlan");
        !           156: }
        !           157:
        !           158: void
        !           159: ieee80211_ifdetach(struct ifnet *ifp)
        !           160: {
        !           161:        struct ieee80211com *ic = (void *)ifp;
        !           162:
        !           163:        ieee80211_proto_detach(ifp);
        !           164:        ieee80211_crypto_detach(ifp);
        !           165:        ieee80211_node_detach(ifp);
        !           166:        LIST_REMOVE(ic, ic_list);
        !           167:        ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY);
        !           168:        ether_ifdetach(ifp);
        !           169: }
        !           170:
        !           171: /*
        !           172:  * Convert MHz frequency to IEEE channel number.
        !           173:  */
        !           174: u_int
        !           175: ieee80211_mhz2ieee(u_int freq, u_int flags)
        !           176: {
        !           177:        if (flags & IEEE80211_CHAN_2GHZ) {      /* 2GHz band */
        !           178:                if (freq == 2484)
        !           179:                        return 14;
        !           180:                if (freq < 2484)
        !           181:                        return (freq - 2407) / 5;
        !           182:                else
        !           183:                        return 15 + ((freq - 2512) / 20);
        !           184:        } else if (flags & IEEE80211_CHAN_5GHZ) {       /* 5Ghz band */
        !           185:                return (freq - 5000) / 5;
        !           186:        } else {                                /* either, guess */
        !           187:                if (freq == 2484)
        !           188:                        return 14;
        !           189:                if (freq < 2484)
        !           190:                        return (freq - 2407) / 5;
        !           191:                if (freq < 5000)
        !           192:                        return 15 + ((freq - 2512) / 20);
        !           193:                return (freq - 5000) / 5;
        !           194:        }
        !           195: }
        !           196:
        !           197: /*
        !           198:  * Convert channel to IEEE channel number.
        !           199:  */
        !           200: u_int
        !           201: ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
        !           202: {
        !           203:        struct ifnet *ifp = &ic->ic_if;
        !           204:        if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX])
        !           205:                return c - ic->ic_channels;
        !           206:        else if (c == IEEE80211_CHAN_ANYC)
        !           207:                return IEEE80211_CHAN_ANY;
        !           208:        else if (c != NULL) {
        !           209:                printf("%s: invalid channel freq %u flags %x\n",
        !           210:                        ifp->if_xname, c->ic_freq, c->ic_flags);
        !           211:                return 0;               /* XXX */
        !           212:        } else {
        !           213:                printf("%s: invalid channel (NULL)\n", ifp->if_xname);
        !           214:                return 0;               /* XXX */
        !           215:        }
        !           216: }
        !           217:
        !           218: /*
        !           219:  * Convert IEEE channel number to MHz frequency.
        !           220:  */
        !           221: u_int
        !           222: ieee80211_ieee2mhz(u_int chan, u_int flags)
        !           223: {
        !           224:        if (flags & IEEE80211_CHAN_2GHZ) {      /* 2GHz band */
        !           225:                if (chan == 14)
        !           226:                        return 2484;
        !           227:                if (chan < 14)
        !           228:                        return 2407 + chan*5;
        !           229:                else
        !           230:                        return 2512 + ((chan-15)*20);
        !           231:        } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
        !           232:                return 5000 + (chan*5);
        !           233:        } else {                                /* either, guess */
        !           234:                if (chan == 14)
        !           235:                        return 2484;
        !           236:                if (chan < 14)                  /* 0-13 */
        !           237:                        return 2407 + chan*5;
        !           238:                if (chan < 27)                  /* 15-26 */
        !           239:                        return 2512 + ((chan-15)*20);
        !           240:                return 5000 + (chan*5);
        !           241:        }
        !           242: }
        !           243:
        !           244: /*
        !           245:  * Setup the media data structures according to the channel and
        !           246:  * rate tables.  This must be called by the driver after
        !           247:  * ieee80211_attach and before most anything else.
        !           248:  */
        !           249: void
        !           250: ieee80211_media_init(struct ifnet *ifp,
        !           251:        ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
        !           252: {
        !           253: #define        ADD(_ic, _s, _o) \
        !           254:        ifmedia_add(&(_ic)->ic_media, \
        !           255:                IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
        !           256:        struct ieee80211com *ic = (void *)ifp;
        !           257:        struct ifmediareq imr;
        !           258:        int i, j, mode, rate, maxrate, mword, mopt, r;
        !           259:        const struct ieee80211_rateset *rs;
        !           260:        struct ieee80211_rateset allrates;
        !           261:
        !           262:        /*
        !           263:         * Do late attach work that must wait for any subclass
        !           264:         * (i.e. driver) work such as overriding methods.
        !           265:         */
        !           266:        ieee80211_node_lateattach(ifp);
        !           267:
        !           268:        /*
        !           269:         * Fill in media characteristics.
        !           270:         */
        !           271:        ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
        !           272:        maxrate = 0;
        !           273:        memset(&allrates, 0, sizeof(allrates));
        !           274:        for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) {
        !           275:                static const u_int mopts[] = {
        !           276:                        IFM_AUTO,
        !           277:                        IFM_IEEE80211_11A,
        !           278:                        IFM_IEEE80211_11B,
        !           279:                        IFM_IEEE80211_11G,
        !           280:                        IFM_IEEE80211_FH,
        !           281:                        IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
        !           282:                };
        !           283:                if ((ic->ic_modecaps & (1<<mode)) == 0)
        !           284:                        continue;
        !           285:                mopt = mopts[mode];
        !           286:                ADD(ic, IFM_AUTO, mopt);        /* e.g. 11a auto */
        !           287:                if (ic->ic_caps & IEEE80211_C_IBSS)
        !           288:                        ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS);
        !           289:                if (ic->ic_caps & IEEE80211_C_HOSTAP)
        !           290:                        ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP);
        !           291:                if (ic->ic_caps & IEEE80211_C_AHDEMO)
        !           292:                        ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC);
        !           293:                if (ic->ic_caps & IEEE80211_C_MONITOR)
        !           294:                        ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR);
        !           295:                if (mode == IEEE80211_MODE_AUTO)
        !           296:                        continue;
        !           297:                rs = &ic->ic_sup_rates[mode];
        !           298:                for (i = 0; i < rs->rs_nrates; i++) {
        !           299:                        rate = rs->rs_rates[i];
        !           300:                        mword = ieee80211_rate2media(ic, rate, mode);
        !           301:                        if (mword == 0)
        !           302:                                continue;
        !           303:                        ADD(ic, mword, mopt);
        !           304:                        if (ic->ic_caps & IEEE80211_C_IBSS)
        !           305:                                ADD(ic, mword, mopt | IFM_IEEE80211_IBSS);
        !           306:                        if (ic->ic_caps & IEEE80211_C_HOSTAP)
        !           307:                                ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
        !           308:                        if (ic->ic_caps & IEEE80211_C_AHDEMO)
        !           309:                                ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
        !           310:                        if (ic->ic_caps & IEEE80211_C_MONITOR)
        !           311:                                ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
        !           312:                        /*
        !           313:                         * Add rate to the collection of all rates.
        !           314:                         */
        !           315:                        r = rate & IEEE80211_RATE_VAL;
        !           316:                        for (j = 0; j < allrates.rs_nrates; j++)
        !           317:                                if (allrates.rs_rates[j] == r)
        !           318:                                        break;
        !           319:                        if (j == allrates.rs_nrates) {
        !           320:                                /* unique, add to the set */
        !           321:                                allrates.rs_rates[j] = r;
        !           322:                                allrates.rs_nrates++;
        !           323:                        }
        !           324:                        rate = (rate & IEEE80211_RATE_VAL) / 2;
        !           325:                        if (rate > maxrate)
        !           326:                                maxrate = rate;
        !           327:                }
        !           328:        }
        !           329:        for (i = 0; i < allrates.rs_nrates; i++) {
        !           330:                mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
        !           331:                                IEEE80211_MODE_AUTO);
        !           332:                if (mword == 0)
        !           333:                        continue;
        !           334:                mword = IFM_SUBTYPE(mword);     /* remove media options */
        !           335:                ADD(ic, mword, 0);
        !           336:                if (ic->ic_caps & IEEE80211_C_IBSS)
        !           337:                        ADD(ic, mword, IFM_IEEE80211_IBSS);
        !           338:                if (ic->ic_caps & IEEE80211_C_HOSTAP)
        !           339:                        ADD(ic, mword, IFM_IEEE80211_HOSTAP);
        !           340:                if (ic->ic_caps & IEEE80211_C_AHDEMO)
        !           341:                        ADD(ic, mword, IFM_IEEE80211_ADHOC);
        !           342:                if (ic->ic_caps & IEEE80211_C_MONITOR)
        !           343:                        ADD(ic, mword, IFM_IEEE80211_MONITOR);
        !           344:        }
        !           345:        ieee80211_media_status(ifp, &imr);
        !           346:        ifmedia_set(&ic->ic_media, imr.ifm_active);
        !           347:
        !           348:        if (maxrate)
        !           349:                ifp->if_baudrate = IF_Mbps(maxrate);
        !           350:
        !           351: #undef ADD
        !           352: }
        !           353:
        !           354: int
        !           355: ieee80211_findrate(struct ieee80211com *ic, enum ieee80211_phymode mode,
        !           356:     int rate)
        !           357: {
        !           358: #define        IEEERATE(_ic,_m,_i) \
        !           359:        ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
        !           360:        int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
        !           361:        for (i = 0; i < nrates; i++)
        !           362:                if (IEEERATE(ic, mode, i) == rate)
        !           363:                        return i;
        !           364:        return -1;
        !           365: #undef IEEERATE
        !           366: }
        !           367:
        !           368: /*
        !           369:  * Handle a media change request.
        !           370:  */
        !           371: int
        !           372: ieee80211_media_change(struct ifnet *ifp)
        !           373: {
        !           374:        struct ieee80211com *ic = (void *)ifp;
        !           375:        struct ifmedia_entry *ime;
        !           376:        enum ieee80211_opmode newopmode;
        !           377:        enum ieee80211_phymode newphymode;
        !           378:        int i, j, newrate, error = 0;
        !           379:
        !           380:        ime = ic->ic_media.ifm_cur;
        !           381:        /*
        !           382:         * First, identify the phy mode.
        !           383:         */
        !           384:        switch (IFM_MODE(ime->ifm_media)) {
        !           385:        case IFM_IEEE80211_11A:
        !           386:                newphymode = IEEE80211_MODE_11A;
        !           387:                break;
        !           388:        case IFM_IEEE80211_11B:
        !           389:                newphymode = IEEE80211_MODE_11B;
        !           390:                break;
        !           391:        case IFM_IEEE80211_11G:
        !           392:                newphymode = IEEE80211_MODE_11G;
        !           393:                break;
        !           394:        case IFM_IEEE80211_FH:
        !           395:                newphymode = IEEE80211_MODE_FH;
        !           396:                break;
        !           397:        case IFM_AUTO:
        !           398:                newphymode = IEEE80211_MODE_AUTO;
        !           399:                break;
        !           400:        default:
        !           401:                return EINVAL;
        !           402:        }
        !           403:        /*
        !           404:         * Turbo mode is an ``option''.  Eventually it
        !           405:         * needs to be applied to 11g too.
        !           406:         */
        !           407:        if (ime->ifm_media & IFM_IEEE80211_TURBO) {
        !           408:                if (newphymode != IEEE80211_MODE_11A)
        !           409:                        return EINVAL;
        !           410:                newphymode = IEEE80211_MODE_TURBO;
        !           411:        }
        !           412:        /*
        !           413:         * Validate requested mode is available.
        !           414:         */
        !           415:        if ((ic->ic_modecaps & (1<<newphymode)) == 0)
        !           416:                return EINVAL;
        !           417:
        !           418:        /*
        !           419:         * Next, the fixed/variable rate.
        !           420:         */
        !           421:        i = -1;
        !           422:        if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
        !           423:                /*
        !           424:                 * Convert media subtype to rate.
        !           425:                 */
        !           426:                newrate = ieee80211_media2rate(ime->ifm_media);
        !           427:                if (newrate == 0)
        !           428:                        return EINVAL;
        !           429:                /*
        !           430:                 * Check the rate table for the specified/current phy.
        !           431:                 */
        !           432:                if (newphymode == IEEE80211_MODE_AUTO) {
        !           433:                        /*
        !           434:                         * In autoselect mode search for the rate.
        !           435:                         */
        !           436:                        for (j = IEEE80211_MODE_11A;
        !           437:                             j < IEEE80211_MODE_MAX; j++) {
        !           438:                                if ((ic->ic_modecaps & (1<<j)) == 0)
        !           439:                                        continue;
        !           440:                                i = ieee80211_findrate(ic, j, newrate);
        !           441:                                if (i != -1) {
        !           442:                                        /* lock mode too */
        !           443:                                        newphymode = j;
        !           444:                                        break;
        !           445:                                }
        !           446:                        }
        !           447:                } else {
        !           448:                        i = ieee80211_findrate(ic, newphymode, newrate);
        !           449:                }
        !           450:                if (i == -1)                    /* mode/rate mismatch */
        !           451:                        return EINVAL;
        !           452:        }
        !           453:        /* NB: defer rate setting to later */
        !           454:
        !           455:        /*
        !           456:         * Deduce new operating mode but don't install it just yet.
        !           457:         */
        !           458:        if (ime->ifm_media & IFM_IEEE80211_ADHOC)
        !           459:                newopmode = IEEE80211_M_AHDEMO;
        !           460:        else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
        !           461:                newopmode = IEEE80211_M_HOSTAP;
        !           462:        else if (ime->ifm_media & IFM_IEEE80211_IBSS)
        !           463:                newopmode = IEEE80211_M_IBSS;
        !           464:        else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
        !           465:                newopmode = IEEE80211_M_MONITOR;
        !           466:        else
        !           467:                newopmode = IEEE80211_M_STA;
        !           468:
        !           469:        /*
        !           470:         * Autoselect doesn't make sense when operating as an AP.
        !           471:         * If no phy mode has been selected, pick one and lock it
        !           472:         * down so rate tables can be used in forming beacon frames
        !           473:         * and the like.
        !           474:         */
        !           475:        if (newopmode == IEEE80211_M_HOSTAP &&
        !           476:            newphymode == IEEE80211_MODE_AUTO) {
        !           477:                for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++)
        !           478:                        if (ic->ic_modecaps & (1<<j)) {
        !           479:                                newphymode = j;
        !           480:                                break;
        !           481:                        }
        !           482:        }
        !           483:
        !           484:        /*
        !           485:         * Handle phy mode change.
        !           486:         */
        !           487:        if (ic->ic_curmode != newphymode) {             /* change phy mode */
        !           488:                error = ieee80211_setmode(ic, newphymode);
        !           489:                if (error != 0)
        !           490:                        return error;
        !           491:                error = ENETRESET;
        !           492:        }
        !           493:
        !           494:        /*
        !           495:         * Committed to changes, install the rate setting.
        !           496:         */
        !           497:        if (ic->ic_fixed_rate != i) {
        !           498:                ic->ic_fixed_rate = i;                  /* set fixed tx rate */
        !           499:                error = ENETRESET;
        !           500:        }
        !           501:
        !           502:        /*
        !           503:         * Handle operating mode change.
        !           504:         */
        !           505:        if (ic->ic_opmode != newopmode) {
        !           506:                ic->ic_opmode = newopmode;
        !           507:                switch (newopmode) {
        !           508:                case IEEE80211_M_AHDEMO:
        !           509:                case IEEE80211_M_HOSTAP:
        !           510:                case IEEE80211_M_STA:
        !           511:                case IEEE80211_M_MONITOR:
        !           512:                        ic->ic_flags &= ~IEEE80211_F_IBSSON;
        !           513:                        break;
        !           514:                case IEEE80211_M_IBSS:
        !           515:                        ic->ic_flags |= IEEE80211_F_IBSSON;
        !           516:                        break;
        !           517:                }
        !           518:                /*
        !           519:                 * Yech, slot time may change depending on the
        !           520:                 * operating mode so reset it to be sure everything
        !           521:                 * is setup appropriately.
        !           522:                 */
        !           523:                ieee80211_reset_erp(ic);
        !           524:                error = ENETRESET;
        !           525:        }
        !           526: #ifdef notdef
        !           527:        if (error == 0)
        !           528:                ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
        !           529: #endif
        !           530:        return error;
        !           531: }
        !           532:
        !           533: void
        !           534: ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
        !           535: {
        !           536:        struct ieee80211com *ic = (void *)ifp;
        !           537:        const struct ieee80211_node *ni = NULL;
        !           538:
        !           539:        imr->ifm_status = IFM_AVALID;
        !           540:        imr->ifm_active = IFM_IEEE80211;
        !           541:        if (ic->ic_state == IEEE80211_S_RUN)
        !           542:                imr->ifm_status |= IFM_ACTIVE;
        !           543:        imr->ifm_active |= IFM_AUTO;
        !           544:        switch (ic->ic_opmode) {
        !           545:        case IEEE80211_M_STA:
        !           546:                ni = ic->ic_bss;
        !           547:                /* calculate rate subtype */
        !           548:                imr->ifm_active |= ieee80211_rate2media(ic,
        !           549:                        ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
        !           550:                break;
        !           551:        case IEEE80211_M_IBSS:
        !           552:                imr->ifm_active |= IFM_IEEE80211_IBSS;
        !           553:                break;
        !           554:        case IEEE80211_M_AHDEMO:
        !           555:                imr->ifm_active |= IFM_IEEE80211_ADHOC;
        !           556:                break;
        !           557:        case IEEE80211_M_HOSTAP:
        !           558:                imr->ifm_active |= IFM_IEEE80211_HOSTAP;
        !           559:                break;
        !           560:        case IEEE80211_M_MONITOR:
        !           561:                imr->ifm_active |= IFM_IEEE80211_MONITOR;
        !           562:                break;
        !           563:        }
        !           564:        switch (ic->ic_curmode) {
        !           565:        case IEEE80211_MODE_11A:
        !           566:                imr->ifm_active |= IFM_IEEE80211_11A;
        !           567:                break;
        !           568:        case IEEE80211_MODE_11B:
        !           569:                imr->ifm_active |= IFM_IEEE80211_11B;
        !           570:                break;
        !           571:        case IEEE80211_MODE_11G:
        !           572:                imr->ifm_active |= IFM_IEEE80211_11G;
        !           573:                break;
        !           574:        case IEEE80211_MODE_FH:
        !           575:                imr->ifm_active |= IFM_IEEE80211_FH;
        !           576:                break;
        !           577:        case IEEE80211_MODE_TURBO:
        !           578:                imr->ifm_active |= IFM_IEEE80211_11A
        !           579:                                |  IFM_IEEE80211_TURBO;
        !           580:                break;
        !           581:        }
        !           582: }
        !           583:
        !           584: void
        !           585: ieee80211_watchdog(struct ifnet *ifp)
        !           586: {
        !           587:        struct ieee80211com *ic = (void *)ifp;
        !           588:
        !           589:        if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
        !           590:                ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
        !           591:
        !           592:        if (ic->ic_mgt_timer != 0)
        !           593:                ifp->if_timer = 1;
        !           594: }
        !           595:
        !           596: const struct ieee80211_rateset ieee80211_std_rateset_11a =
        !           597:        { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
        !           598:
        !           599: const struct ieee80211_rateset ieee80211_std_rateset_11b =
        !           600:        { 4, { 2, 4, 11, 22 } };
        !           601:
        !           602: const struct ieee80211_rateset ieee80211_std_rateset_11g =
        !           603:        { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
        !           604:
        !           605: /*
        !           606:  * Mark the basic rates for the 11g rate table based on the
        !           607:  * operating mode.  For real 11g we mark all the 11b rates
        !           608:  * and 6, 12, and 24 OFDM.  For 11b compatibility we mark only
        !           609:  * 11b rates.  There's also a pseudo 11a-mode used to mark only
        !           610:  * the basic OFDM rates.
        !           611:  */
        !           612: void
        !           613: ieee80211_setbasicrates(struct ieee80211com *ic)
        !           614: {
        !           615:        static const struct ieee80211_rateset basic[] = {
        !           616:            { 0 },                              /* IEEE80211_MODE_AUTO */
        !           617:            { 3, { 12, 24, 48 } },              /* IEEE80211_MODE_11A */
        !           618:            { 2, { 2, 4 } },                    /* IEEE80211_MODE_11B */
        !           619:            { 4, { 2, 4, 11, 22 } },            /* IEEE80211_MODE_11G */
        !           620:            { 2, { 2, 4 } },                    /* IEEE80211_MODE_FH */
        !           621:            { 0 },                              /* IEEE80211_MODE_TURBO */
        !           622:        };
        !           623:        enum ieee80211_phymode mode;
        !           624:        struct ieee80211_rateset *rs;
        !           625:        int i, j;
        !           626:
        !           627:        for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) {
        !           628:                rs = &ic->ic_sup_rates[mode];
        !           629:                for (i = 0; i < rs->rs_nrates; i++) {
        !           630:                        rs->rs_rates[i] &= IEEE80211_RATE_VAL;
        !           631:                        for (j = 0; j < basic[mode].rs_nrates; j++) {
        !           632:                                if (basic[mode].rs_rates[j] ==
        !           633:                                    rs->rs_rates[i]) {
        !           634:                                        rs->rs_rates[i] |=
        !           635:                                            IEEE80211_RATE_BASIC;
        !           636:                                        break;
        !           637:                                }
        !           638:                        }
        !           639:                }
        !           640:        }
        !           641: }
        !           642:
        !           643: /*
        !           644:  * Set the current phy mode and recalculate the active channel
        !           645:  * set based on the available channels for this mode.  Also
        !           646:  * select a new default/current channel if the current one is
        !           647:  * inappropriate for this mode.
        !           648:  */
        !           649: int
        !           650: ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
        !           651: {
        !           652: #define        N(a)    (sizeof(a) / sizeof(a[0]))
        !           653:        struct ifnet *ifp = &ic->ic_if;
        !           654:        static const u_int chanflags[] = {
        !           655:                0,                      /* IEEE80211_MODE_AUTO */
        !           656:                IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
        !           657:                IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
        !           658:                IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
        !           659:                IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
        !           660:                IEEE80211_CHAN_T,       /* IEEE80211_MODE_TURBO */
        !           661:        };
        !           662:        const struct ieee80211_channel *c;
        !           663:        u_int modeflags;
        !           664:        int i;
        !           665:
        !           666:        /* validate new mode */
        !           667:        if ((ic->ic_modecaps & (1<<mode)) == 0) {
        !           668:                IEEE80211_DPRINTF(("%s: mode %u not supported (caps 0x%x)\n",
        !           669:                        __func__, mode, ic->ic_modecaps));
        !           670:                return EINVAL;
        !           671:        }
        !           672:
        !           673:        /*
        !           674:         * Verify at least one channel is present in the available
        !           675:         * channel list before committing to the new mode.
        !           676:         */
        !           677:        if (mode >= N(chanflags))
        !           678:                panic("Unexpected mode %u", mode);
        !           679:        modeflags = chanflags[mode];
        !           680:        for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
        !           681:                c = &ic->ic_channels[i];
        !           682:                if (mode == IEEE80211_MODE_AUTO) {
        !           683:                        /* ignore turbo channels for autoselect */
        !           684:                        if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
        !           685:                                break;
        !           686:                } else {
        !           687:                        if ((c->ic_flags & modeflags) == modeflags)
        !           688:                                break;
        !           689:                }
        !           690:        }
        !           691:        if (i > IEEE80211_CHAN_MAX) {
        !           692:                IEEE80211_DPRINTF(("%s: no channels found for mode %u\n",
        !           693:                        __func__, mode));
        !           694:                return EINVAL;
        !           695:        }
        !           696:
        !           697:        /*
        !           698:         * Calculate the active channel set.
        !           699:         */
        !           700:        memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active));
        !           701:        for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
        !           702:                c = &ic->ic_channels[i];
        !           703:                if (mode == IEEE80211_MODE_AUTO) {
        !           704:                        /* take anything but pure turbo channels */
        !           705:                        if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
        !           706:                                setbit(ic->ic_chan_active, i);
        !           707:                } else {
        !           708:                        if ((c->ic_flags & modeflags) == modeflags)
        !           709:                                setbit(ic->ic_chan_active, i);
        !           710:                }
        !           711:        }
        !           712:        /*
        !           713:         * If no current/default channel is setup or the current
        !           714:         * channel is wrong for the mode then pick the first
        !           715:         * available channel from the active list.  This is likely
        !           716:         * not the right one.
        !           717:         */
        !           718:        if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active,
        !           719:            ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
        !           720:                for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
        !           721:                        if (isset(ic->ic_chan_active, i)) {
        !           722:                                ic->ic_ibss_chan = &ic->ic_channels[i];
        !           723:                                break;
        !           724:                        }
        !           725:                if ((ic->ic_ibss_chan == NULL) || isclr(ic->ic_chan_active,
        !           726:                    ieee80211_chan2ieee(ic, ic->ic_ibss_chan)))
        !           727:                        panic("Bad IBSS channel %u\n",
        !           728:                            ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
        !           729:        }
        !           730:
        !           731:        /*
        !           732:         * Reset the scan state for the new mode. This avoids scanning
        !           733:         * of invalid channels, ie. 5GHz channels in 11b mode.
        !           734:         */
        !           735:        ieee80211_reset_scan(ifp);
        !           736:
        !           737:        ic->ic_curmode = mode;
        !           738:        ieee80211_reset_erp(ic);        /* reset ERP state */
        !           739:
        !           740:        return 0;
        !           741: #undef N
        !           742: }
        !           743:
        !           744: enum ieee80211_phymode
        !           745: ieee80211_next_mode(struct ifnet *ifp)
        !           746: {
        !           747:        struct ieee80211com *ic = (void *)ifp;
        !           748:
        !           749:        if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) {
        !           750:                /*
        !           751:                 * Reset the scan state and indicate a wrap around
        !           752:                 * if we're running in a fixed, user-specified phy mode.
        !           753:                 */
        !           754:                ieee80211_reset_scan(ifp);
        !           755:                return (IEEE80211_MODE_AUTO);
        !           756:        }
        !           757:
        !           758:        /*
        !           759:         * Get the next supported mode
        !           760:         */
        !           761:        for (++ic->ic_curmode;
        !           762:            ic->ic_curmode <= IEEE80211_MODE_TURBO;
        !           763:            ic->ic_curmode++) {
        !           764:                /* Wrap around and ignore turbo mode */
        !           765:                if (ic->ic_curmode >= IEEE80211_MODE_TURBO) {
        !           766:                        ic->ic_curmode = IEEE80211_MODE_AUTO;
        !           767:                        break;
        !           768:                }
        !           769:
        !           770:                if (ic->ic_modecaps & (1 << ic->ic_curmode))
        !           771:                        break;
        !           772:        }
        !           773:
        !           774:        ieee80211_setmode(ic, ic->ic_curmode);
        !           775:
        !           776:        return (ic->ic_curmode);
        !           777: }
        !           778:
        !           779: /*
        !           780:  * Return the phy mode for with the specified channel so the
        !           781:  * caller can select a rate set.  This is problematic and the
        !           782:  * work here assumes how things work elsewhere in this code.
        !           783:  *
        !           784:  * XXX never returns turbo modes -dcy
        !           785:  */
        !           786: enum ieee80211_phymode
        !           787: ieee80211_chan2mode(struct ieee80211com *ic,
        !           788:     const struct ieee80211_channel *chan)
        !           789: {
        !           790:        /*
        !           791:         * NB: this assumes the channel would not be supplied to us
        !           792:         *     unless it was already compatible with the current mode.
        !           793:         */
        !           794:        if (ic->ic_curmode != IEEE80211_MODE_AUTO ||
        !           795:            chan == IEEE80211_CHAN_ANYC)
        !           796:                return ic->ic_curmode;
        !           797:        /*
        !           798:         * In autoselect mode; deduce a mode based on the channel
        !           799:         * characteristics.  We assume that turbo-only channels
        !           800:         * are not considered when the channel set is constructed.
        !           801:         */
        !           802:        if (IEEE80211_IS_CHAN_T(chan))
        !           803:                return IEEE80211_MODE_TURBO;
        !           804:        else if (IEEE80211_IS_CHAN_5GHZ(chan))
        !           805:                return IEEE80211_MODE_11A;
        !           806:        else if (IEEE80211_IS_CHAN_FHSS(chan))
        !           807:                return IEEE80211_MODE_FH;
        !           808:        else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN))
        !           809:                return IEEE80211_MODE_11G;
        !           810:        else
        !           811:                return IEEE80211_MODE_11B;
        !           812: }
        !           813:
        !           814: /*
        !           815:  * convert IEEE80211 rate value to ifmedia subtype.
        !           816:  * ieee80211 rate is in unit of 0.5Mbps.
        !           817:  */
        !           818: int
        !           819: ieee80211_rate2media(struct ieee80211com *ic, int rate,
        !           820:     enum ieee80211_phymode mode)
        !           821: {
        !           822: #define        N(a)    (sizeof(a) / sizeof(a[0]))
        !           823:        static const struct {
        !           824:                u_int   m;      /* rate + mode */
        !           825:                u_int   r;      /* if_media rate */
        !           826:        } rates[] = {
        !           827:                {   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
        !           828:                {   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
        !           829:                {   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
        !           830:                {   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
        !           831:                {  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
        !           832:                {  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
        !           833:                {  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
        !           834:                {  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
        !           835:                {  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
        !           836:                {  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
        !           837:                {  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
        !           838:                {  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
        !           839:                {  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
        !           840:                {  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
        !           841:                { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
        !           842:                {   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
        !           843:                {   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
        !           844:                {  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
        !           845:                {  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
        !           846:                {  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
        !           847:                {  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
        !           848:                {  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
        !           849:                {  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
        !           850:                {  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
        !           851:                {  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
        !           852:                {  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
        !           853:                { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
        !           854:                /* NB: OFDM72 doesn't realy exist so we don't handle it */
        !           855:        };
        !           856:        u_int mask, i;
        !           857:
        !           858:        mask = rate & IEEE80211_RATE_VAL;
        !           859:        switch (mode) {
        !           860:        case IEEE80211_MODE_11A:
        !           861:        case IEEE80211_MODE_TURBO:
        !           862:                mask |= IFM_IEEE80211_11A;
        !           863:                break;
        !           864:        case IEEE80211_MODE_11B:
        !           865:                mask |= IFM_IEEE80211_11B;
        !           866:                break;
        !           867:        case IEEE80211_MODE_FH:
        !           868:                mask |= IFM_IEEE80211_FH;
        !           869:                break;
        !           870:        case IEEE80211_MODE_AUTO:
        !           871:                /* NB: ic may be NULL for some drivers */
        !           872:                if (ic && ic->ic_phytype == IEEE80211_T_FH) {
        !           873:                        mask |= IFM_IEEE80211_FH;
        !           874:                        break;
        !           875:                }
        !           876:                /* NB: hack, 11g matches both 11b+11a rates */
        !           877:                /* FALLTHROUGH */
        !           878:        case IEEE80211_MODE_11G:
        !           879:                mask |= IFM_IEEE80211_11G;
        !           880:                break;
        !           881:        }
        !           882:        for (i = 0; i < N(rates); i++)
        !           883:                if (rates[i].m == mask)
        !           884:                        return rates[i].r;
        !           885:        return IFM_AUTO;
        !           886: #undef N
        !           887: }
        !           888:
        !           889: int
        !           890: ieee80211_media2rate(int mword)
        !           891: {
        !           892: #define        N(a)    (sizeof(a) / sizeof(a[0]))
        !           893:        int i;
        !           894:        static const struct {
        !           895:                int subtype;
        !           896:                int rate;
        !           897:        } ieeerates[] = {
        !           898:                { IFM_AUTO,             -1      },
        !           899:                { IFM_MANUAL,           0       },
        !           900:                { IFM_NONE,             0       },
        !           901:                { IFM_IEEE80211_FH1,    2       },
        !           902:                { IFM_IEEE80211_FH2,    4       },
        !           903:                { IFM_IEEE80211_DS1,    2       },
        !           904:                { IFM_IEEE80211_DS2,    4       },
        !           905:                { IFM_IEEE80211_DS5,    11      },
        !           906:                { IFM_IEEE80211_DS11,   22      },
        !           907:                { IFM_IEEE80211_DS22,   44      },
        !           908:                { IFM_IEEE80211_OFDM6,  12      },
        !           909:                { IFM_IEEE80211_OFDM9,  18      },
        !           910:                { IFM_IEEE80211_OFDM12, 24      },
        !           911:                { IFM_IEEE80211_OFDM18, 36      },
        !           912:                { IFM_IEEE80211_OFDM24, 48      },
        !           913:                { IFM_IEEE80211_OFDM36, 72      },
        !           914:                { IFM_IEEE80211_OFDM48, 96      },
        !           915:                { IFM_IEEE80211_OFDM54, 108     },
        !           916:                { IFM_IEEE80211_OFDM72, 144     },
        !           917:        };
        !           918:        for (i = 0; i < N(ieeerates); i++) {
        !           919:                if (ieeerates[i].subtype == IFM_SUBTYPE(mword))
        !           920:                        return ieeerates[i].rate;
        !           921:        }
        !           922:        return 0;
        !           923: #undef N
        !           924: }

CVSweb