[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

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