[BACK]Return to if_wi_hostap.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/if_wi_hostap.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: if_wi_hostap.c,v 1.37 2006/11/26 19:46:28 deraadt Exp $       */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2002
        !             5:  *     Thomas Skibo <skibo@pacbell.net>.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by Thomas Skibo.
        !            18:  * 4. Neither the name of the author nor the names of any co-contributors
        !            19:  *    may be used to endorse or promote products derived from this software
        !            20:  *    without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
        !            23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            25:  * ARE DISCLAIMED.  IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
        !            26:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            27:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            28:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            32:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            33:  *
        !            34:  */
        !            35:
        !            36: /* This is experimental Host AP software for Prism 2 802.11b interfaces.
        !            37:  *
        !            38:  * Much of this is based upon the "Linux Host AP driver Host AP driver
        !            39:  * for Intersil Prism2" by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>.
        !            40:  */
        !            41:
        !            42: #include <sys/param.h>
        !            43: #include <sys/systm.h>
        !            44: #include <sys/sockio.h>
        !            45: #include <sys/mbuf.h>
        !            46: #include <sys/malloc.h>
        !            47: #include <sys/kernel.h>
        !            48: #include <sys/timeout.h>
        !            49: #include <sys/proc.h>
        !            50: #include <sys/ucred.h>
        !            51: #include <sys/socket.h>
        !            52: #include <sys/queue.h>
        !            53: #include <sys/syslog.h>
        !            54: #include <sys/sysctl.h>
        !            55: #include <sys/device.h>
        !            56:
        !            57: #include <machine/bus.h>
        !            58:
        !            59: #include <net/if.h>
        !            60: #include <net/if_arp.h>
        !            61: #include <net/if_dl.h>
        !            62: #include <net/if_media.h>
        !            63: #include <net/if_types.h>
        !            64:
        !            65: #include <netinet/in.h>
        !            66: #include <netinet/in_systm.h>
        !            67: #include <netinet/in_var.h>
        !            68: #include <netinet/ip.h>
        !            69: #include <netinet/if_ether.h>
        !            70:
        !            71: #include <net80211/ieee80211_var.h>
        !            72: #include <net80211/ieee80211_ioctl.h>
        !            73:
        !            74: #include <dev/rndvar.h>
        !            75:
        !            76: #include <dev/ic/if_wireg.h>
        !            77: #include <dev/ic/if_wi_ieee.h>
        !            78: #include <dev/ic/if_wivar.h>
        !            79:
        !            80: void wihap_timeout(void *v);
        !            81: void wihap_sta_timeout(void *v);
        !            82: struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr);
        !            83: void wihap_sta_delete(struct wihap_sta_info *sta);
        !            84: struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr);
        !            85: int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]);
        !            86: void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !            87:     caddr_t pkt, int len);
        !            88: void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[],
        !            89:     u_int16_t reason);
        !            90: void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !            91:     caddr_t pkt, int len);
        !            92: void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !            93:     caddr_t pkt, int len);
        !            94: void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[],
        !            95:     u_int16_t reason);
        !            96: void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !            97:     caddr_t pkt, int len);
        !            98:
        !            99: #ifndef SMALL_KERNEL
        !           100: /*
        !           101:  * take_hword()
        !           102:  *
        !           103:  *     Used for parsing management frames.  The pkt pointer and length
        !           104:  *     variables are updated after the value is removed.
        !           105:  */
        !           106: static __inline u_int16_t
        !           107: take_hword(caddr_t *ppkt, int *plen)
        !           108: {
        !           109:        u_int16_t s = letoh16(* (u_int16_t *) *ppkt);
        !           110:        *ppkt += sizeof(u_int16_t);
        !           111:        *plen -= sizeof(u_int16_t);
        !           112:        return s;
        !           113: }
        !           114:
        !           115: /* take_tlv()
        !           116:  *
        !           117:  *     Parse out TLV element from a packet, check for underflow of packet
        !           118:  *     or overflow of buffer, update pkt/len.
        !           119:  */
        !           120: static int
        !           121: take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen)
        !           122: {
        !           123:        u_int8_t id, len;
        !           124:
        !           125:        if (*plen < 2)
        !           126:                return -1;
        !           127:
        !           128:        id = ((u_int8_t *)*ppkt)[0];
        !           129:        len = ((u_int8_t *)*ppkt)[1];
        !           130:
        !           131:        if (id != id_expect || *plen < len+2 || maxlen < len)
        !           132:                return -1;
        !           133:
        !           134:        bcopy(*ppkt + 2, dst, len);
        !           135:        *plen -= 2 + len;
        !           136:        *ppkt += 2 + len;
        !           137:
        !           138:        return (len);
        !           139: }
        !           140:
        !           141: /* put_hword()
        !           142:  *     Put half-word element into management frames.
        !           143:  */
        !           144: static __inline void
        !           145: put_hword(caddr_t *ppkt, u_int16_t s)
        !           146: {
        !           147:        * (u_int16_t *) *ppkt = htole16(s);
        !           148:        *ppkt += sizeof(u_int16_t);
        !           149: }
        !           150:
        !           151: /* put_tlv()
        !           152:  *     Put TLV elements into management frames.
        !           153:  */
        !           154: static void
        !           155: put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len)
        !           156: {
        !           157:        (*ppkt)[0] = id;
        !           158:        (*ppkt)[1] = len;
        !           159:        bcopy(src, (*ppkt) + 2, len);
        !           160:        *ppkt += 2 + len;
        !           161: }
        !           162:
        !           163: static int
        !           164: put_rates(caddr_t *ppkt, u_int16_t rates)
        !           165: {
        !           166:        u_int8_t ratebuf[8];
        !           167:        int len = 0;
        !           168:
        !           169:        if (rates & WI_SUPPRATES_1M)
        !           170:                ratebuf[len++] = 0x82;
        !           171:        if (rates & WI_SUPPRATES_2M)
        !           172:                ratebuf[len++] = 0x84;
        !           173:        if (rates & WI_SUPPRATES_5M)
        !           174:                ratebuf[len++] = 0x8b;
        !           175:        if (rates & WI_SUPPRATES_11M)
        !           176:                ratebuf[len++] = 0x96;
        !           177:
        !           178:        put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len);
        !           179:        return len;
        !           180: }
        !           181:
        !           182: /* wihap_init()
        !           183:  *
        !           184:  *     Initialize host AP data structures.  Called even if port type is
        !           185:  *     not AP.  Caller MUST raise to splnet().
        !           186:  */
        !           187: void
        !           188: wihap_init(struct wi_softc *sc)
        !           189: {
        !           190:        int i;
        !           191:        struct wihap_info *whi = &sc->wi_hostap_info;
        !           192:
        !           193:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           194:                printf("wihap_init: sc=%p whi=%p\n", sc, whi);
        !           195:
        !           196:        bzero(whi, sizeof(struct wihap_info));
        !           197:
        !           198:        if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
        !           199:                return;
        !           200:
        !           201:        whi->apflags = WIHAPFL_ACTIVE;
        !           202:
        !           203:        TAILQ_INIT(&whi->sta_list);
        !           204:        for (i = 0; i < WI_STA_HASH_SIZE; i++)
        !           205:                LIST_INIT(&whi->sta_hash[i]);
        !           206:
        !           207:        whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME;
        !           208:        timeout_set(&whi->tmo, wihap_timeout, sc);
        !           209: }
        !           210:
        !           211: /* wihap_sta_disassoc()
        !           212:  *
        !           213:  *     Send a disassociation frame to a specified station.
        !           214:  */
        !           215: void
        !           216: wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
        !           217: {
        !           218:        struct wi_80211_hdr     *resp_hdr;
        !           219:        caddr_t                 pkt;
        !           220:
        !           221:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           222:                printf("Sending disassoc to sta %s\n", ether_sprintf(sta_addr));
        !           223:
        !           224:        /* Send disassoc packet. */
        !           225:        resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
        !           226:        bzero(resp_hdr, sizeof(struct wi_80211_hdr));
        !           227:        resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS;
        !           228:        pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
        !           229:
        !           230:        bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
        !           231:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
        !           232:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
        !           233:
        !           234:        put_hword(&pkt, reason);
        !           235:
        !           236:        wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
        !           237:            2 + sizeof(struct wi_80211_hdr));
        !           238: }
        !           239:
        !           240: /* wihap_sta_deauth()
        !           241:  *
        !           242:  *     Send a deauthentication message to a specified station.
        !           243:  */
        !           244: void
        !           245: wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
        !           246: {
        !           247:        struct wi_80211_hdr     *resp_hdr;
        !           248:        caddr_t                 pkt;
        !           249:
        !           250:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           251:                printf("Sending deauth to sta %s\n", ether_sprintf(sta_addr));
        !           252:
        !           253:        /* Send deauth packet. */
        !           254:        resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
        !           255:        bzero(resp_hdr, sizeof(struct wi_80211_hdr));
        !           256:        resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH);
        !           257:        pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
        !           258:
        !           259:        bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
        !           260:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
        !           261:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
        !           262:
        !           263:        put_hword(&pkt, reason);
        !           264:
        !           265:        wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
        !           266:            2 + sizeof(struct wi_80211_hdr));
        !           267: }
        !           268:
        !           269: /* wihap_shutdown()
        !           270:  *
        !           271:  *     Disassociate all stations and free up data structures.
        !           272:  */
        !           273: void
        !           274: wihap_shutdown(struct wi_softc *sc)
        !           275: {
        !           276:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           277:        struct wihap_sta_info   *sta, *next;
        !           278:        int i, s;
        !           279:
        !           280:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           281:                printf("wihap_shutdown: sc=%p whi=%p\n", sc, whi);
        !           282:
        !           283:        if (!(whi->apflags & WIHAPFL_ACTIVE))
        !           284:                return;
        !           285:        whi->apflags = 0;
        !           286:
        !           287:        s = splnet();
        !           288:
        !           289:        /* Disable wihap inactivity timer. */
        !           290:        timeout_del(&whi->tmo);
        !           291:
        !           292:        /* Delete all stations from the list. */
        !           293:        for (sta = TAILQ_FIRST(&whi->sta_list);
        !           294:            sta != TAILQ_END(&whi->sta_list); sta = next) {
        !           295:                timeout_del(&sta->tmo);
        !           296:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           297:                        printf("wihap_shutdown: FREE(sta=%p)\n", sta);
        !           298:                next = TAILQ_NEXT(sta, list);
        !           299:                if (sta->challenge)
        !           300:                        FREE(sta->challenge, M_TEMP);
        !           301:                FREE(sta, M_DEVBUF);
        !           302:        }
        !           303:        TAILQ_INIT(&whi->sta_list);
        !           304:
        !           305:        /* Broadcast disassoc and deauth to all the stations. */
        !           306:        if (sc->wi_flags & WI_FLAGS_ATTACHED) {
        !           307:                for (i = 0; i < 5; i++) {
        !           308:                        wihap_sta_disassoc(sc, etherbroadcastaddr,
        !           309:                            IEEE80211_REASON_ASSOC_LEAVE);
        !           310:                        wihap_sta_deauth(sc, etherbroadcastaddr,
        !           311:                            IEEE80211_REASON_AUTH_LEAVE);
        !           312:                        DELAY(50);
        !           313:                }
        !           314:        }
        !           315:
        !           316:        splx(s);
        !           317: }
        !           318:
        !           319: /* sta_hash_func()
        !           320:  * Hash function for finding stations from ethernet address.
        !           321:  */
        !           322: static __inline int
        !           323: sta_hash_func(u_int8_t addr[])
        !           324: {
        !           325:        return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE);
        !           326: }
        !           327:
        !           328: /* addr_cmp():  Maybe this is a faster way to compare addresses? */
        !           329: static __inline int
        !           330: addr_cmp(u_int8_t a[], u_int8_t b[])
        !           331: {
        !           332:        return (*(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4) &&
        !           333:                *(u_int16_t *)(a + 2) == *(u_int16_t *)(b + 2) &&
        !           334:                *(u_int16_t *)(a    ) == *(u_int16_t *)(b));
        !           335: }
        !           336:
        !           337: /* wihap_sta_movetail(): move sta to the tail of the station list in whi */
        !           338: static __inline void
        !           339: wihap_sta_movetail(struct wihap_info *whi, struct wihap_sta_info *sta)
        !           340: {
        !           341:        TAILQ_REMOVE(&whi->sta_list, sta, list);
        !           342:        sta->flags &= ~WI_SIFLAGS_DEAD;
        !           343:        TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
        !           344: }
        !           345:
        !           346: void
        !           347: wihap_timeout(void *v)
        !           348: {
        !           349:        struct wi_softc         *sc = v;
        !           350:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           351:        struct wihap_sta_info   *sta, *next;
        !           352:        int     i, s;
        !           353:
        !           354:        s = splnet();
        !           355:
        !           356:        for (i = 10, sta = TAILQ_FIRST(&whi->sta_list);
        !           357:            i != 0 && sta != TAILQ_END(&whi->sta_list) &&
        !           358:            (sta->flags & WI_SIFLAGS_DEAD); i--, sta = next) {
        !           359:                next = TAILQ_NEXT(sta, list);
        !           360:                if (timeout_pending(&sta->tmo)) {
        !           361:                        /* Became alive again, move to end of list. */
        !           362:                        wihap_sta_movetail(whi, sta);
        !           363:                } else if (sta->flags & WI_SIFLAGS_ASSOC) {
        !           364:                        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           365:                                printf("wihap_timeout: disassoc due to inactivity: %s\n",
        !           366:                                    ether_sprintf(sta->addr));
        !           367:
        !           368:                        /* Disassoc station. */
        !           369:                        wihap_sta_disassoc(sc, sta->addr,
        !           370:                            IEEE80211_REASON_ASSOC_EXPIRE);
        !           371:                        sta->flags &= ~WI_SIFLAGS_ASSOC;
        !           372:
        !           373:                        /*
        !           374:                         * Move to end of the list and reset station timeout.
        !           375:                         * We do this to make sure we don't get deauthed
        !           376:                         * until inactivity_time seconds have passed.
        !           377:                         */
        !           378:                        wihap_sta_movetail(whi, sta);
        !           379:                        timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !           380:                } else if (sta->flags & WI_SIFLAGS_AUTHEN) {
        !           381:                        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           382:                                printf("wihap_timeout: deauth due to inactivity: %s\n",
        !           383:                                    ether_sprintf(sta->addr));
        !           384:
        !           385:                        /* Deauthenticate station. */
        !           386:                        wihap_sta_deauth(sc, sta->addr,
        !           387:                            IEEE80211_REASON_AUTH_EXPIRE);
        !           388:                        sta->flags &= ~WI_SIFLAGS_AUTHEN;
        !           389:
        !           390:                        /* Delete the station if it's not permanent. */
        !           391:                        if (sta->flags & WI_SIFLAGS_PERM)
        !           392:                                wihap_sta_movetail(whi, sta);
        !           393:                        else
        !           394:                                wihap_sta_delete(sta);
        !           395:                }
        !           396:        }
        !           397:
        !           398:        /* Restart the timeout if there are still dead stations left. */
        !           399:        sta = TAILQ_FIRST(&whi->sta_list);
        !           400:        if (sta != NULL && (sta->flags & WI_SIFLAGS_DEAD))
        !           401:                timeout_add(&whi->tmo, 1);      /* still work left, requeue */
        !           402:
        !           403:        splx(s);
        !           404: }
        !           405:
        !           406: void
        !           407: wihap_sta_timeout(void *v)
        !           408: {
        !           409:        struct wihap_sta_info   *sta = v;
        !           410:        struct wi_softc         *sc = sta->sc;
        !           411:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           412:        int     s;
        !           413:
        !           414:        s = splnet();
        !           415:
        !           416:        /* Mark sta as dead and move it to the head of the list. */
        !           417:        TAILQ_REMOVE(&whi->sta_list, sta, list);
        !           418:        sta->flags |= WI_SIFLAGS_DEAD;
        !           419:        TAILQ_INSERT_HEAD(&whi->sta_list, sta, list);
        !           420:
        !           421:        /* Add wihap timeout if we have not already done so. */
        !           422:        if (!timeout_pending(&whi->tmo))
        !           423:                timeout_add(&whi->tmo, hz / 10);
        !           424:
        !           425:        splx(s);
        !           426: }
        !           427:
        !           428: /* wihap_sta_delete()
        !           429:  * Delete a single station and free up its data structure.
        !           430:  * Caller must raise to splnet().
        !           431:  */
        !           432: void
        !           433: wihap_sta_delete(struct wihap_sta_info *sta)
        !           434: {
        !           435:        struct wi_softc         *sc = sta->sc;
        !           436:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           437:        int i = sta->asid - 0xc001;
        !           438:
        !           439:        timeout_del(&sta->tmo);
        !           440:
        !           441:        whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf));
        !           442:
        !           443:        TAILQ_REMOVE(&whi->sta_list, sta, list);
        !           444:        LIST_REMOVE(sta, hash);
        !           445:        if (sta->challenge)
        !           446:                FREE(sta->challenge, M_TEMP);
        !           447:        FREE(sta, M_DEVBUF);
        !           448:        whi->n_stations--;
        !           449: }
        !           450:
        !           451: /* wihap_sta_alloc()
        !           452:  *
        !           453:  *     Create a new station data structure and put it in the list
        !           454:  *     and hash table.
        !           455:  */
        !           456: struct wihap_sta_info *
        !           457: wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr)
        !           458: {
        !           459:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           460:        struct wihap_sta_info   *sta;
        !           461:        int i, hash = sta_hash_func(addr);
        !           462:
        !           463:        /* Allocate structure. */
        !           464:        MALLOC(sta, struct wihap_sta_info *, sizeof(struct wihap_sta_info),
        !           465:            M_DEVBUF, M_NOWAIT);
        !           466:        if (sta == NULL)
        !           467:                return (NULL);
        !           468:
        !           469:        bzero(sta, sizeof(struct wihap_sta_info));
        !           470:
        !           471:        /* Allocate an ASID. */
        !           472:        i=hash<<4;
        !           473:        while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
        !           474:                i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
        !           475:        whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
        !           476:        sta->asid = 0xc001 + i;
        !           477:
        !           478:        /* Insert in list and hash list. */
        !           479:        TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
        !           480:        LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash);
        !           481:
        !           482:        sta->sc = sc;
        !           483:        whi->n_stations++;
        !           484:        bcopy(addr, &sta->addr, ETHER_ADDR_LEN);
        !           485:        timeout_set(&sta->tmo, wihap_sta_timeout, sta);
        !           486:        timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !           487:
        !           488:        return (sta);
        !           489: }
        !           490:
        !           491: /* wihap_sta_find()
        !           492:  *
        !           493:  *     Find station structure given address.
        !           494:  */
        !           495: struct wihap_sta_info *
        !           496: wihap_sta_find(struct wihap_info *whi, u_int8_t *addr)
        !           497: {
        !           498:        int i;
        !           499:        struct wihap_sta_info *sta;
        !           500:
        !           501:        i = sta_hash_func(addr);
        !           502:        LIST_FOREACH(sta, &whi->sta_hash[i], hash)
        !           503:                if (addr_cmp(addr, sta->addr))
        !           504:                        return sta;
        !           505:
        !           506:        return (NULL);
        !           507: }
        !           508:
        !           509: static __inline int
        !           510: wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
        !           511: {
        !           512:        struct wi_softc *sc = sta->sc;
        !           513:        int     i;
        !           514:
        !           515:        sta->rates = 0;
        !           516:        sta->tx_max_rate = 0;
        !           517:        for (i = 0; i < rates_len; i++)
        !           518:                switch (rates[i] & 0x7f) {
        !           519:                case 0x02:
        !           520:                        sta->rates |= WI_SUPPRATES_1M;
        !           521:                        break;
        !           522:                case 0x04:
        !           523:                        sta->rates |= WI_SUPPRATES_2M;
        !           524:                        if (sta->tx_max_rate < 1)
        !           525:                                sta->tx_max_rate = 1;
        !           526:                        break;
        !           527:                case 0x0b:
        !           528:                        sta->rates |= WI_SUPPRATES_5M;
        !           529:                        if (sta->tx_max_rate < 2)
        !           530:                                sta->tx_max_rate = 2;
        !           531:                        break;
        !           532:                case 0x16:
        !           533:                        sta->rates |= WI_SUPPRATES_11M;
        !           534:                        sta->tx_max_rate = 3;
        !           535:                        break;
        !           536:                }
        !           537:
        !           538:        sta->rates &= sc->wi_supprates;
        !           539:        sta->tx_curr_rate = sta->tx_max_rate;
        !           540:
        !           541:        return (sta->rates == 0 ? -1 : 0);
        !           542: }
        !           543:
        !           544:
        !           545: /* wihap_auth_req()
        !           546:  *
        !           547:  *     Handle incoming authentication request.
        !           548:  */
        !           549: void
        !           550: wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !           551:     caddr_t pkt, int len)
        !           552: {
        !           553:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           554:        struct wihap_sta_info   *sta;
        !           555:        int                     i, s;
        !           556:
        !           557:        u_int16_t               algo;
        !           558:        u_int16_t               seq;
        !           559:        u_int16_t               status;
        !           560:        int                     challenge_len;
        !           561:        u_int32_t               challenge[32];
        !           562:
        !           563:        struct wi_80211_hdr     *resp_hdr;
        !           564:
        !           565:        if (len < 6) {
        !           566:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           567:                        printf("wihap_auth_req: station %s short request\n",
        !           568:                            ether_sprintf(rxfrm->wi_addr2));
        !           569:                return;
        !           570:        }
        !           571:
        !           572:        /* Break open packet. */
        !           573:        algo = take_hword(&pkt, &len);
        !           574:        seq = take_hword(&pkt, &len);
        !           575:        status = take_hword(&pkt, &len);
        !           576:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           577:                printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n",
        !           578:                    ether_sprintf(rxfrm->wi_addr2), algo, seq);
        !           579:
        !           580:        /* Ignore vendor private tlv (if any). */
        !           581:        (void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge,
        !           582:            sizeof(challenge));
        !           583:
        !           584:        challenge_len = 0;
        !           585:        if (len > 0 && (challenge_len = take_tlv(&pkt, &len,
        !           586:            IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) {
        !           587:                status = IEEE80211_STATUS_CHALLENGE;
        !           588:                goto fail;
        !           589:        }
        !           590:
        !           591:        /* Find or create station info. */
        !           592:        sta = wihap_sta_find(whi, rxfrm->wi_addr2);
        !           593:        if (sta == NULL) {
        !           594:
        !           595:                /* Are we allowing new stations?
        !           596:                 */
        !           597:                if (whi->apflags & WIHAPFL_MAC_FILT) {
        !           598:                        status = IEEE80211_STATUS_OTHER; /* XXX */
        !           599:                        goto fail;
        !           600:                }
        !           601:
        !           602:                /* Check for too many stations.
        !           603:                 */
        !           604:                if (whi->n_stations >= WIHAP_MAX_STATIONS) {
        !           605:                        status = IEEE80211_STATUS_TOOMANY;
        !           606:                        goto fail;
        !           607:                }
        !           608:
        !           609:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           610:                        printf("wihap_auth_req: new station\n");
        !           611:
        !           612:                /* Create new station. */
        !           613:                s = splnet();
        !           614:                sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
        !           615:                splx(s);
        !           616:                if (sta == NULL) {
        !           617:                        /* Out of memory! */
        !           618:                        status = IEEE80211_STATUS_TOOMANY;
        !           619:                        goto fail;
        !           620:                }
        !           621:        }
        !           622:        timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !           623:
        !           624:        /* Note: it's okay to leave the station info structure around
        !           625:         * if the authen fails.  It'll be timed out eventually.
        !           626:         */
        !           627:        switch (algo) {
        !           628:        case IEEE80211_AUTH_ALG_OPEN:
        !           629:                if (sc->wi_authtype != IEEE80211_AUTH_OPEN) {
        !           630:                        status = IEEE80211_STATUS_ALG;
        !           631:                        goto fail;
        !           632:                }
        !           633:                if (seq != 1) {
        !           634:                        status = IEEE80211_STATUS_SEQUENCE;
        !           635:                        goto fail;
        !           636:                }
        !           637:                challenge_len = 0;
        !           638:                sta->flags |= WI_SIFLAGS_AUTHEN;
        !           639:                break;
        !           640:        case IEEE80211_AUTH_ALG_SHARED:
        !           641:                if (sc->wi_authtype != IEEE80211_AUTH_SHARED) {
        !           642:                        status = IEEE80211_STATUS_ALG;
        !           643:                        goto fail;
        !           644:                }
        !           645:                switch (seq) {
        !           646:                case 1:
        !           647:                        /* Create a challenge frame. */
        !           648:                        if (!sta->challenge) {
        !           649:                                MALLOC(sta->challenge, u_int32_t *, 128,
        !           650:                                       M_TEMP, M_NOWAIT);
        !           651:                                if (!sta->challenge)
        !           652:                                        return;
        !           653:                        }
        !           654:                        for (i = 0; i < 32; i++)
        !           655:                                challenge[i] = sta->challenge[i] =
        !           656:                                        arc4random();
        !           657:
        !           658:                        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           659:                                printf("\tchallenge: 0x%x 0x%x ...\n",
        !           660:                                   challenge[0], challenge[1]);
        !           661:                        challenge_len = 128;
        !           662:                        break;
        !           663:                case 3:
        !           664:                        if (challenge_len != 128 || !sta->challenge ||
        !           665:                            !(letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) {
        !           666:                                status = IEEE80211_STATUS_CHALLENGE;
        !           667:                                goto fail;
        !           668:                        }
        !           669:
        !           670:                        for (i=0; i<32; i++)
        !           671:                                if (sta->challenge[i] != challenge[i]) {
        !           672:                                        status = IEEE80211_STATUS_CHALLENGE;
        !           673:                                        goto fail;
        !           674:                                }
        !           675:
        !           676:                        sta->flags |= WI_SIFLAGS_AUTHEN;
        !           677:                        FREE(sta->challenge, M_TEMP);
        !           678:                        sta->challenge = NULL;
        !           679:                        challenge_len = 0;
        !           680:                        break;
        !           681:                default:
        !           682:                        status = IEEE80211_STATUS_SEQUENCE;
        !           683:                        goto fail;
        !           684:                } /* switch (seq) */
        !           685:                break;
        !           686:        default:
        !           687:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           688:                        printf("wihap_auth_req: algorithm unsupported: 0x%x\n",
        !           689:                           algo);
        !           690:                status = IEEE80211_STATUS_ALG;
        !           691:                goto fail;
        !           692:        } /* switch (algo) */
        !           693:
        !           694:        status = IEEE80211_STATUS_SUCCESS;
        !           695:
        !           696: fail:
        !           697:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           698:                printf("wihap_auth_req: returns status=0x%x\n", status);
        !           699:
        !           700:        /* Send response. */
        !           701:        resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
        !           702:        bzero(resp_hdr, sizeof(struct wi_80211_hdr));
        !           703:        resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH);
        !           704:        bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
        !           705:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
        !           706:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
        !           707:
        !           708:        pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
        !           709:        put_hword(&pkt, algo);
        !           710:        put_hword(&pkt, seq + 1);
        !           711:        put_hword(&pkt, status);
        !           712:        if (challenge_len > 0)
        !           713:                put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE,
        !           714:                        challenge, challenge_len);
        !           715:
        !           716:        wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
        !           717:            6 + sizeof(struct wi_80211_hdr) +
        !           718:            (challenge_len > 0 ? challenge_len + 2 : 0));
        !           719: }
        !           720:
        !           721:
        !           722: /* wihap_assoc_req()
        !           723:  *
        !           724:  *     Handle incoming association and reassociation requests.
        !           725:  */
        !           726: void
        !           727: wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !           728:                caddr_t pkt, int len)
        !           729: {
        !           730:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           731:        struct wihap_sta_info   *sta;
        !           732:        struct wi_80211_hdr     *resp_hdr;
        !           733:        u_int16_t               capinfo;
        !           734:        u_int16_t               lstintvl;
        !           735:        u_int8_t                rates[12];
        !           736:        int                     ssid_len, rates_len;
        !           737:        struct ieee80211_nwid   ssid;
        !           738:        u_int16_t               status;
        !           739:        u_int16_t               asid = 0;
        !           740:
        !           741:        if (len < 8)
        !           742:                return;
        !           743:
        !           744:        /* Pull out request parameters. */
        !           745:        capinfo = take_hword(&pkt, &len);
        !           746:        lstintvl = take_hword(&pkt, &len);
        !           747:
        !           748:        if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
        !           749:            htole16(WI_STYPE_MGMT_REASREQ)) {
        !           750:                if (len < 6)
        !           751:                        return;
        !           752:                /* Eat the MAC address of the current AP */
        !           753:                take_hword(&pkt, &len);
        !           754:                take_hword(&pkt, &len);
        !           755:                take_hword(&pkt, &len);
        !           756:        }
        !           757:
        !           758:        if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
        !           759:            ssid.i_nwid, sizeof(ssid))) < 0)
        !           760:                return;
        !           761:        ssid.i_len = ssid_len;
        !           762:        if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES,
        !           763:            rates, sizeof(rates))) < 0)
        !           764:                return;
        !           765:
        !           766:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           767:                printf("wihap_assoc_req: from station %s\n",
        !           768:                    ether_sprintf(rxfrm->wi_addr2));
        !           769:
        !           770:        /* If SSID doesn't match, simply drop. */
        !           771:        if (sc->wi_net_name.i_len != ssid.i_len ||
        !           772:            memcmp(sc->wi_net_name.i_nwid, ssid.i_nwid, ssid.i_len)) {
        !           773:
        !           774:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           775:                        printf("wihap_assoc_req: bad ssid: '%.*s' != '%.*s'\n",
        !           776:                            ssid.i_len, ssid.i_nwid, sc->wi_net_name.i_len,
        !           777:                            sc->wi_net_name.i_nwid);
        !           778:                return;
        !           779:        }
        !           780:
        !           781:        /* Is this station authenticated yet? */
        !           782:        sta = wihap_sta_find(whi, rxfrm->wi_addr2);
        !           783:        if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) {
        !           784:                wihap_sta_deauth(sc, rxfrm->wi_addr2,
        !           785:                    IEEE80211_REASON_NOT_AUTHED);
        !           786:                return;
        !           787:        }
        !           788:
        !           789:        /* Check supported rates against ours. */
        !           790:        if (wihap_check_rates(sta, rates, rates_len) < 0) {
        !           791:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           792:                        printf("wihap_assoc_req: rates mismatch.\n");
        !           793:                status = IEEE80211_STATUS_BASIC_RATE;
        !           794:                goto fail;
        !           795:        }
        !           796:
        !           797:        /* Check capinfo.
        !           798:         * Check for ESS, not IBSS.
        !           799:         * Check WEP/PRIVACY flags match.
        !           800:         * Refuse stations requesting to be put on CF-polling list.
        !           801:         */
        !           802:        sta->capinfo = capinfo;
        !           803:        status = IEEE80211_STATUS_CAPINFO;
        !           804:        if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) !=
        !           805:            IEEE80211_CAPINFO_ESS) {
        !           806:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           807:                        printf("wihap_assoc_req: capinfo: not ESS: "
        !           808:                            "capinfo=0x%x\n", capinfo);
        !           809:                goto fail;
        !           810:
        !           811:        }
        !           812:        if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) ||
        !           813:            (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) {
        !           814:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           815:                        printf("wihap_assoc_req: WEP flag mismatch: "
        !           816:                            "capinfo=0x%x\n", capinfo);
        !           817:                goto fail;
        !           818:        }
        !           819:        if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE |
        !           820:            IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) {
        !           821:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           822:                        printf("wihap_assoc_req: polling not supported: "
        !           823:                            "capinfo=0x%x\n", capinfo);
        !           824:                goto fail;
        !           825:        }
        !           826:
        !           827:        /* Use ASID is allocated by whi_sta_alloc(). */
        !           828:        asid = sta->asid;
        !           829:
        !           830:        if (sta->flags & WI_SIFLAGS_ASSOC) {
        !           831:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           832:                        printf("wihap_assoc_req: already assoc'ed?\n");
        !           833:        }
        !           834:
        !           835:        sta->flags |= WI_SIFLAGS_ASSOC;
        !           836:        timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !           837:        status = IEEE80211_STATUS_SUCCESS;
        !           838:
        !           839: fail:
        !           840:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           841:                printf("wihap_assoc_req: returns status=0x%x\n", status);
        !           842:
        !           843:        /* Send response. */
        !           844:        resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
        !           845:        bzero(resp_hdr, sizeof(struct wi_80211_hdr));
        !           846:        resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
        !           847:        pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
        !           848:
        !           849:        bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
        !           850:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
        !           851:        bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
        !           852:
        !           853:        put_hword(&pkt, capinfo);
        !           854:        put_hword(&pkt, status);
        !           855:        put_hword(&pkt, asid);
        !           856:        rates_len = put_rates(&pkt, sc->wi_supprates);
        !           857:
        !           858:        wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
        !           859:            8 + rates_len + sizeof(struct wi_80211_hdr));
        !           860: }
        !           861:
        !           862: /* wihap_deauth_req()
        !           863:  *
        !           864:  *     Handle deauthentication requests.  Delete the station.
        !           865:  */
        !           866: void
        !           867: wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !           868:                 caddr_t pkt, int len)
        !           869: {
        !           870:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           871:        struct wihap_sta_info   *sta;
        !           872:        u_int16_t               reason;
        !           873:
        !           874:        if (len<2)
        !           875:                return;
        !           876:
        !           877:        reason = take_hword(&pkt, &len);
        !           878:
        !           879:        sta = wihap_sta_find(whi, rxfrm->wi_addr2);
        !           880:        if (sta == NULL) {
        !           881:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           882:                        printf("wihap_deauth_req: unknown station: %s\n",
        !           883:                            ether_sprintf(rxfrm->wi_addr2));
        !           884:        }
        !           885:        else
        !           886:                wihap_sta_delete(sta);
        !           887: }
        !           888:
        !           889: /* wihap_disassoc_req()
        !           890:  *
        !           891:  *     Handle disassociation requests.  Just reset the assoc flag.
        !           892:  *     We'll free up the station resources when we get a deauth
        !           893:  *     request or when it times out.
        !           894:  */
        !           895: void
        !           896: wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
        !           897:     caddr_t pkt, int len)
        !           898: {
        !           899:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !           900:        struct wihap_sta_info   *sta;
        !           901:        u_int16_t               reason;
        !           902:
        !           903:        if (len < 2)
        !           904:                return;
        !           905:
        !           906:        reason = take_hword(&pkt, &len);
        !           907:
        !           908:        sta = wihap_sta_find(whi, rxfrm->wi_addr2);
        !           909:        if (sta == NULL) {
        !           910:                if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !           911:                        printf("wihap_disassoc_req: unknown station: %s\n",
        !           912:                            ether_sprintf(rxfrm->wi_addr2));
        !           913:        }
        !           914:        else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) {
        !           915:                /*
        !           916:                 * If station is not authenticated, send deauthentication
        !           917:                 * frame.
        !           918:                 */
        !           919:                wihap_sta_deauth(sc, rxfrm->wi_addr2,
        !           920:                    IEEE80211_REASON_NOT_AUTHED);
        !           921:                return;
        !           922:        }
        !           923:        else
        !           924:                sta->flags &= ~WI_SIFLAGS_ASSOC;
        !           925: }
        !           926:
        !           927: /* wihap_debug_frame_type()
        !           928:  *
        !           929:  * Print out frame type.  Used in early debugging.
        !           930:  */
        !           931: static __inline void
        !           932: wihap_debug_frame_type(struct wi_frame *rxfrm)
        !           933: {
        !           934:        printf("wihap_mgmt_input: len=%d ", letoh16(rxfrm->wi_dat_len));
        !           935:
        !           936:        if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
        !           937:            htole16(WI_FTYPE_MGMT)) {
        !           938:
        !           939:                printf("MGMT: ");
        !           940:
        !           941:                switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
        !           942:                case WI_STYPE_MGMT_ASREQ:
        !           943:                        printf("assoc req: \n");
        !           944:                        break;
        !           945:                case WI_STYPE_MGMT_ASRESP:
        !           946:                        printf("assoc resp: \n");
        !           947:                        break;
        !           948:                case WI_STYPE_MGMT_REASREQ:
        !           949:                        printf("reassoc req: \n");
        !           950:                        break;
        !           951:                case WI_STYPE_MGMT_REASRESP:
        !           952:                        printf("reassoc resp: \n");
        !           953:                        break;
        !           954:                case WI_STYPE_MGMT_PROBEREQ:
        !           955:                        printf("probe req: \n");
        !           956:                        break;
        !           957:                case WI_STYPE_MGMT_PROBERESP:
        !           958:                        printf("probe resp: \n");
        !           959:                        break;
        !           960:                case WI_STYPE_MGMT_BEACON:
        !           961:                        printf("beacon: \n");
        !           962:                        break;
        !           963:                case WI_STYPE_MGMT_ATIM:
        !           964:                        printf("ann traf ind \n");
        !           965:                        break;
        !           966:                case WI_STYPE_MGMT_DISAS:
        !           967:                        printf("disassociation: \n");
        !           968:                        break;
        !           969:                case WI_STYPE_MGMT_AUTH:
        !           970:                        printf("auth: \n");
        !           971:                        break;
        !           972:                case WI_STYPE_MGMT_DEAUTH:
        !           973:                        printf("deauth: \n");
        !           974:                        break;
        !           975:                default:
        !           976:                        printf("unknown (stype=0x%x)\n",
        !           977:                            letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE);
        !           978:                }
        !           979:
        !           980:        }
        !           981:        else {
        !           982:                printf("ftype=0x%x (ctl=0x%x)\n",
        !           983:                    letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE,
        !           984:                    letoh16(rxfrm->wi_frame_ctl));
        !           985:        }
        !           986: }
        !           987:
        !           988: /*
        !           989:  * wihap_mgmt_input:
        !           990:  *
        !           991:  *     Called for each management frame received in host ap mode.
        !           992:  *     wihap_mgmt_input() is expected to free the mbuf.
        !           993:  */
        !           994: void
        !           995: wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
        !           996: {
        !           997:        caddr_t pkt;
        !           998:        int     s, len;
        !           999:
        !          1000:        if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
        !          1001:                wihap_debug_frame_type(rxfrm);
        !          1002:
        !          1003:        pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW;
        !          1004:        len = m->m_len - WI_802_11_OFFSET_RAW;
        !          1005:
        !          1006:        if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
        !          1007:            htole16(WI_FTYPE_MGMT)) {
        !          1008:
        !          1009:                /* any of the following will mess w/ the station list */
        !          1010:                s = splsoftclock();
        !          1011:                switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
        !          1012:                case WI_STYPE_MGMT_ASREQ:
        !          1013:                        wihap_assoc_req(sc, rxfrm, pkt, len);
        !          1014:                        break;
        !          1015:                case WI_STYPE_MGMT_ASRESP:
        !          1016:                        break;
        !          1017:                case WI_STYPE_MGMT_REASREQ:
        !          1018:                        wihap_assoc_req(sc, rxfrm, pkt, len);
        !          1019:                        break;
        !          1020:                case WI_STYPE_MGMT_REASRESP:
        !          1021:                        break;
        !          1022:                case WI_STYPE_MGMT_PROBEREQ:
        !          1023:                        break;
        !          1024:                case WI_STYPE_MGMT_PROBERESP:
        !          1025:                        break;
        !          1026:                case WI_STYPE_MGMT_BEACON:
        !          1027:                        break;
        !          1028:                case WI_STYPE_MGMT_ATIM:
        !          1029:                        break;
        !          1030:                case WI_STYPE_MGMT_DISAS:
        !          1031:                        wihap_disassoc_req(sc, rxfrm, pkt, len);
        !          1032:                        break;
        !          1033:                case WI_STYPE_MGMT_AUTH:
        !          1034:                        wihap_auth_req(sc, rxfrm, pkt, len);
        !          1035:                        break;
        !          1036:                case WI_STYPE_MGMT_DEAUTH:
        !          1037:                        wihap_deauth_req(sc, rxfrm, pkt, len);
        !          1038:                        break;
        !          1039:                }
        !          1040:                splx(s);
        !          1041:        }
        !          1042:
        !          1043:        m_freem(m);
        !          1044: }
        !          1045:
        !          1046: /* wihap_sta_is_assoc()
        !          1047:  *
        !          1048:  *     Determine if a station is assoc'ed.  Update its activity
        !          1049:  *     counter as a side-effect.
        !          1050:  */
        !          1051: int
        !          1052: wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[])
        !          1053: {
        !          1054:        struct wihap_sta_info *sta;
        !          1055:
        !          1056:        sta = wihap_sta_find(whi, addr);
        !          1057:        if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
        !          1058:                /* Keep it active. */
        !          1059:                timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !          1060:                return (1);
        !          1061:        }
        !          1062:
        !          1063:        return (0);
        !          1064: }
        !          1065:
        !          1066: /* wihap_check_tx()
        !          1067:  *
        !          1068:  *     Determine if a station is assoc'ed, get its tx rate, and update
        !          1069:  *     its activity.
        !          1070:  */
        !          1071: int
        !          1072: wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
        !          1073: {
        !          1074:        struct wihap_sta_info *sta;
        !          1075:        static u_int8_t txratetable[] = { 10, 20, 55, 110 };
        !          1076:        int s;
        !          1077:
        !          1078:        if (addr[0] & 0x01) {
        !          1079:                *txrate = 0; /* XXX: multicast rate? */
        !          1080:                return (1);
        !          1081:        }
        !          1082:
        !          1083:        s = splsoftclock();
        !          1084:        sta = wihap_sta_find(whi, addr);
        !          1085:        if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
        !          1086:                /* Keep it active. */
        !          1087:                timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !          1088:                *txrate = txratetable[sta->tx_curr_rate];
        !          1089:                splx(s);
        !          1090:                return (1);
        !          1091:        }
        !          1092:        splx(s);
        !          1093:
        !          1094:        return (0);
        !          1095: }
        !          1096:
        !          1097: /*
        !          1098:  * wihap_data_input()
        !          1099:  *
        !          1100:  *     Handle all data input on interface when in Host AP mode.
        !          1101:  *     Some packets are destined for this machine, others are
        !          1102:  *     repeated to other stations.
        !          1103:  *
        !          1104:  *     If wihap_data_input() returns a non-zero, it has processed
        !          1105:  *     the packet and will free the mbuf.
        !          1106:  */
        !          1107: int
        !          1108: wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
        !          1109: {
        !          1110:        struct ifnet            *ifp = &sc->sc_ic.ic_if;
        !          1111:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !          1112:        struct wihap_sta_info   *sta;
        !          1113:        int                     mcast, s;
        !          1114:        u_int16_t               fctl;
        !          1115:
        !          1116:        /*
        !          1117:         * TODS flag must be set.  However, Lucent cards set NULLFUNC but
        !          1118:         * not TODS when probing an AP to see if it is alive after it has
        !          1119:         * been down for a while.  We accept these probe packets and send a
        !          1120:         * disassoc packet later on if the station is not already associated.
        !          1121:         */
        !          1122:        fctl = letoh16(rxfrm->wi_frame_ctl);
        !          1123:        if (!(fctl & WI_FCTL_TODS) && !(fctl & WI_STYPE_NULLFUNC)) {
        !          1124:                if (ifp->if_flags & IFF_DEBUG)
        !          1125:                        printf("wihap_data_input: no TODS src=%s, fctl=0x%x\n",
        !          1126:                            ether_sprintf(rxfrm->wi_addr2), fctl);
        !          1127:                m_freem(m);
        !          1128:                return (1);
        !          1129:        }
        !          1130:
        !          1131:        /* Check BSSID. (Is this necessary?) */
        !          1132:        if (!addr_cmp(rxfrm->wi_addr1, sc->sc_ic.ic_myaddr)) {
        !          1133:                if (ifp->if_flags & IFF_DEBUG)
        !          1134:                        printf("wihap_data_input: incorrect bss: %s\n",
        !          1135:                            ether_sprintf(rxfrm->wi_addr1));
        !          1136:                m_freem(m);
        !          1137:                return (1);
        !          1138:        }
        !          1139:
        !          1140:        s = splsoftclock();
        !          1141:
        !          1142:        /* Find source station. */
        !          1143:        sta = wihap_sta_find(whi, rxfrm->wi_addr2);
        !          1144:
        !          1145:        /* Source station must be associated. */
        !          1146:        if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) {
        !          1147:                if (ifp->if_flags & IFF_DEBUG)
        !          1148:                        printf("wihap_data_input: dropping unassoc src %s\n",
        !          1149:                            ether_sprintf(rxfrm->wi_addr2));
        !          1150:                wihap_sta_disassoc(sc, rxfrm->wi_addr2,
        !          1151:                    IEEE80211_REASON_ASSOC_LEAVE);
        !          1152:                splx(s);
        !          1153:                m_freem(m);
        !          1154:                return (1);
        !          1155:        }
        !          1156:
        !          1157:        timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !          1158:        sta->sig_info = letoh16(rxfrm->wi_q_info);
        !          1159:
        !          1160:        splx(s);
        !          1161:
        !          1162:        /* Repeat this packet to BSS? */
        !          1163:        mcast = (rxfrm->wi_addr3[0] & 0x01) != 0;
        !          1164:        if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) {
        !          1165:
        !          1166:                /* If it's multicast, make a copy.
        !          1167:                 */
        !          1168:                if (mcast) {
        !          1169:                        m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
        !          1170:                        if (m == NULL)
        !          1171:                                return (0);
        !          1172:                        m->m_flags |= M_MCAST; /* XXX */
        !          1173:                }
        !          1174:
        !          1175:                /* Queue up for repeating.
        !          1176:                 */
        !          1177:                if (IF_QFULL(&ifp->if_snd)) {
        !          1178:                        IF_DROP(&ifp->if_snd);
        !          1179:                        m_freem(m);
        !          1180:                }
        !          1181:                else {
        !          1182:                        ifp->if_obytes += m->m_pkthdr.len;
        !          1183:                        if (m->m_flags & M_MCAST)
        !          1184:                                ifp->if_omcasts++;
        !          1185:                        IF_ENQUEUE(&ifp->if_snd, m);
        !          1186:                        if ((ifp->if_flags & IFF_OACTIVE) == 0)
        !          1187:                                (*ifp->if_start)(ifp);
        !          1188:                }
        !          1189:                return (!mcast);
        !          1190:        }
        !          1191:
        !          1192:        return (0);
        !          1193: }
        !          1194:
        !          1195: /* wihap_ioctl()
        !          1196:  *
        !          1197:  *     Handle Host AP specific ioctls.  Called from wi_ioctl().
        !          1198:  */
        !          1199: int
        !          1200: wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
        !          1201: {
        !          1202:        struct proc             *p = curproc;
        !          1203:        struct ifreq            *ifr = (struct ifreq *) data;
        !          1204:        struct wihap_info       *whi = &sc->wi_hostap_info;
        !          1205:        struct wihap_sta_info   *sta;
        !          1206:        struct hostap_getall    reqall;
        !          1207:        struct hostap_sta       reqsta;
        !          1208:        struct hostap_sta       stabuf;
        !          1209:        int                     s, error = 0, n, flag;
        !          1210:
        !          1211:        struct ieee80211_nodereq nr;
        !          1212:        struct ieee80211_nodereq_all *na;
        !          1213:
        !          1214:        if (!(sc->sc_ic.ic_if.if_flags & IFF_RUNNING))
        !          1215:                return ENODEV;
        !          1216:
        !          1217:        switch (command) {
        !          1218:        case SIOCHOSTAP_DEL:
        !          1219:                if ((error = suser(p, 0)))
        !          1220:                        break;
        !          1221:                if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
        !          1222:                        break;
        !          1223:                s = splnet();
        !          1224:                sta = wihap_sta_find(whi, reqsta.addr);
        !          1225:                if (sta == NULL)
        !          1226:                        error = ENOENT;
        !          1227:                else {
        !          1228:                        /* Disassociate station. */
        !          1229:                        if (sta->flags & WI_SIFLAGS_ASSOC)
        !          1230:                                wihap_sta_disassoc(sc, sta->addr,
        !          1231:                                    IEEE80211_REASON_ASSOC_LEAVE);
        !          1232:                        /* Deauth station. */
        !          1233:                        if (sta->flags & WI_SIFLAGS_AUTHEN)
        !          1234:                                wihap_sta_deauth(sc, sta->addr,
        !          1235:                                    IEEE80211_REASON_AUTH_LEAVE);
        !          1236:
        !          1237:                        wihap_sta_delete(sta);
        !          1238:                }
        !          1239:                splx(s);
        !          1240:                break;
        !          1241:
        !          1242:        case SIOCHOSTAP_GET:
        !          1243:                if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
        !          1244:                        break;
        !          1245:                s = splnet();
        !          1246:                sta = wihap_sta_find(whi, reqsta.addr);
        !          1247:                if (sta == NULL)
        !          1248:                        error = ENOENT;
        !          1249:                else {
        !          1250:                        reqsta.flags = sta->flags;
        !          1251:                        reqsta.asid = sta->asid;
        !          1252:                        reqsta.capinfo = sta->capinfo;
        !          1253:                        reqsta.sig_info = sta->sig_info;
        !          1254:                        reqsta.rates = sta->rates;
        !          1255:
        !          1256:                        error = copyout(&reqsta, ifr->ifr_data,
        !          1257:                            sizeof(reqsta));
        !          1258:                }
        !          1259:                splx(s);
        !          1260:                break;
        !          1261:
        !          1262:        case SIOCHOSTAP_ADD:
        !          1263:                if ((error = suser(p, 0)))
        !          1264:                        break;
        !          1265:                if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
        !          1266:                        break;
        !          1267:                s = splnet();
        !          1268:                sta = wihap_sta_find(whi, reqsta.addr);
        !          1269:                if (sta != NULL) {
        !          1270:                        error = EEXIST;
        !          1271:                        splx(s);
        !          1272:                        break;
        !          1273:                }
        !          1274:                if (whi->n_stations >= WIHAP_MAX_STATIONS) {
        !          1275:                        error = ENOSPC;
        !          1276:                        splx(s);
        !          1277:                        break;
        !          1278:                }
        !          1279:                sta = wihap_sta_alloc(sc, reqsta.addr);
        !          1280:                sta->flags = reqsta.flags;
        !          1281:                timeout_add(&sta->tmo, hz * whi->inactivity_time);
        !          1282:                splx(s);
        !          1283:                break;
        !          1284:
        !          1285:        case SIOCHOSTAP_SFLAGS:
        !          1286:                if ((error = suser(p, 0)))
        !          1287:                        break;
        !          1288:                if ((error = copyin(ifr->ifr_data, &flag, sizeof(int))))
        !          1289:                        break;
        !          1290:
        !          1291:                whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) |
        !          1292:                    (flag & ~WIHAPFL_CANTCHANGE);
        !          1293:                break;
        !          1294:
        !          1295:        case SIOCHOSTAP_GFLAGS:
        !          1296:                flag = (int) whi->apflags;
        !          1297:                error = copyout(&flag, ifr->ifr_data, sizeof(int));
        !          1298:                break;
        !          1299:
        !          1300:        case SIOCHOSTAP_GETALL:
        !          1301:                if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall))))
        !          1302:                        break;
        !          1303:
        !          1304:                reqall.nstations = whi->n_stations;
        !          1305:                n = 0;
        !          1306:                s = splnet();
        !          1307:                sta = TAILQ_FIRST(&whi->sta_list);
        !          1308:                while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
        !          1309:
        !          1310:                        bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
        !          1311:                        stabuf.asid = sta->asid;
        !          1312:                        stabuf.flags = sta->flags;
        !          1313:                        stabuf.capinfo = sta->capinfo;
        !          1314:                        stabuf.sig_info = sta->sig_info;
        !          1315:                        stabuf.rates = sta->rates;
        !          1316:
        !          1317:                        error = copyout(&stabuf, (caddr_t) reqall.addr + n,
        !          1318:                            sizeof(struct hostap_sta));
        !          1319:                        if (error)
        !          1320:                                break;
        !          1321:
        !          1322:                        sta = TAILQ_NEXT(sta, list);
        !          1323:                        n += sizeof(struct hostap_sta);
        !          1324:                }
        !          1325:                splx(s);
        !          1326:
        !          1327:                if (!error)
        !          1328:                        error = copyout(&reqall, ifr->ifr_data,
        !          1329:                            sizeof(reqall));
        !          1330:                break;
        !          1331:
        !          1332:        case SIOCG80211ALLNODES:
        !          1333:                na = (struct ieee80211_nodereq_all *)data;
        !          1334:                na->na_nodes = n = 0;
        !          1335:                s = splnet();
        !          1336:                sta = TAILQ_FIRST(&whi->sta_list);
        !          1337:                while (sta && na->na_size >=
        !          1338:                    n + sizeof(struct ieee80211_nodereq)) {
        !          1339:                        bzero(&nr, sizeof(nr));
        !          1340:                        IEEE80211_ADDR_COPY(nr.nr_macaddr, sta->addr);
        !          1341:                        IEEE80211_ADDR_COPY(nr.nr_bssid,
        !          1342:                            &sc->sc_ic.ic_myaddr);
        !          1343:                        nr.nr_channel = sc->wi_channel;
        !          1344:                        nr.nr_chan_flags = IEEE80211_CHAN_B;
        !          1345:                        nr.nr_associd = sta->asid;
        !          1346:                        nr.nr_rssi = sta->sig_info >> 8;
        !          1347:                        nr.nr_max_rssi = 0;
        !          1348:                        nr.nr_capinfo = sta->capinfo;
        !          1349:                        nr.nr_nrates = 0;
        !          1350:                        if (sta->rates & WI_SUPPRATES_1M)
        !          1351:                                nr.nr_rates[nr.nr_nrates++] = 2;
        !          1352:                        if (sta->rates & WI_SUPPRATES_2M)
        !          1353:                                nr.nr_rates[nr.nr_nrates++] = 4;
        !          1354:                        if (sta->rates & WI_SUPPRATES_5M)
        !          1355:                                nr.nr_rates[nr.nr_nrates++] = 11;
        !          1356:                        if (sta->rates & WI_SUPPRATES_11M)
        !          1357:                                nr.nr_rates[nr.nr_nrates++] = 22;
        !          1358:
        !          1359:                        error = copyout(&nr, (caddr_t)na->na_node + n,
        !          1360:                            sizeof(struct ieee80211_nodereq));
        !          1361:                        if (error)
        !          1362:                                break;
        !          1363:                        n += sizeof(struct ieee80211_nodereq);
        !          1364:                        na->na_nodes++;
        !          1365:                        sta = TAILQ_NEXT(sta, list);
        !          1366:                }
        !          1367:                splx(s);
        !          1368:                break;
        !          1369:
        !          1370:        default:
        !          1371:                printf("wihap_ioctl: i shouldn't get other ioctls!\n");
        !          1372:                error = EINVAL;
        !          1373:        }
        !          1374:
        !          1375:        return (error);
        !          1376: }
        !          1377:
        !          1378: #else
        !          1379: void
        !          1380: wihap_init(struct wi_softc *sc)
        !          1381: {
        !          1382:        return;
        !          1383: }
        !          1384:
        !          1385: void
        !          1386: wihap_shutdown(struct wi_softc *sc)
        !          1387: {
        !          1388:        return;
        !          1389: }
        !          1390:
        !          1391: void
        !          1392: wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
        !          1393: {
        !          1394:        return;
        !          1395: }
        !          1396:
        !          1397: int
        !          1398: wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
        !          1399: {
        !          1400:        return (0);
        !          1401: }
        !          1402:
        !          1403: int
        !          1404: wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
        !          1405: {
        !          1406:        return (EINVAL);
        !          1407: }
        !          1408:
        !          1409: int
        !          1410: wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
        !          1411: {
        !          1412:        return (0);
        !          1413: }
        !          1414: #endif

CVSweb