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

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

1.1     ! nbrk        1: /*     $OpenBSD: ieee80211_node.c,v 1.28 2007/07/06 18:18:43 damien Exp $      */
        !             2: /*     $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 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: #include "bpfilter.h"
        !            33: #include "bridge.h"
        !            34:
        !            35: #include <sys/param.h>
        !            36: #include <sys/systm.h>
        !            37: #include <sys/mbuf.h>
        !            38: #include <sys/malloc.h>
        !            39: #include <sys/kernel.h>
        !            40: #include <sys/socket.h>
        !            41: #include <sys/sockio.h>
        !            42: #include <sys/endian.h>
        !            43: #include <sys/errno.h>
        !            44: #include <sys/proc.h>
        !            45: #include <sys/sysctl.h>
        !            46: #include <sys/tree.h>
        !            47:
        !            48: #include <net/if.h>
        !            49: #include <net/if_dl.h>
        !            50: #include <net/if_media.h>
        !            51: #include <net/if_arp.h>
        !            52: #include <net/if_llc.h>
        !            53:
        !            54: #if NBPFILTER > 0
        !            55: #include <net/bpf.h>
        !            56: #endif
        !            57:
        !            58: #ifdef INET
        !            59: #include <netinet/in.h>
        !            60: #include <netinet/if_ether.h>
        !            61: #endif
        !            62:
        !            63: #if NBRIDGE > 0
        !            64: #include <net/if_bridge.h>
        !            65: #endif
        !            66:
        !            67: #include <net80211/ieee80211_var.h>
        !            68:
        !            69: #include <dev/rndvar.h>
        !            70:
        !            71: struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *);
        !            72: void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *);
        !            73: void ieee80211_node_copy(struct ieee80211com *, struct ieee80211_node *,
        !            74:     const struct ieee80211_node *);
        !            75: u_int8_t ieee80211_node_getrssi(struct ieee80211com *,
        !            76:     const struct ieee80211_node *);
        !            77: void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *,
        !            78:     const u_int8_t *);
        !            79: void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *);
        !            80: struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
        !            81: void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *);
        !            82: void ieee80211_node_join_11g(struct ieee80211com *, struct ieee80211_node *);
        !            83: void ieee80211_node_leave_11g(struct ieee80211com *, struct ieee80211_node *);
        !            84: void ieee80211_set_tim(struct ieee80211com *, int, int);
        !            85:
        !            86: #define M_80211_NODE   M_DEVBUF
        !            87:
        !            88: void
        !            89: ieee80211_node_attach(struct ifnet *ifp)
        !            90: {
        !            91:        struct ieee80211com *ic = (void *)ifp;
        !            92:        int size;
        !            93:
        !            94:        RB_INIT(&ic->ic_tree);
        !            95:        ic->ic_node_alloc = ieee80211_node_alloc;
        !            96:        ic->ic_node_free = ieee80211_node_free;
        !            97:        ic->ic_node_copy = ieee80211_node_copy;
        !            98:        ic->ic_node_getrssi = ieee80211_node_getrssi;
        !            99:        ic->ic_scangen = 1;
        !           100:        ic->ic_max_nnodes = ieee80211_cache_size;
        !           101:
        !           102:        if (ic->ic_max_aid == 0)
        !           103:                ic->ic_max_aid = IEEE80211_AID_DEF;
        !           104:        else if (ic->ic_max_aid > IEEE80211_AID_MAX)
        !           105:                ic->ic_max_aid = IEEE80211_AID_MAX;
        !           106:        size = howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t);
        !           107:        MALLOC(ic->ic_aid_bitmap, u_int32_t *, size, M_DEVBUF, M_NOWAIT);
        !           108:        if (ic->ic_aid_bitmap == NULL) {
        !           109:                /* XXX no way to recover */
        !           110:                printf("%s: no memory for AID bitmap!\n", __func__);
        !           111:                ic->ic_max_aid = 0;
        !           112:        } else
        !           113:                memset(ic->ic_aid_bitmap, 0, size);
        !           114:
        !           115:        if (ic->ic_caps & (IEEE80211_C_HOSTAP | IEEE80211_C_IBSS)) {
        !           116:                ic->ic_tim_len = howmany(ic->ic_max_aid, 8);
        !           117:                MALLOC(ic->ic_tim_bitmap, u_int8_t *, ic->ic_tim_len, M_DEVBUF,
        !           118:                    M_NOWAIT);
        !           119:                if (ic->ic_tim_bitmap == NULL) {
        !           120:                        printf("%s: no memory for TIM bitmap!\n", __func__);
        !           121:                        ic->ic_tim_len = 0;
        !           122:                } else {
        !           123:                        memset(ic->ic_tim_bitmap, 0, ic->ic_tim_len);
        !           124:                        ic->ic_set_tim = ieee80211_set_tim;
        !           125:                }
        !           126:        }
        !           127: }
        !           128:
        !           129: struct ieee80211_node *
        !           130: ieee80211_alloc_node_helper(struct ieee80211com *ic)
        !           131: {
        !           132:        struct ieee80211_node *ni;
        !           133:        if (ic->ic_nnodes >= ic->ic_max_nnodes)
        !           134:                ieee80211_clean_nodes(ic);
        !           135:        if (ic->ic_nnodes >= ic->ic_max_nnodes)
        !           136:                return NULL;
        !           137:        ni = (*ic->ic_node_alloc)(ic);
        !           138:        if (ni != NULL)
        !           139:                ic->ic_nnodes++;
        !           140:        return ni;
        !           141: }
        !           142:
        !           143: void
        !           144: ieee80211_node_lateattach(struct ifnet *ifp)
        !           145: {
        !           146:        struct ieee80211com *ic = (void *)ifp;
        !           147:        struct ieee80211_node *ni;
        !           148:
        !           149:        ni = ieee80211_alloc_node_helper(ic);
        !           150:        if (ni == NULL)
        !           151:                panic("unable to setup inital BSS node");
        !           152:        ni->ni_chan = IEEE80211_CHAN_ANYC;
        !           153:        ic->ic_bss = ieee80211_ref_node(ni);
        !           154:        ic->ic_txpower = IEEE80211_TXPOWER_MAX;
        !           155: }
        !           156:
        !           157: void
        !           158: ieee80211_node_detach(struct ifnet *ifp)
        !           159: {
        !           160:        struct ieee80211com *ic = (void *)ifp;
        !           161:
        !           162:        if (ic->ic_bss != NULL) {
        !           163:                (*ic->ic_node_free)(ic, ic->ic_bss);
        !           164:                ic->ic_bss = NULL;
        !           165:        }
        !           166:        ieee80211_free_allnodes(ic);
        !           167:        if (ic->ic_aid_bitmap != NULL)
        !           168:                FREE(ic->ic_aid_bitmap, M_DEVBUF);
        !           169:        if (ic->ic_tim_bitmap != NULL)
        !           170:                FREE(ic->ic_tim_bitmap, M_DEVBUF);
        !           171: }
        !           172:
        !           173: /*
        !           174:  * AP scanning support.
        !           175:  */
        !           176:
        !           177: /*
        !           178:  * Initialize the active channel set based on the set
        !           179:  * of available channels and the current PHY mode.
        !           180:  */
        !           181: void
        !           182: ieee80211_reset_scan(struct ifnet *ifp)
        !           183: {
        !           184:        struct ieee80211com *ic = (void *)ifp;
        !           185:
        !           186:        memcpy(ic->ic_chan_scan, ic->ic_chan_active,
        !           187:                sizeof(ic->ic_chan_active));
        !           188:        /* NB: hack, setup so next_scan starts with the first channel */
        !           189:        if (ic->ic_bss != NULL && ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC)
        !           190:                ic->ic_bss->ni_chan = &ic->ic_channels[IEEE80211_CHAN_MAX];
        !           191: }
        !           192:
        !           193: /*
        !           194:  * Begin an active scan.
        !           195:  */
        !           196: void
        !           197: ieee80211_begin_scan(struct ifnet *ifp)
        !           198: {
        !           199:        struct ieee80211com *ic = (void *)ifp;
        !           200:
        !           201:        if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED)
        !           202:                return;
        !           203:        ic->ic_scan_lock |= IEEE80211_SCAN_LOCKED;
        !           204:
        !           205:        /*
        !           206:         * In all but hostap mode scanning starts off in
        !           207:         * an active mode before switching to passive.
        !           208:         */
        !           209:        if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
        !           210:                ic->ic_flags |= IEEE80211_F_ASCAN;
        !           211:                ic->ic_stats.is_scan_active++;
        !           212:        } else
        !           213:                ic->ic_stats.is_scan_passive++;
        !           214:        if (ifp->if_flags & IFF_DEBUG)
        !           215:                printf("%s: begin %s scan\n", ifp->if_xname,
        !           216:                        (ic->ic_flags & IEEE80211_F_ASCAN) ?
        !           217:                                "active" : "passive");
        !           218:
        !           219:        /*
        !           220:         * Flush any previously seen AP's. Note that the latter
        !           221:         * assumes we don't act as both an AP and a station,
        !           222:         * otherwise we'll potentially flush state of stations
        !           223:         * associated with us.
        !           224:         */
        !           225:        ieee80211_free_allnodes(ic);
        !           226:
        !           227:        /*
        !           228:         * Reset the current mode. Setting the current mode will also
        !           229:         * reset scan state.
        !           230:         */
        !           231:        if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO)
        !           232:                ic->ic_curmode = IEEE80211_MODE_AUTO;
        !           233:        ieee80211_setmode(ic, ic->ic_curmode);
        !           234:
        !           235:        ic->ic_scan_count = 0;
        !           236:
        !           237:        /* Scan the next channel. */
        !           238:        ieee80211_next_scan(ifp);
        !           239: }
        !           240:
        !           241: /*
        !           242:  * Switch to the next channel marked for scanning.
        !           243:  */
        !           244: void
        !           245: ieee80211_next_scan(struct ifnet *ifp)
        !           246: {
        !           247:        struct ieee80211com *ic = (void *)ifp;
        !           248:        struct ieee80211_channel *chan;
        !           249:
        !           250:        chan = ic->ic_bss->ni_chan;
        !           251:        for (;;) {
        !           252:                if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX])
        !           253:                        chan = &ic->ic_channels[0];
        !           254:                if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) {
        !           255:                        /*
        !           256:                         * Ignore channels marked passive-only
        !           257:                         * during an active scan.
        !           258:                         */
        !           259:                        if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 ||
        !           260:                            (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
        !           261:                                break;
        !           262:                }
        !           263:                if (chan == ic->ic_bss->ni_chan) {
        !           264:                        ieee80211_end_scan(ifp);
        !           265:                        return;
        !           266:                }
        !           267:        }
        !           268:        clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
        !           269:        IEEE80211_DPRINTF(("%s: chan %d->%d\n", __func__,
        !           270:            ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
        !           271:            ieee80211_chan2ieee(ic, chan)));
        !           272:        ic->ic_bss->ni_chan = chan;
        !           273:        ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
        !           274: }
        !           275:
        !           276: void
        !           277: ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
        !           278: {
        !           279:        struct ieee80211_node *ni;
        !           280:        struct ifnet *ifp = &ic->ic_if;
        !           281:
        !           282:        ni = ic->ic_bss;
        !           283:        if (ifp->if_flags & IFF_DEBUG)
        !           284:                printf("%s: creating ibss\n", ifp->if_xname);
        !           285:        ic->ic_flags |= IEEE80211_F_SIBSS;
        !           286:        ni->ni_chan = chan;
        !           287:        ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
        !           288:        IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
        !           289:        IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
        !           290:        if (ic->ic_opmode == IEEE80211_M_IBSS) {
        !           291:                if ((ic->ic_flags & IEEE80211_F_DESBSSID) != 0)
        !           292:                        IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
        !           293:                else
        !           294:                        ni->ni_bssid[0] |= 0x02;        /* local bit for IBSS */
        !           295:        }
        !           296:        ni->ni_esslen = ic->ic_des_esslen;
        !           297:        memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
        !           298:        ni->ni_rssi = 0;
        !           299:        ni->ni_rstamp = 0;
        !           300:        memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
        !           301:        ni->ni_intval = ic->ic_lintval;
        !           302:        ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
        !           303:        if (ic->ic_flags & IEEE80211_F_WEPON)
        !           304:                ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
        !           305:        if (ic->ic_phytype == IEEE80211_T_FH) {
        !           306:                ni->ni_fhdwell = 200;   /* XXX */
        !           307:                ni->ni_fhindex = 1;
        !           308:        }
        !           309:        ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
        !           310: }
        !           311:
        !           312: int
        !           313: ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
        !           314: {
        !           315:        u_int8_t rate;
        !           316:        int fail;
        !           317:
        !           318:        fail = 0;
        !           319:        if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
        !           320:                fail |= 0x01;
        !           321:        if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
        !           322:            ni->ni_chan != ic->ic_des_chan)
        !           323:                fail |= 0x01;
        !           324:        if (ic->ic_opmode == IEEE80211_M_IBSS) {
        !           325:                if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
        !           326:                        fail |= 0x02;
        !           327:        } else {
        !           328:                if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
        !           329:                        fail |= 0x02;
        !           330:        }
        !           331:        if (ic->ic_flags & IEEE80211_F_WEPON) {
        !           332:                if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
        !           333:                        fail |= 0x04;
        !           334:        } else {
        !           335:                /* XXX does this mean privacy is supported or required? */
        !           336:                if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
        !           337:                        fail |= 0x04;
        !           338:        }
        !           339:        rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
        !           340:        if (rate & IEEE80211_RATE_BASIC)
        !           341:                fail |= 0x08;
        !           342:        if (ic->ic_des_esslen != 0 &&
        !           343:            (ni->ni_esslen != ic->ic_des_esslen ||
        !           344:             memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0))
        !           345:                fail |= 0x10;
        !           346:        if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
        !           347:            !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
        !           348:                fail |= 0x20;
        !           349: #ifdef IEEE80211_DEBUG
        !           350:        if (ic->ic_if.if_flags & IFF_DEBUG) {
        !           351:                printf(" %c %s", fail ? '-' : '+',
        !           352:                    ether_sprintf(ni->ni_macaddr));
        !           353:                printf(" %s%c", ether_sprintf(ni->ni_bssid),
        !           354:                    fail & 0x20 ? '!' : ' ');
        !           355:                printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
        !           356:                        fail & 0x01 ? '!' : ' ');
        !           357:                printf(" %+4d", ni->ni_rssi);
        !           358:                printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
        !           359:                    fail & 0x08 ? '!' : ' ');
        !           360:                printf(" %4s%c",
        !           361:                    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
        !           362:                    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
        !           363:                    "????",
        !           364:                    fail & 0x02 ? '!' : ' ');
        !           365:                printf(" %3s%c ",
        !           366:                    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
        !           367:                    "wep" : "no",
        !           368:                    fail & 0x04 ? '!' : ' ');
        !           369:                ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
        !           370:                printf("%s\n", fail & 0x10 ? "!" : "");
        !           371:        }
        !           372: #endif
        !           373:        return fail;
        !           374: }
        !           375:
        !           376: /*
        !           377:  * Complete a scan of potential channels.
        !           378:  */
        !           379: void
        !           380: ieee80211_end_scan(struct ifnet *ifp)
        !           381: {
        !           382:        struct ieee80211com *ic = (void *)ifp;
        !           383:        struct ieee80211_node *ni, *nextbs, *selbs;
        !           384:        int i, fail;
        !           385:
        !           386:        if (ifp->if_flags & IFF_DEBUG)
        !           387:                printf("%s: end %s scan\n", ifp->if_xname,
        !           388:                        (ic->ic_flags & IEEE80211_F_ASCAN) ?
        !           389:                                "active" : "passive");
        !           390:
        !           391:        if (ic->ic_scan_count)
        !           392:                ic->ic_flags &= ~IEEE80211_F_ASCAN;
        !           393:
        !           394:        ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
        !           395:
        !           396:        if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
        !           397:                /* XXX off stack? */
        !           398:                u_char occupied[howmany(IEEE80211_CHAN_MAX, NBBY)];
        !           399:                /*
        !           400:                 * The passive scan to look for existing AP's completed,
        !           401:                 * select a channel to camp on.  Identify the channels
        !           402:                 * that already have one or more AP's and try to locate
        !           403:                 * an unnoccupied one.  If that fails, pick a random
        !           404:                 * channel from the active set.
        !           405:                 */
        !           406:                RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree)
        !           407:                        setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan));
        !           408:                for (i = 0; i < IEEE80211_CHAN_MAX; i++)
        !           409:                        if (isset(ic->ic_chan_active, i) && isclr(occupied, i))
        !           410:                                break;
        !           411:                if (i == IEEE80211_CHAN_MAX) {
        !           412:                        fail = arc4random() & 3;        /* random 0-3 */
        !           413:                        for (i = 0; i < IEEE80211_CHAN_MAX; i++)
        !           414:                                if (isset(ic->ic_chan_active, i) && fail-- == 0)
        !           415:                                        break;
        !           416:                }
        !           417:                ieee80211_create_ibss(ic, &ic->ic_channels[i]);
        !           418:                goto wakeup;
        !           419:        }
        !           420:        if (ni == NULL) {
        !           421:                IEEE80211_DPRINTF(("%s: no scan candidate\n", __func__));
        !           422:  notfound:
        !           423:                if (ic->ic_opmode == IEEE80211_M_IBSS &&
        !           424:                    (ic->ic_flags & IEEE80211_F_IBSSON) &&
        !           425:                    ic->ic_des_esslen != 0) {
        !           426:                        ieee80211_create_ibss(ic, ic->ic_ibss_chan);
        !           427:                        goto wakeup;
        !           428:                }
        !           429:
        !           430:                /*
        !           431:                 * Scan the next mode if nothing has been found. This
        !           432:                 * is necessary if the device supports different
        !           433:                 * incompatible modes in the same channel range, like
        !           434:                 * like 11b and "pure" 11G mode. This will loop
        !           435:                 * forever except for user-initiated scans.
        !           436:                 */
        !           437:                if (ieee80211_next_mode(ifp) == IEEE80211_MODE_AUTO) {
        !           438:                        if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST &&
        !           439:                            ic->ic_scan_lock & IEEE80211_SCAN_RESUME) {
        !           440:                                ic->ic_scan_lock = IEEE80211_SCAN_LOCKED;
        !           441:                                /* Return from an user-initiated scan */
        !           442:                                wakeup(&ic->ic_scan_lock);
        !           443:                        } else if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST)
        !           444:                                goto wakeup;
        !           445:                        ic->ic_scan_count++;
        !           446:                }
        !           447:
        !           448:                /*
        !           449:                 * Reset the list of channels to scan and start again.
        !           450:                 */
        !           451:                ieee80211_next_scan(ifp);
        !           452:                return;
        !           453:        }
        !           454:        selbs = NULL;
        !           455:
        !           456:        for (; ni != NULL; ni = nextbs) {
        !           457:                nextbs = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
        !           458:                if (ni->ni_fails) {
        !           459:                        /*
        !           460:                         * The configuration of the access points may change
        !           461:                         * during my scan.  So delete the entry for the AP
        !           462:                         * and retry to associate if there is another beacon.
        !           463:                         */
        !           464:                        if (ni->ni_fails++ > 2)
        !           465:                                ieee80211_free_node(ic, ni);
        !           466:                        continue;
        !           467:                }
        !           468:                if (ieee80211_match_bss(ic, ni) == 0) {
        !           469:                        if (selbs == NULL)
        !           470:                                selbs = ni;
        !           471:                        else if (ni->ni_rssi > selbs->ni_rssi)
        !           472:                                selbs = ni;
        !           473:                }
        !           474:        }
        !           475:        if (selbs == NULL)
        !           476:                goto notfound;
        !           477:        (*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
        !           478:
        !           479:        /*
        !           480:         * Set the erp state (mostly the slot time) to deal with
        !           481:         * the auto-select case; this should be redundant if the
        !           482:         * mode is locked.
        !           483:         */
        !           484:        ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan);
        !           485:        ieee80211_reset_erp(ic);
        !           486:
        !           487:        ieee80211_node_newstate(selbs, IEEE80211_STA_BSS);
        !           488:        if (ic->ic_opmode == IEEE80211_M_IBSS) {
        !           489:                ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE |
        !           490:                    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
        !           491:                if (ic->ic_bss->ni_rates.rs_nrates == 0)
        !           492:                        goto notfound;
        !           493:                ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
        !           494:        } else {
        !           495:                ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
        !           496:        }
        !           497:
        !           498:  wakeup:
        !           499:        if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) {
        !           500:                /* Return from an user-initiated scan */
        !           501:                wakeup(&ic->ic_scan_lock);
        !           502:        }
        !           503:
        !           504:        ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED;
        !           505: }
        !           506:
        !           507: int
        !           508: ieee80211_get_rate(struct ieee80211com *ic)
        !           509: {
        !           510:        u_int8_t (*rates)[IEEE80211_RATE_MAXSIZE];
        !           511:        int rate;
        !           512:
        !           513:        rates = &ic->ic_bss->ni_rates.rs_rates;
        !           514:
        !           515:        if (ic->ic_fixed_rate != -1)
        !           516:                rate = (*rates)[ic->ic_fixed_rate];
        !           517:        else if (ic->ic_state == IEEE80211_S_RUN)
        !           518:                rate = (*rates)[ic->ic_bss->ni_txrate];
        !           519:        else
        !           520:                rate = 0;
        !           521:
        !           522:        return rate & IEEE80211_RATE_VAL;
        !           523: }
        !           524:
        !           525: struct ieee80211_node *
        !           526: ieee80211_node_alloc(struct ieee80211com *ic)
        !           527: {
        !           528:        struct ieee80211_node *ni;
        !           529:        MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node),
        !           530:            M_80211_NODE, M_NOWAIT);
        !           531:        if (ni != NULL)
        !           532:                memset(ni, 0, sizeof(struct ieee80211_node));
        !           533:        return ni;
        !           534: }
        !           535:
        !           536: void
        !           537: ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni)
        !           538: {
        !           539: }
        !           540:
        !           541: void
        !           542: ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
        !           543: {
        !           544:        ieee80211_node_cleanup(ic, ni);
        !           545:        FREE(ni, M_80211_NODE);
        !           546: }
        !           547:
        !           548: void
        !           549: ieee80211_node_copy(struct ieee80211com *ic,
        !           550:        struct ieee80211_node *dst, const struct ieee80211_node *src)
        !           551: {
        !           552:        ieee80211_node_cleanup(ic, dst);
        !           553:        *dst = *src;
        !           554: }
        !           555:
        !           556: u_int8_t
        !           557: ieee80211_node_getrssi(struct ieee80211com *ic,
        !           558:     const struct ieee80211_node *ni)
        !           559: {
        !           560:        return ni->ni_rssi;
        !           561: }
        !           562:
        !           563: void
        !           564: ieee80211_setup_node(struct ieee80211com *ic,
        !           565:        struct ieee80211_node *ni, const u_int8_t *macaddr)
        !           566: {
        !           567:        int s;
        !           568:
        !           569:        IEEE80211_DPRINTF(("%s %s\n", __func__,
        !           570:            ether_sprintf((u_int8_t *)macaddr)));
        !           571:        IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
        !           572:        ieee80211_node_newstate(ni, IEEE80211_STA_CACHE);
        !           573:
        !           574:        /*
        !           575:         * Note we don't enable the inactive timer when acting
        !           576:         * as a station.  Nodes created in this mode represent
        !           577:         * AP's identified while scanning.  If we time them out
        !           578:         * then several things happen: we can't return the data
        !           579:         * to users to show the list of AP's we encountered, and
        !           580:         * more importantly, we'll incorrectly deauthenticate
        !           581:         * ourself because the inactivity timer will kick us off.
        !           582:         */
        !           583:        s = splnet();
        !           584:        if (ic->ic_opmode != IEEE80211_M_STA &&
        !           585:            RB_EMPTY(&ic->ic_tree))
        !           586:                ic->ic_inact_timer = IEEE80211_INACT_WAIT;
        !           587:        RB_INSERT(ieee80211_tree, &ic->ic_tree, ni);
        !           588:        splx(s);
        !           589: }
        !           590:
        !           591: struct ieee80211_node *
        !           592: ieee80211_alloc_node(struct ieee80211com *ic, const u_int8_t *macaddr)
        !           593: {
        !           594:        struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic);
        !           595:        if (ni != NULL)
        !           596:                ieee80211_setup_node(ic, ni, macaddr);
        !           597:        else
        !           598:                ic->ic_stats.is_rx_nodealloc++;
        !           599:        return ni;
        !           600: }
        !           601:
        !           602: struct ieee80211_node *
        !           603: ieee80211_dup_bss(struct ieee80211com *ic, const u_int8_t *macaddr)
        !           604: {
        !           605:        struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic);
        !           606:        if (ni != NULL) {
        !           607:                ieee80211_setup_node(ic, ni, macaddr);
        !           608:                /*
        !           609:                 * Inherit from ic_bss.
        !           610:                 */
        !           611:                IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
        !           612:                ni->ni_chan = ic->ic_bss->ni_chan;
        !           613:        } else
        !           614:                ic->ic_stats.is_rx_nodealloc++;
        !           615:        return ni;
        !           616: }
        !           617:
        !           618: struct ieee80211_node *
        !           619: ieee80211_find_node(struct ieee80211com *ic, const u_int8_t *macaddr)
        !           620: {
        !           621:        struct ieee80211_node ni;
        !           622:
        !           623:        IEEE80211_ADDR_COPY(ni.ni_macaddr, macaddr);
        !           624:        return (RB_FIND(ieee80211_tree, &ic->ic_tree, &ni));
        !           625: }
        !           626:
        !           627: /*
        !           628:  * Return a reference to the appropriate node for sending
        !           629:  * a data frame.  This handles node discovery in adhoc networks.
        !           630:  *
        !           631:  * Drivers will call this, so increase the reference count before
        !           632:  * returning the node.
        !           633:  */
        !           634: struct ieee80211_node *
        !           635: ieee80211_find_txnode(struct ieee80211com *ic, const u_int8_t *macaddr)
        !           636: {
        !           637:        struct ieee80211_node *ni;
        !           638:        int s;
        !           639:
        !           640:        /*
        !           641:         * The destination address should be in the node table
        !           642:         * unless we are operating in station mode or this is a
        !           643:         * multicast/broadcast frame.
        !           644:         */
        !           645:        if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr))
        !           646:                return ieee80211_ref_node(ic->ic_bss);
        !           647:
        !           648:        s = splnet();
        !           649:        ni = ieee80211_find_node(ic, macaddr);
        !           650:        splx(s);
        !           651:        if (ni == NULL) {
        !           652:                if (ic->ic_opmode != IEEE80211_M_IBSS &&
        !           653:                    ic->ic_opmode != IEEE80211_M_AHDEMO)
        !           654:                        return NULL;
        !           655:
        !           656:                /*
        !           657:                 * Fake up a node; this handles node discovery in
        !           658:                 * adhoc mode.  Note that for the driver's benefit
        !           659:                 * we we treat this like an association so the driver
        !           660:                 * has an opportunity to setup its private state.
        !           661:                 *
        !           662:                 * XXX need better way to handle this; issue probe
        !           663:                 *     request so we can deduce rate set, etc.
        !           664:                 */
        !           665:                if ((ni = ieee80211_dup_bss(ic, macaddr)) == NULL)
        !           666:                        return NULL;
        !           667:                /* XXX no rate negotiation; just dup */
        !           668:                ni->ni_rates = ic->ic_bss->ni_rates;
        !           669:                if (ic->ic_newassoc)
        !           670:                        (*ic->ic_newassoc)(ic, ni, 1);
        !           671:        }
        !           672:        return ieee80211_ref_node(ni);
        !           673: }
        !           674:
        !           675: /*
        !           676:  * It is usually desirable to process a Rx packet using its sender's
        !           677:  * node-record instead of the BSS record.
        !           678:  *
        !           679:  * - AP mode: keep a node-record for every authenticated/associated
        !           680:  *   station *in the BSS*. For future use, we also track neighboring
        !           681:  *   APs, since they might belong to the same ESS.  APs in the same
        !           682:  *   ESS may bridge packets to each other, forming a Wireless
        !           683:  *   Distribution System (WDS).
        !           684:  *
        !           685:  * - IBSS mode: keep a node-record for every station *in the BSS*.
        !           686:  *   Also track neighboring stations by their beacons/probe responses.
        !           687:  *
        !           688:  * - monitor mode: keep a node-record for every sender, regardless
        !           689:  *   of BSS.
        !           690:  *
        !           691:  * - STA mode: the only available node-record is the BSS record,
        !           692:  *   ic->ic_bss.
        !           693:  *
        !           694:  * Of all the 802.11 Control packets, only the node-records for
        !           695:  * RTS packets node-record can be looked up.
        !           696:  *
        !           697:  * Return non-zero if the packet's node-record is kept, zero
        !           698:  * otherwise.
        !           699:  */
        !           700: static __inline int
        !           701: ieee80211_needs_rxnode(struct ieee80211com *ic,
        !           702:     const struct ieee80211_frame *wh, const u_int8_t **bssid)
        !           703: {
        !           704:        struct ieee80211_node *bss = ic->ic_bss;
        !           705:        int monitor, rc = 0;
        !           706:
        !           707:        monitor = (ic->ic_opmode == IEEE80211_M_MONITOR);
        !           708:
        !           709:        *bssid = NULL;
        !           710:
        !           711:        switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
        !           712:        case IEEE80211_FC0_TYPE_CTL:
        !           713:                if (!monitor)
        !           714:                        break;
        !           715:                return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
        !           716:                    IEEE80211_FC0_SUBTYPE_RTS;
        !           717:        case IEEE80211_FC0_TYPE_MGT:
        !           718:                *bssid = wh->i_addr3;
        !           719:                switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
        !           720:                case IEEE80211_FC0_SUBTYPE_BEACON:
        !           721:                case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
        !           722:                        rc = 1;
        !           723:                        break;
        !           724:                default:
        !           725:                        if (ic->ic_opmode == IEEE80211_M_STA)
        !           726:                                break;
        !           727:                        rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid) ||
        !           728:                             IEEE80211_ADDR_EQ(*bssid, etherbroadcastaddr);
        !           729:                        break;
        !           730:                }
        !           731:                break;
        !           732:        case IEEE80211_FC0_TYPE_DATA:
        !           733:                switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        !           734:                case IEEE80211_FC1_DIR_NODS:
        !           735:                        *bssid = wh->i_addr3;
        !           736:                        if (ic->ic_opmode == IEEE80211_M_IBSS ||
        !           737:                            ic->ic_opmode == IEEE80211_M_AHDEMO)
        !           738:                                rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
        !           739:                        break;
        !           740:                case IEEE80211_FC1_DIR_TODS:
        !           741:                        *bssid = wh->i_addr1;
        !           742:                        if (ic->ic_opmode == IEEE80211_M_HOSTAP)
        !           743:                                rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
        !           744:                        break;
        !           745:                case IEEE80211_FC1_DIR_FROMDS:
        !           746:                case IEEE80211_FC1_DIR_DSTODS:
        !           747:                        *bssid = wh->i_addr2;
        !           748:                        rc = (ic->ic_opmode == IEEE80211_M_HOSTAP);
        !           749:                        break;
        !           750:                }
        !           751:                break;
        !           752:        }
        !           753:        return monitor || rc;
        !           754: }
        !           755:
        !           756: /*
        !           757:  * Drivers call this, so increase the reference count before returning
        !           758:  * the node.
        !           759:  */
        !           760: struct ieee80211_node *
        !           761: ieee80211_find_rxnode(struct ieee80211com *ic,
        !           762:     const struct ieee80211_frame *wh)
        !           763: {
        !           764:        static const u_int8_t zero[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        !           765:        struct ieee80211_node *ni;
        !           766:        const u_int8_t *bssid;
        !           767:        int s;
        !           768:
        !           769:        if (!ieee80211_needs_rxnode(ic, wh, &bssid))
        !           770:                return ieee80211_ref_node(ic->ic_bss);
        !           771:
        !           772:        s = splnet();
        !           773:        ni = ieee80211_find_node(ic, wh->i_addr2);
        !           774:        splx(s);
        !           775:
        !           776:        if (ni != NULL)
        !           777:                return ieee80211_ref_node(ni);
        !           778:        if (ic->ic_opmode == IEEE80211_M_HOSTAP)
        !           779:                return ieee80211_ref_node(ic->ic_bss);
        !           780:
        !           781:        /* XXX see remarks in ieee80211_find_txnode */
        !           782:        /* XXX no rate negotiation; just dup */
        !           783:        if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) == NULL)
        !           784:                return ieee80211_ref_node(ic->ic_bss);
        !           785:
        !           786:        IEEE80211_ADDR_COPY(ni->ni_bssid, (bssid != NULL) ? bssid : zero);
        !           787:
        !           788:        ni->ni_rates = ic->ic_bss->ni_rates;
        !           789:        if (ic->ic_newassoc)
        !           790:                (*ic->ic_newassoc)(ic, ni, 1);
        !           791:
        !           792:        IEEE80211_DPRINTF(("%s: faked-up node %p for %s\n", __func__, ni,
        !           793:            ether_sprintf((u_int8_t *)wh->i_addr2)));
        !           794:
        !           795:        return ieee80211_ref_node(ni);
        !           796: }
        !           797:
        !           798: struct ieee80211_node *
        !           799: ieee80211_find_node_for_beacon(struct ieee80211com *ic,
        !           800:     const u_int8_t *macaddr, const struct ieee80211_channel *chan,
        !           801:     const char *ssid, u_int8_t rssi)
        !           802: {
        !           803:        struct ieee80211_node *ni, *keep = NULL;
        !           804:        int s, score = 0;
        !           805:
        !           806:        if ((ni = ieee80211_find_node(ic, macaddr)) != NULL) {
        !           807:                s = splnet();
        !           808:
        !           809:                if (ni->ni_chan != chan && ni->ni_rssi >= rssi)
        !           810:                        score++;
        !           811:                if (ssid[1] == 0 && ni->ni_esslen != 0)
        !           812:                        score++;
        !           813:                if (score > 0)
        !           814:                        keep = ni;
        !           815:
        !           816:                splx(s);
        !           817:        }
        !           818:
        !           819:        return (keep);
        !           820: }
        !           821:
        !           822: void
        !           823: ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
        !           824: {
        !           825:        if (ni == ic->ic_bss)
        !           826:                panic("freeing bss node");
        !           827:
        !           828:        IEEE80211_DPRINTF(("%s %s\n", __func__, ether_sprintf(ni->ni_macaddr)));
        !           829:        IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
        !           830:        RB_REMOVE(ieee80211_tree, &ic->ic_tree, ni);
        !           831:        ic->ic_nnodes--;
        !           832:        if (!IF_IS_EMPTY(&ni->ni_savedq)) {
        !           833:                IF_PURGE(&ni->ni_savedq);
        !           834:                if (ic->ic_set_tim != NULL)
        !           835:                        (*ic->ic_set_tim)(ic, ni->ni_associd, 0);
        !           836:        }
        !           837:        if (RB_EMPTY(&ic->ic_tree))
        !           838:                ic->ic_inact_timer = 0;
        !           839:        (*ic->ic_node_free)(ic, ni);
        !           840:        /* TBD indicate to drivers that a new node can be allocated */
        !           841: }
        !           842:
        !           843: void
        !           844: ieee80211_release_node(struct ieee80211com *ic, struct ieee80211_node *ni)
        !           845: {
        !           846:        int s;
        !           847:
        !           848:        IEEE80211_DPRINTF(("%s %s refcnt %d\n", __func__,
        !           849:            ether_sprintf(ni->ni_macaddr), ni->ni_refcnt));
        !           850:        if (ieee80211_node_decref(ni) == 0 &&
        !           851:            ni->ni_state == IEEE80211_STA_COLLECT) {
        !           852:                s = splnet();
        !           853:                ieee80211_free_node(ic, ni);
        !           854:                splx(s);
        !           855:        }
        !           856: }
        !           857:
        !           858: void
        !           859: ieee80211_free_allnodes(struct ieee80211com *ic)
        !           860: {
        !           861:        struct ieee80211_node *ni;
        !           862:        int s;
        !           863:
        !           864:        IEEE80211_DPRINTF(("%s\n", __func__));
        !           865:        s = splnet();
        !           866:        while ((ni = RB_MIN(ieee80211_tree, &ic->ic_tree)) != NULL)
        !           867:                ieee80211_free_node(ic, ni);
        !           868:        splx(s);
        !           869:
        !           870:        if (ic->ic_bss != NULL)
        !           871:                ieee80211_node_cleanup(ic, ic->ic_bss); /* for station mode */
        !           872: }
        !           873:
        !           874: /*
        !           875:  * Timeout inactive nodes.
        !           876:  */
        !           877: void
        !           878: ieee80211_clean_nodes(struct ieee80211com *ic)
        !           879: {
        !           880:        struct ieee80211_node *ni, *next_ni;
        !           881:        u_int gen = ic->ic_scangen++;           /* NB: ok 'cuz single-threaded*/
        !           882:        int s;
        !           883:
        !           884:        s = splnet();
        !           885:        for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
        !           886:            ni != NULL; ni = next_ni) {
        !           887:                next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
        !           888:                if (ic->ic_nnodes <= ic->ic_max_nnodes)
        !           889:                        break;
        !           890:                if (ni->ni_scangen == gen)      /* previously handled */
        !           891:                        continue;
        !           892:                ni->ni_scangen = gen;
        !           893:                if (ni->ni_refcnt > 0)
        !           894:                        continue;
        !           895:                IEEE80211_DPRINTF(("station %s purged from LRU cache\n",
        !           896:                    ether_sprintf(ni->ni_macaddr)));
        !           897:                /*
        !           898:                 * Send a deauthenticate frame.
        !           899:                 */
        !           900:                if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
        !           901:                        splx(s);
        !           902:                        IEEE80211_SEND_MGMT(ic, ni,
        !           903:                            IEEE80211_FC0_SUBTYPE_DEAUTH,
        !           904:                            IEEE80211_REASON_AUTH_EXPIRE);
        !           905:                        s = splnet();
        !           906:                        ieee80211_node_leave(ic, ni);
        !           907:                } else
        !           908:                        ieee80211_free_node(ic, ni);
        !           909:                ic->ic_stats.is_node_timeout++;
        !           910:        }
        !           911:        splx(s);
        !           912: }
        !           913:
        !           914: void
        !           915: ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f,
        !           916:     void *arg)
        !           917: {
        !           918:        struct ieee80211_node *ni;
        !           919:        int s;
        !           920:
        !           921:        s = splnet();
        !           922:        RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree)
        !           923:                (*f)(arg, ni);
        !           924:        splx(s);
        !           925: }
        !           926:
        !           927: /*
        !           928:  * Check if the specified node supports ERP.
        !           929:  */
        !           930: int
        !           931: ieee80211_iserp_sta(const struct ieee80211_node *ni)
        !           932: {
        !           933: #define N(a)   (sizeof (a) / sizeof (a)[0])
        !           934:        static const u_int8_t rates[] = { 2, 4, 11, 22, 12, 24, 48 };
        !           935:        const struct ieee80211_rateset *rs = &ni->ni_rates;
        !           936:        int i, j;
        !           937:
        !           938:        /*
        !           939:         * A STA supports ERP operation if it includes all the Clause 19
        !           940:         * mandatory rates in its supported rate set.
        !           941:         */
        !           942:        for (i = 0; i < N(rates); i++) {
        !           943:                for (j = 0; j < rs->rs_nrates; j++) {
        !           944:                        if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == rates[i])
        !           945:                                break;
        !           946:                }
        !           947:                if (j == rs->rs_nrates)
        !           948:                        return 0;
        !           949:        }
        !           950:        return 1;
        !           951: #undef N
        !           952: }
        !           953:
        !           954: /*
        !           955:  * Handle a station joining an 11g network.
        !           956:  */
        !           957: void
        !           958: ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
        !           959: {
        !           960:        if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) {
        !           961:                /*
        !           962:                 * Joining STA doesn't support short slot time.  We must
        !           963:                 * disable the use of short slot time for all other associated
        !           964:                 * STAs and give the driver a chance to reconfigure the
        !           965:                 * hardware.
        !           966:                 */
        !           967:                if (++ic->ic_longslotsta == 1) {
        !           968:                        if (ic->ic_caps & IEEE80211_C_SHSLOT)
        !           969:                                ieee80211_set_shortslottime(ic, 0);
        !           970:                }
        !           971:                IEEE80211_DPRINTF(("[%s] station needs long slot time, "
        !           972:                    "count %d\n", ether_sprintf(ni->ni_macaddr),
        !           973:                    ic->ic_longslotsta));
        !           974:        }
        !           975:
        !           976:        if (!ieee80211_iserp_sta(ni)) {
        !           977:                /*
        !           978:                 * Joining STA is non-ERP.
        !           979:                 */
        !           980:                ic->ic_nonerpsta++;
        !           981:
        !           982:                IEEE80211_DPRINTF(("[%s] station is non-ERP, %d non-ERP "
        !           983:                    "stations associated\n", ether_sprintf(ni->ni_macaddr),
        !           984:                    ic->ic_nonerpsta));
        !           985:
        !           986:                /* must enable the use of protection */
        !           987:                if (ic->ic_protmode != IEEE80211_PROT_NONE) {
        !           988:                        IEEE80211_DPRINTF(("%s: enable use of protection\n",
        !           989:                            __func__));
        !           990:                        ic->ic_flags |= IEEE80211_F_USEPROT;
        !           991:                }
        !           992:
        !           993:                if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
        !           994:                        ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
        !           995:        } else
        !           996:                ni->ni_flags |= IEEE80211_NODE_ERP;
        !           997: }
        !           998:
        !           999: void
        !          1000: ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
        !          1001:     int resp)
        !          1002: {
        !          1003:        int newassoc;
        !          1004:
        !          1005:        if (ni->ni_associd == 0) {
        !          1006:                u_int16_t aid;
        !          1007:
        !          1008:                /*
        !          1009:                 * It would be clever to search the bitmap
        !          1010:                 * more efficiently, but this will do for now.
        !          1011:                 */
        !          1012:                for (aid = 1; aid < ic->ic_max_aid; aid++) {
        !          1013:                        if (!IEEE80211_AID_ISSET(aid,
        !          1014:                            ic->ic_aid_bitmap))
        !          1015:                                break;
        !          1016:                }
        !          1017:                if (aid >= ic->ic_max_aid) {
        !          1018:                        IEEE80211_SEND_MGMT(ic, ni, resp,
        !          1019:                            IEEE80211_REASON_ASSOC_TOOMANY);
        !          1020:                        ieee80211_node_leave(ic, ni);
        !          1021:                        return;
        !          1022:                }
        !          1023:                ni->ni_associd = aid | 0xc000;
        !          1024:                IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
        !          1025:                newassoc = 1;
        !          1026:                if (ic->ic_curmode == IEEE80211_MODE_11G)
        !          1027:                        ieee80211_node_join_11g(ic, ni);
        !          1028:        } else
        !          1029:                newassoc = 0;
        !          1030:
        !          1031:        IEEE80211_DPRINTF(("station %s %s associated at aid %d\n",
        !          1032:            ether_sprintf(ni->ni_macaddr),
        !          1033:            (newassoc ? "newly" : "already"),
        !          1034:            ni->ni_associd & ~0xc000));
        !          1035:
        !          1036:        /* give driver a chance to setup state like ni_txrate */
        !          1037:        if (ic->ic_newassoc)
        !          1038:                (*ic->ic_newassoc)(ic, ni, newassoc);
        !          1039:        IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
        !          1040:        ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC);
        !          1041:
        !          1042: #if NBRIDGE > 0
        !          1043:        /*
        !          1044:         * If the parent interface belongs to a bridge, learn
        !          1045:         * the node's address dynamically on this interface.
        !          1046:         */
        !          1047:        if (ic->ic_if.if_bridge != NULL)
        !          1048:                bridge_update(&ic->ic_if,
        !          1049:                    (struct ether_addr *)ni->ni_macaddr, 0);
        !          1050: #endif
        !          1051: }
        !          1052:
        !          1053: /*
        !          1054:  * Handle a station leaving an 11g network.
        !          1055:  */
        !          1056: void
        !          1057: ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni)
        !          1058: {
        !          1059:        if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) {
        !          1060: #ifdef DIAGNOSTIC
        !          1061:                if (ic->ic_longslotsta == 0) {
        !          1062:                        panic("bogus long slot station count %d",
        !          1063:                            ic->ic_longslotsta);
        !          1064:                }
        !          1065: #endif
        !          1066:                /* leaving STA did not support short slot time */
        !          1067:                if (--ic->ic_longslotsta == 0) {
        !          1068:                        /*
        !          1069:                         * All associated STAs now support short slot time, so
        !          1070:                         * enable this feature and give the driver a chance to
        !          1071:                         * reconfigure the hardware. Notice that IBSS always
        !          1072:                         * use a long slot time.
        !          1073:                         */
        !          1074:                        if ((ic->ic_caps & IEEE80211_C_SHSLOT) &&
        !          1075:                            ic->ic_opmode != IEEE80211_M_IBSS)
        !          1076:                                ieee80211_set_shortslottime(ic, 1);
        !          1077:                }
        !          1078:                IEEE80211_DPRINTF(("[%s] long slot time station leaves, "
        !          1079:                    "count now %d\n", ether_sprintf(ni->ni_macaddr),
        !          1080:                    ic->ic_longslotsta));
        !          1081:        }
        !          1082:
        !          1083:        if (!(ni->ni_flags & IEEE80211_NODE_ERP)) {
        !          1084: #ifdef DIAGNOSTIC
        !          1085:                if (ic->ic_nonerpsta == 0) {
        !          1086:                        panic("bogus non-ERP station count %d\n",
        !          1087:                            ic->ic_nonerpsta);
        !          1088:                }
        !          1089: #endif
        !          1090:                /* leaving STA was non-ERP */
        !          1091:                if (--ic->ic_nonerpsta == 0) {
        !          1092:                        /*
        !          1093:                         * All associated STAs are now ERP capable, disable use
        !          1094:                         * of protection and re-enable short preamble support.
        !          1095:                         */
        !          1096:                        ic->ic_flags &= ~IEEE80211_F_USEPROT;
        !          1097:                        if (ic->ic_caps & IEEE80211_C_SHPREAMBLE)
        !          1098:                                ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
        !          1099:                }
        !          1100:                IEEE80211_DPRINTF(("[%s] non-ERP station leaves, "
        !          1101:                    "count now %d\n", ether_sprintf(ni->ni_macaddr),
        !          1102:                    ic->ic_nonerpsta));
        !          1103:        }
        !          1104: }
        !          1105:
        !          1106: /*
        !          1107:  * Handle bookkeeping for station deauthentication/disassociation
        !          1108:  * when operating as an ap.
        !          1109:  */
        !          1110: void
        !          1111: ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
        !          1112: {
        !          1113:        if (ic->ic_opmode != IEEE80211_M_HOSTAP)
        !          1114:                panic("not in ap mode, mode %u", ic->ic_opmode);
        !          1115:        /*
        !          1116:         * If node wasn't previously associated all
        !          1117:         * we need to do is reclaim the reference.
        !          1118:         */
        !          1119:        if (ni->ni_associd == 0)
        !          1120:                return;
        !          1121:        IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
        !          1122:        ni->ni_associd = 0;
        !          1123:
        !          1124:        if (ic->ic_curmode == IEEE80211_MODE_11G)
        !          1125:                ieee80211_node_leave_11g(ic, ni);
        !          1126:
        !          1127:        ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT);
        !          1128:
        !          1129: #if NBRIDGE > 0
        !          1130:        /*
        !          1131:         * If the parent interface belongs to a bridge, delete
        !          1132:         * any dynamically learned address for this node.
        !          1133:         */
        !          1134:        if (ic->ic_if.if_bridge != NULL)
        !          1135:                bridge_update(&ic->ic_if,
        !          1136:                    (struct ether_addr *)ni->ni_macaddr, 1);
        !          1137: #endif
        !          1138: }
        !          1139:
        !          1140: void
        !          1141: ieee80211_set_tim(struct ieee80211com *ic, int aid, int set)
        !          1142: {
        !          1143:        if (set)
        !          1144:                setbit(ic->ic_tim_bitmap, aid & ~0xc000);
        !          1145:        else
        !          1146:                clrbit(ic->ic_tim_bitmap, aid & ~0xc000);
        !          1147: }
        !          1148:
        !          1149: /*
        !          1150:  * Compare nodes in the tree by lladdr
        !          1151:  */
        !          1152: int
        !          1153: ieee80211_node_cmp(const struct ieee80211_node *b1,
        !          1154:     const struct ieee80211_node *b2)
        !          1155: {
        !          1156:        return (memcmp(b1->ni_macaddr, b2->ni_macaddr, IEEE80211_ADDR_LEN));
        !          1157: }
        !          1158:
        !          1159: /*
        !          1160:  * Generate red-black tree function logic
        !          1161:  */
        !          1162: RB_GENERATE(ieee80211_tree, ieee80211_node, ni_node, ieee80211_node_cmp);

CVSweb