diff options
author | imp <imp@FreeBSD.org> | 2002-04-16 07:45:30 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2002-04-16 07:45:30 +0000 |
commit | 37bc817098c906e79d7266109cf861c9963bf150 (patch) | |
tree | 2501c22213ae97acb64f20ceb4d6424d3628b13d | |
parent | ca41daa96dffea7c5f4cdce6e17d62bf9e6f3e59 (diff) | |
download | FreeBSD-src-37bc817098c906e79d7266109cf861c9963bf150.zip FreeBSD-src-37bc817098c906e79d7266109cf861c9963bf150.tar.gz |
Merge from OpenBSD's fixes:
o move timeout from wihap_info to wihap_sta_info
o sprinkle spls into the code (need to use proper -current locking)
o better use of le16toh and htole16
o fix a few leaks m_freem(m)
o minor knf
o minor de-knf to match OpenBSD
o de__P
-rw-r--r-- | sys/dev/wi/wi_hostap.c | 536 | ||||
-rw-r--r-- | sys/dev/wi/wi_hostap.h | 20 |
2 files changed, 278 insertions, 278 deletions
diff --git a/sys/dev/wi/wi_hostap.c b/sys/dev/wi/wi_hostap.c index 64a3933..8497095 100644 --- a/sys/dev/wi/wi_hostap.c +++ b/sys/dev/wi/wi_hostap.c @@ -81,6 +81,26 @@ MALLOC_DEFINE(M_HAP_STA, "hostap_sta", "if_wi host AP mode station entry"); +static void wihap_sta_timeout(void *v); +static struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, + u_int8_t *addr); +static void wihap_sta_delete(struct wihap_sta_info *sta); +static struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, + u_int8_t *addr); +static int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]); +static void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len); +static void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], + u_int16_t reason); +static void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len); +static void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len); +static void wihap_sta_disassoc(struct wi_softc *sc, + struct wihap_sta_info *sta, u_int16_t reason); +static void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, + caddr_t pkt, int len); + /* * take_hword() * @@ -96,8 +116,7 @@ take_hword(caddr_t *ppkt, int *plen) return s; } -/* - * take_tlv() +/* take_tlv() * * Parse out TLV element from a packet, check for underflow of packet * or overflow of buffer, update pkt/len. @@ -116,15 +135,14 @@ take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen) if (id != id_expect || *plen < len+2 || maxlen < len) return -1; - bcopy(*ppkt+2, dst, len); - *plen -= 2+len; - *ppkt += 2+len; + bcopy(*ppkt + 2, dst, len); + *plen -= 2 + len; + *ppkt += 2 + len; - return len; + return (len); } -/* - * put_hword() +/* put_hword() * Put half-word element into management frames. */ static __inline void @@ -134,8 +152,7 @@ put_hword(caddr_t *ppkt, u_int16_t s) *ppkt += sizeof(u_int16_t); } -/* - * put_tlv() +/* put_tlv() * Put TLV elements into management frames. */ static void @@ -143,15 +160,15 @@ put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len) { (*ppkt)[0] = id; (*ppkt)[1] = len; - bcopy(src, (*ppkt)+2, len); - *ppkt += 2+len; + bcopy(src, (*ppkt) + 2, len); + *ppkt += 2 + len; } static int put_rates(caddr_t *ppkt, u_int16_t rates) { - int len = 0; u_int8_t ratebuf[8]; + int len = 0; if (rates & WI_SUPPRATES_1M) ratebuf[len++] = 0x82; @@ -166,8 +183,7 @@ put_rates(caddr_t *ppkt, u_int16_t rates) return len; } -/* - * wihap_init() +/* wihap_init() * * Initialize host AP data structures. Called even if port type is * not AP. @@ -189,27 +205,25 @@ wihap_init(struct wi_softc *sc) whi->apflags = WIHAPFL_ACTIVE; LIST_INIT(&whi->sta_list); - for (i=0; i<WI_STA_HASH_SIZE; i++) + for (i = 0; i < WI_STA_HASH_SIZE; i++) LIST_INIT(&whi->sta_hash[i]); whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME; - whi->hostap_ch = timeout(wihap_timer, sc, hz * WIHAP_INTERVAL); } -/* - * wihap_sta_disassoc() +/* wihap_sta_disassoc() * * Send a disassociation frame to a specified station. */ static void -wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], - u_int16_t reason) +wihap_sta_disassoc(struct wi_softc *sc, + struct wihap_sta_info *sta, u_int16_t reason) { - struct wi_80211_hdr *resp_hdr; + struct wi_80211_hdr *resp_hdr; caddr_t pkt; if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) - printf("Sending disassoc to sta %6D\n", sta_addr, ":"); + printf("Sending disassoc to sta %6D\n", sta->addr, ":"); /* Send disassoc packet. */ resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; @@ -217,25 +231,24 @@ wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS; pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr); - bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN); + bcopy(sta->addr, resp_hdr->addr1, ETHER_ADDR_LEN); bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN); bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN); put_hword(&pkt, reason); - wi_mgmt_xmit(sc, sc->wi_txbuf, 2+sizeof(struct wi_80211_hdr)); + wi_mgmt_xmit(sc, sc->wi_txbuf, 2 + sizeof(struct wi_80211_hdr)); } -/* - * wihap_sta_deauth() +/* wihap_sta_deauth() * * Send a deauthentication message to a specified station. */ static void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], - u_int16_t reason) + u_int16_t reason) { - struct wi_80211_hdr *resp_hdr; + struct wi_80211_hdr *resp_hdr; caddr_t pkt; if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) @@ -253,39 +266,39 @@ wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], put_hword(&pkt, reason); - wi_mgmt_xmit(sc, sc->wi_txbuf, 2+sizeof(struct wi_80211_hdr)); + wi_mgmt_xmit(sc, sc->wi_txbuf, 2 + sizeof(struct wi_80211_hdr)); } -/* - * wihap_shutdown() +/* wihap_shutdown() * * Disassociate all stations and free up data structures. */ void wihap_shutdown(struct wi_softc *sc) { - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta, *next; + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta, *next; + int s; if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_shutdown: sc=0x%x whi=0x%x\n", - (int)sc, (int)whi); + (int)sc, (int)whi); if (!(whi->apflags & WIHAPFL_ACTIVE)) return; - /* - * XXX: I read somewhere you can deauth all the stations with + /* XXX: I read somewhere you can deauth all the stations with * a single broadcast. Maybe try that someday. */ + s = splimp(); sta = LIST_FIRST(&whi->sta_list); while (sta) { - + untimeout(wihap_sta_timeout, sta, sta->tmo); if (!sc->wi_gone) { /* Disassociate station. */ if (sta->flags & WI_SIFLAGS_ASSOC) - wihap_sta_disassoc(sc, sta->addr, + wihap_sta_disassoc(sc, sta, IEEE80211_REASON_ASSOC_LEAVE); /* Deauth station. */ if (sta->flags & WI_SIFLAGS_AUTHEN) @@ -295,19 +308,16 @@ wihap_shutdown(struct wi_softc *sc) /* Delete the structure. */ if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) - printf("wihap_shutdown: FREE(sta=0x%x)\n", (int) sta); + printf("wihap_shutdown: FREE(sta=0x%x)\n", (int)sta); next = LIST_NEXT(sta, list); FREE(sta, M_HAP_STA); sta = next; } - untimeout(wihap_timer, sc, whi->hostap_ch); - whi->apflags = 0; } -/* - * sta_hash_func() +/* sta_hash_func() * Hash function for finding stations from ethernet address. */ static __inline int @@ -316,26 +326,65 @@ sta_hash_func(u_int8_t addr[]) return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE); } -/* - * addr_cmp(): - * Maybe this is a faster way to compare addresses? - */ +/* addr_cmp(): Maybe this is a faster way to compare addresses? */ static __inline int addr_cmp(u_int8_t a[], u_int8_t b[]) { - return (*(u_int16_t *)(a+4) == *(u_int16_t *)(b+4) && - *(u_int32_t *)a == *(u_int32_t *)b); + return (*(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4) && + *(u_int32_t *)(a ) == *(u_int32_t *)(b)); } -/* - * wihap_sta_delete() +void +wihap_sta_timeout(void *v) +{ + struct wihap_sta_info *sta = v; + struct wi_softc *sc = sta->sc; + struct wihap_info *whi = &sc->wi_hostap_info; + int s; + + s = splnet(); + if (sta->flags & WI_SIFLAGS_ASSOC) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + device_printf(sc->dev, "inactivity disassoc: %6D\n", + sta->addr, ":"); + + /* Disassoc station. */ + wihap_sta_disassoc(sc, sta, IEEE80211_REASON_ASSOC_EXPIRE); + sta->flags &= ~WI_SIFLAGS_ASSOC; + + sta->tmo = timeout(wihap_sta_timeout, sta, + hz * whi->inactivity_time); + + } else if (sta->flags & WI_SIFLAGS_AUTHEN) { + + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + device_printf(sc->dev, "inactivity disassoc: %6D\n", + sta->addr, ":"); + + /* Deauthenticate station. */ + wihap_sta_deauth(sc, sta->addr, IEEE80211_REASON_AUTH_EXPIRE); + sta->flags &= ~WI_SIFLAGS_AUTHEN; + + /* Delete the station if it's not permanent. */ + if (!(sta->flags & WI_SIFLAGS_PERM)) + wihap_sta_delete(sta); + } + splx(s); +} + +/* wihap_sta_delete() * Delete a single station and free up its data structure. */ static void -wihap_sta_delete(struct wihap_info *whi, struct wihap_sta_info *sta) +wihap_sta_delete(struct wihap_sta_info *sta) { + struct wi_softc *sc = sta->sc; + struct wihap_info *whi = &sc->wi_hostap_info; int i = sta->asid - 0xc001; - whi->asid_inuse_mask[i>>4] &= ~(1ul<<(i&0xf)); + + untimeout(wihap_sta_timeout, sta, sta->tmo); + + whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf)); LIST_REMOVE(sta, list); LIST_REMOVE(sta, hash); @@ -343,22 +392,21 @@ wihap_sta_delete(struct wihap_info *whi, struct wihap_sta_info *sta) whi->n_stations--; } -/* - * wihap_sta_alloc() +/* wihap_sta_alloc() * * Create a new station data structure and put it in the list * and hash table. */ static struct wihap_sta_info * -wihap_sta_alloc(struct wihap_info *whi, u_int8_t *addr) +wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr) { - int i; - int hash = sta_hash_func(addr); - struct wihap_sta_info *sta; + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + int i, hash = sta_hash_func(addr); /* Allocate structure. */ MALLOC(sta, struct wihap_sta_info *, sizeof(struct wihap_sta_info), - M_HAP_STA, M_NOWAIT); + M_HAP_STA, M_NOWAIT); if (sta == NULL) return(NULL); @@ -366,15 +414,16 @@ wihap_sta_alloc(struct wihap_info *whi, u_int8_t *addr) /* Allocate an ASID. */ i=hash<<4; - while (whi->asid_inuse_mask[i>>4] & (1ul<<(i&0xf))) - i = (i==(WI_STA_HASH_SIZE<<4)-1) ? 0 : (i+1); - whi->asid_inuse_mask[i>>4] |= (1ul<<(i&0xf)); - sta->asid = 0xc001+i; + while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf))) + i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1); + whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf)); + sta->asid = 0xc001 + i; /* Insert in list and hash list. */ LIST_INSERT_HEAD(&whi->sta_list, sta, list); LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash); + sta->sc = sc; whi->n_stations++; bcopy(addr, &sta->addr, ETHER_ADDR_LEN); sta->inactivity_timer = whi->inactivity_time; @@ -382,8 +431,7 @@ wihap_sta_alloc(struct wihap_info *whi, u_int8_t *addr) return(sta); } -/* - * wihap_sta_find() +/* wihap_sta_find() * * Find station structure given address. */ @@ -398,80 +446,13 @@ wihap_sta_find(struct wihap_info *whi, u_int8_t *addr) if (addr_cmp(addr,sta->addr)) return sta; - return(NULL); -} - -/* - * wihap_timer() - * - * Called every WIHAP_INTERVAL seconds. Look for inactive - * stations and disassociate them. - */ -void -wihap_timer(void *xsc) -{ - int s; - struct wihap_sta_info *sta, *next; - struct wi_softc *sc = (struct wi_softc *) xsc; - struct wihap_info *whi = &sc->wi_hostap_info; - - s = splimp(); - - sta = LIST_FIRST(&whi->sta_list); - while (sta) { - - /* Grab next station now just in case we delete it. */ - next = LIST_NEXT(sta, list); - - if (sta->inactivity_timer >= 0) { - if (--sta->inactivity_timer == 0) { - - if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) - printf("wihap_timer: disassoc due to " - "inactivity: %6D\n", - sta->addr, ":"); - - if (sta->flags & WI_SIFLAGS_ASSOC) { - /* Disassoc station. */ - wihap_sta_disassoc(sc, sta->addr, - IEEE80211_REASON_ASSOC_EXPIRE); - - sta->flags &= ~WI_SIFLAGS_ASSOC; - } - } - else if (sta->inactivity_timer == -1) { - - if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) - printf("wihap_timer: deauth due to " - "inactivity: %6D\n", - sta->addr, ":"); - - if (sta->flags & WI_SIFLAGS_AUTHEN) { - /* Deauthenticate station. */ - wihap_sta_deauth(sc, sta->addr, - IEEE80211_REASON_AUTH_EXPIRE); - - sta->flags &= ~WI_SIFLAGS_AUTHEN; - } - - /* Delete the station if it's not permanent. */ - if (!(sta->flags & WI_SIFLAGS_PERM)) - wihap_sta_delete(whi, sta); - } - } - - sta = next; - } - - splx(s); - - whi->hostap_ch = timeout(wihap_timer, sc, hz * WIHAP_INTERVAL); + return (NULL); } static int -wihap_check_rates(struct wi_softc *sc, struct wihap_sta_info *sta, - u_int8_t rates[], int rates_len) +wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len) { + struct wi_softc *sc = sta->sc; int i; sta->rates = 0; @@ -504,15 +485,14 @@ wihap_check_rates(struct wi_softc *sc, struct wihap_sta_info *sta, } -/* - * wihap_auth_req() +/* wihap_auth_req() * * Handle incoming authentication request. Only handle OPEN * requests. */ static void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len) + caddr_t pkt, int len) { struct wihap_info *whi = &sc->wi_hostap_info; struct wihap_sta_info *sta; @@ -523,24 +503,23 @@ wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, int challenge_len; u_int8_t challenge[128]; - struct wi_80211_hdr *resp_hdr; + struct wi_80211_hdr *resp_hdr; - if (len<6) + if (len < 6) return; /* Break open packet. */ algo = take_hword(&pkt, &len); seq = take_hword(&pkt, &len); status = take_hword(&pkt, &len); - challenge_len=0; - if (len>0 && (challenge_len=take_tlv(&pkt, &len, - IEEE80211_ELEMID_CHALLENGE, - challenge, sizeof(challenge)))<0) + challenge_len = 0; + if (len > 0 && (challenge_len = take_tlv(&pkt, &len, + IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) return; if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_auth_req: from station: %6D\n", - rxfrm->wi_addr2, ":"); + rxfrm->wi_addr2, ":"); switch (algo) { case IEEE80211_AUTH_ALG_OPEN: @@ -548,14 +527,14 @@ wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, status = IEEE80211_STATUS_SEQUENCE; goto fail; } - challenge_len=0; + challenge_len = 0; break; case IEEE80211_AUTH_ALG_SHARED: /* NOT YET */ default: if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_auth_req: algorithm unsupported: %d\n", - algo); + algo); status = IEEE80211_STATUS_ALG; goto fail; } @@ -581,7 +560,7 @@ wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, printf("wihap_auth_req: new station\n"); /* Create new station. */ - sta = wihap_sta_alloc(whi, rxfrm->wi_addr2); + sta = wihap_sta_alloc(sc, rxfrm->wi_addr2); if (sta == NULL) { /* Out of memory! */ status = IEEE80211_STATUS_TOO_MANY_STATIONS; @@ -600,28 +579,25 @@ fail: /* Send response. */ resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; bzero(resp_hdr, sizeof(struct wi_80211_hdr)); - resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH; - pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr); - + resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH); bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN); bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN); + pkt = &sc->wi_txbuf[sizeof(struct wi_80211_hdr)]; put_hword(&pkt, algo); put_hword(&pkt, 2); put_hword(&pkt, status); if (challenge_len>0) put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE, - challenge, challenge_len); + challenge, challenge_len); - wi_mgmt_xmit(sc, sc->wi_txbuf, - 6 + sizeof(struct wi_80211_hdr) + - (challenge_len>0 ? challenge_len+2 : 0) ); + wi_mgmt_xmit(sc, sc->wi_txbuf, 6 + sizeof(struct wi_80211_hdr) + + (challenge_len > 0 ? challenge_len + 2 : 0) ); } -/* - * wihap_assoc_req() +/* wihap_assoc_req() * * Handle incoming association and reassociation requests. */ @@ -631,49 +607,45 @@ wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, { struct wihap_info *whi = &sc->wi_hostap_info; struct wihap_sta_info *sta; - - struct wi_80211_hdr *resp_hdr; - + struct wi_80211_hdr *resp_hdr; u_int16_t capinfo; u_int16_t lstintvl; u_int8_t rates[8]; - int rates_len; - int ssid_len; - char ssid[33]; - - + int ssid_len, rates_len; + struct ieee80211_nwid ssid; u_int16_t status; u_int16_t asid = 0; - if (len<8) + if (len < 8) return; /* Pull out request parameters. */ capinfo = take_hword(&pkt, &len); lstintvl = take_hword(&pkt, &len); - if ((ssid_len=take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID, - ssid, sizeof(ssid)-1))<0) + if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID, + ssid.i_nwid, sizeof(ssid)))<0) return; - ssid[ssid_len] = '\0'; - if ((rates_len=take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES, - rates, sizeof(rates)))<0) + ssid.i_len = ssid_len; + if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES, + rates, sizeof(rates)))<0) return; - if ((rxfrm->wi_frame_ctl & WI_FCTL_STYPE) == WI_STYPE_MGMT_REASREQ) { - /* Reassociation Request-- - * Current AP. (Ignore?) - */ - if (len<6) + + if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) == + htole16(WI_STYPE_MGMT_REASREQ)) { + /* Reassociation Request-- * Current AP. (Ignore?) */ + if (len < 6) return; } if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_assoc_req: from station %6D\n", - rxfrm->wi_addr2, ":"); + rxfrm->wi_addr2, ":"); /* If SSID doesn't match, simply drop. */ - if (strcmp(sc->wi_net_name, ssid) != 0) { + if (strcmp(sc->wi_net_name, ssid.i_nwid) != 0) { if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: bad ssid: '%s'\n", ssid); + printf("wihap_assoc_req: bad ssid: '%s' != '%s'\n", + ssid.i_nwid, sc->wi_net_name); return; } @@ -681,36 +653,43 @@ wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, sta = wihap_sta_find(whi, rxfrm->wi_addr2); if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) { wihap_sta_deauth(sc, rxfrm->wi_addr2, - IEEE80211_REASON_NOT_AUTHED); + IEEE80211_REASON_NOT_AUTHED); return; } + /* Check supported rates against ours. */ + if (wihap_check_rates(sta, rates, rates_len) < 0) { + status = IEEE80211_STATUS_RATES; + goto fail; + } + /* Check capinfo. * Check for ESS, not IBSS. - * Check WEP/PRIVACY flags match. XXX: WEP doesn't work for host AP. + * Check WEP/PRIVACY flags match. * Refuse stations requesting to be put on CF-polling list. */ - if ((capinfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) != - IEEE80211_CAPINFO_ESS || - (sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) || - (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY)) || - (capinfo & (IEEE80211_CAPINFO_CF_POLLABLE| - IEEE80211_CAPINFO_CF_POLLREQ)) == - IEEE80211_CAPINFO_CF_POLLABLE) { - + sta->capinfo = capinfo; + status = IEEE80211_STATUS_CAPINFO; + if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) != + IEEE80211_CAPINFO_ESS) { if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_assoc_req: capinfo mismatch: " - "capinfo=0x%x\n", capinfo); + "client using IBSS mode\n"); + goto fail; - status = IEEE80211_STATUS_CAPINFO; + } + if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) || + (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: capinfo mismatch: client " + "%susing WEP\n", sc->wi_use_wep ? "not " : ""); goto fail; } - sta->capinfo = capinfo; - - - /* Check supported rates against ours. */ - if (wihap_check_rates(sc, sta, rates, rates_len)<0) { - status = IEEE80211_STATUS_RATES; + if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE | + IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) { + if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) + printf("wihap_assoc_req: capinfo mismatch: " + "client requested CF polling\n"); goto fail; } @@ -733,7 +712,7 @@ fail: /* Send response. */ resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf; bzero(resp_hdr, sizeof(struct wi_80211_hdr)); - resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP; + resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP); pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr); bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); @@ -743,14 +722,13 @@ fail: put_hword(&pkt, capinfo); put_hword(&pkt, status); put_hword(&pkt, asid); - rates_len=put_rates(&pkt, sc->wi_supprates); + rates_len = put_rates(&pkt, sc->wi_supprates); wi_mgmt_xmit(sc, sc->wi_txbuf, - 8+rates_len+sizeof(struct wi_80211_hdr)); + 8 + rates_len + sizeof(struct wi_80211_hdr)); } -/* - * wihap_deauth_req() +/* wihap_deauth_req() * * Handle deauthentication requests. Delete the station. */ @@ -760,7 +738,7 @@ wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, { struct wihap_info *whi = &sc->wi_hostap_info; struct wihap_sta_info *sta; - u_int16_t reason; + u_int16_t reason; if (len<2) return; @@ -771,14 +749,13 @@ wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, if (sta == NULL) { if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_deauth_req: unknown station: 6D\n", - rxfrm->wi_addr2, ":"); + rxfrm->wi_addr2, ":"); } else - wihap_sta_delete(whi, sta); + wihap_sta_delete(sta); } -/* - * wihap_disassoc_req() +/* wihap_disassoc_req() * * Handle disassociation requests. Just reset the assoc flag. * We'll free up the station resources when we get a deauth @@ -786,13 +763,13 @@ wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, */ static void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len) + caddr_t pkt, int len) { struct wihap_info *whi = &sc->wi_hostap_info; struct wihap_sta_info *sta; - u_int16_t reason; + u_int16_t reason; - if (len<2) + if (len < 2) return; reason = take_hword(&pkt, &len); @@ -801,31 +778,32 @@ wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, if (sta == NULL) { if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) printf("wihap_disassoc_req: unknown station: 6D\n", - rxfrm->wi_addr2, ":"); + rxfrm->wi_addr2, ":"); } else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) { - /* If station is not authenticated, send deauthentication + /* + * If station is not authenticated, send deauthentication * frame. */ wihap_sta_deauth(sc, rxfrm->wi_addr2, - IEEE80211_REASON_NOT_AUTHED); + IEEE80211_REASON_NOT_AUTHED); return; } else sta->flags &= ~WI_SIFLAGS_ASSOC; } -/* - * wihap_debug_frame_type() +/* wihap_debug_frame_type() * * Print out frame type. Used in early debugging. */ -static void +static __inline void wihap_debug_frame_type(struct wi_frame *rxfrm) { - printf("wihap_mgmt_input: len=%d ", rxfrm->wi_dat_len); + printf("wihap_mgmt_input: len=%d ", le16toh(rxfrm->wi_dat_len)); - if ((le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE) == WI_FTYPE_MGMT) { + if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) == + htole16(WI_FTYPE_MGMT)) { printf("MGMT: "); @@ -865,19 +843,18 @@ wihap_debug_frame_type(struct wi_frame *rxfrm) break; default: printf("unknown (stype=0x%x)\n", - le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE); + le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE); } } else { printf("ftype=0x%x (ctl=0x%x)\n", - le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE, - le16toh(rxfrm->wi_frame_ctl)); + le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE, + le16toh(rxfrm->wi_frame_ctl)); } } -/* - * wihap_mgmt_input: +/* wihap_mgmt_input: * * Called for each management frame received in host ap mode. * wihap_mgmt_input() is expected to free the mbuf. @@ -885,8 +862,8 @@ wihap_debug_frame_type(struct wi_frame *rxfrm) void wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) { - caddr_t pkt; - int len; + caddr_t pkt; + int s, len; if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) wihap_debug_frame_type(rxfrm); @@ -894,8 +871,11 @@ wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW; len = m->m_len - WI_802_11_OFFSET_RAW; - if ((rxfrm->wi_frame_ctl & WI_FCTL_FTYPE) == WI_FTYPE_MGMT) { + if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) == + htole16(WI_FTYPE_MGMT)) { + /* any of the following will mess w/ the station list */ + s = splsoftclock(); switch (le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { case WI_STYPE_MGMT_ASREQ: wihap_assoc_req(sc, rxfrm, pkt, len); @@ -925,14 +905,13 @@ wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) wihap_deauth_req(sc, rxfrm, pkt, len); break; } - + splx(s); } m_freem(m); } -/* - * wihap_sta_is_assoc() +/* wihap_sta_is_assoc() * * Determine if a station is assoc'ed. Update its activity * counter as a side-effect. @@ -943,17 +922,18 @@ wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]) struct wihap_sta_info *sta; sta = wihap_sta_find(whi, addr); - if (sta!=NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { + if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { /* Keep it active. */ sta->inactivity_timer = whi->inactivity_time; + sta->tmo = timeout(wihap_sta_timeout, sta, + hz * whi->inactivity_time); return(1); } else return(0); } -/* - * wihap_check_tx() +/* wihap_check_tx() * * Determine if a station is assoc'ed, get its tx rate, and update * its activity. @@ -963,18 +943,24 @@ wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate) { struct wihap_sta_info *sta; static u_int8_t txratetable[] = { 10, 20, 55, 110 }; + int s; + s = splclock(); if (addr[0] & 0x01) { *txrate = 0; /* XXX: multicast rate? */ return(1); } sta = wihap_sta_find(whi, addr); - if (sta!=NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { + if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { /* Keep it active. */ - sta->inactivity_timer = whi->inactivity_time; + sta->tmo = timeout(wihap_sta_timeout, sta, + hz * whi->inactivity_time); *txrate = txratetable[ sta->tx_curr_rate ]; + splx(s); return(1); } + splx(s); + return(0); } @@ -993,14 +979,15 @@ wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) { struct ifnet *ifp = &sc->arpcom.ac_if; struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - int mcast; + struct wihap_sta_info *sta; + int mcast, s; /* TODS flag must be set. */ - if (!(le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_TODS)) { + if (!(rxfrm->wi_frame_ctl & htole16(WI_FCTL_TODS))) { if (ifp->if_flags & IFF_DEBUG) printf("wihap_data_input: no TODS src=%6D\n", - rxfrm->wi_addr2, ":"); + rxfrm->wi_addr2, ":"); + m_freem(m); return(1); } @@ -1009,9 +996,12 @@ wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) if (ifp->if_flags & IFF_DEBUG) printf("wihap_data_input: incorrect bss: %6D\n", rxfrm->wi_addr1, ":"); - return(1); + m_freem(m); + return (1); } + s = splsoftclock(); + /* Find source station. */ sta = wihap_sta_find(whi, rxfrm->wi_addr2); @@ -1019,12 +1009,17 @@ wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) { if (ifp->if_flags & IFF_DEBUG) printf("wihap_data_input: dropping unassoc src %6D\n", - rxfrm->wi_addr2, ":"); + rxfrm->wi_addr2, ":"); + splx(s); + m_freem(m); return(1); } - sta->inactivity_timer = whi->inactivity_time; - sta->sig_info = rxfrm->wi_q_info; + sta->tmo = timeout(wihap_sta_timeout, sta, + hz * whi->inactivity_time); + sta->sig_info = le16toh(rxfrm->wi_q_info); + + splx(s); /* Repeat this packet to BSS? */ mcast = (rxfrm->wi_addr3[0] & 0x01) != 0; @@ -1045,26 +1040,23 @@ wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) return (!mcast); } - return (0); + return(0); } -/* - * wihap_ioctl() +/* wihap_ioctl() * * Handle Host AP specific ioctls. Called from wi_ioctl(). */ int wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) { - int error = 0; struct ifreq *ifr = (struct ifreq *) data; - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - struct hostap_getall reqall; - struct hostap_sta reqsta; - struct hostap_sta stabuf; - int n; - int flag; + struct wihap_info *whi = &sc->wi_hostap_info; + struct wihap_sta_info *sta; + struct hostap_getall reqall; + struct hostap_sta reqsta; + struct hostap_sta stabuf; + int s, error = 0, n, flag; if (!(sc->arpcom.ac_if.if_flags & IFF_RUNNING)) return ENODEV; @@ -1075,26 +1067,29 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) break; if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) break; + s = splimp(); sta = wihap_sta_find(whi, reqsta.addr); if (sta == NULL) error = ENOENT; else { /* Disassociate station. */ if (sta->flags & WI_SIFLAGS_ASSOC) - wihap_sta_disassoc(sc, sta->addr, - IEEE80211_REASON_ASSOC_LEAVE); + wihap_sta_disassoc(sc, sta, + IEEE80211_REASON_ASSOC_LEAVE); /* Deauth station. */ if (sta->flags & WI_SIFLAGS_AUTHEN) wihap_sta_deauth(sc, sta->addr, - IEEE80211_REASON_AUTH_LEAVE); + IEEE80211_REASON_AUTH_LEAVE); - wihap_sta_delete(whi, sta); + wihap_sta_delete(sta); } + splx(s); break; case SIOCHOSTAP_GET: if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) break; + s = splimp(); sta = wihap_sta_find(whi, reqsta.addr); if (sta == NULL) error = ENOENT; @@ -1106,8 +1101,9 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) reqsta.rates = sta->rates; error = copyout(&reqsta, ifr->ifr_data, - sizeof(reqsta)); + sizeof(reqsta)); } + splx(s); break; case SIOCHOSTAP_ADD: @@ -1115,18 +1111,23 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) break; if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) break; + s = splimp(); sta = wihap_sta_find(whi, reqsta.addr); if (sta != NULL) { error = EEXIST; + splx(s); break; } if (whi->n_stations >= WIHAP_MAX_STATIONS) { error = ENOSPC; + splx(s); break; } - sta = wihap_sta_alloc(whi, reqsta.addr); + sta = wihap_sta_alloc(sc, reqsta.addr); sta->flags = reqsta.flags; - sta->inactivity_timer = whi->inactivity_time; + sta->tmo = timeout(wihap_sta_timeout, sta, + hz * whi->inactivity_time); + splx(s); break; case SIOCHOSTAP_SFLAGS: @@ -1135,9 +1136,8 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) if ((error = copyin(ifr->ifr_data, &flag, sizeof(int)))) break; - whi->apflags = - (whi->apflags & WIHAPFL_CANTCHANGE) | - (flag & ~WIHAPFL_CANTCHANGE); + whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) | + (flag & ~WIHAPFL_CANTCHANGE); break; case SIOCHOSTAP_GFLAGS: @@ -1151,6 +1151,7 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) reqall.nstations = whi->n_stations; n = 0; + s = splimp(); sta = LIST_FIRST(&whi->sta_list); while (sta && reqall.size >= n+sizeof(struct hostap_sta)) { @@ -1162,17 +1163,18 @@ wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) stabuf.rates = sta->rates; error = copyout(&stabuf, (caddr_t) reqall.addr + n, - sizeof(struct hostap_sta)); + sizeof(struct hostap_sta)); if (error) break; sta = LIST_NEXT(sta, list); n += sizeof(struct hostap_sta); } + splx(s); if (!error) error = copyout(&reqall, ifr->ifr_data, - sizeof(reqall)); + sizeof(reqall)); break; default: printf("wihap_ioctl: i shouldn't get other ioctls!\n"); diff --git a/sys/dev/wi/wi_hostap.h b/sys/dev/wi/wi_hostap.h index 493b5ad..4338499 100644 --- a/sys/dev/wi/wi_hostap.h +++ b/sys/dev/wi/wi_hostap.h @@ -77,6 +77,7 @@ struct wihap_sta_info { LIST_ENTRY(wihap_sta_info) list; LIST_ENTRY(wihap_sta_info) hash; + struct wi_softc *sc; u_int8_t addr[6]; u_short flags; int inactivity_timer; @@ -87,6 +88,7 @@ struct wihap_sta_info { u_int8_t rates; u_int8_t tx_curr_rate; u_int8_t tx_max_rate; + struct callout_handle tmo; }; #define WI_SIFLAGS_ASSOC HOSTAP_FLAGS_ASSOC @@ -112,7 +114,6 @@ struct wihap_info { u_int16_t asid_inuse_mask[WI_STA_HASH_SIZE]; int inactivity_time; - struct callout_handle hostap_ch; }; #define WIHAP_INTERVAL 5 @@ -121,16 +122,13 @@ struct wihap_info { struct wi_softc; struct wi_frame; -void wihap_timer __P((void *)); -void wihap_mgmt_input __P((struct wi_softc *, struct wi_frame *, - struct mbuf *)); -int wihap_data_input __P((struct wi_softc *, struct wi_frame *, - struct mbuf *)); -int wihap_check_tx __P((struct wihap_info *, u_int8_t [], - u_int8_t *)); -void wihap_init __P((struct wi_softc *)); -void wihap_shutdown __P((struct wi_softc *)); -int wihap_ioctl __P((struct wi_softc *, u_long, caddr_t)); +void wihap_timer(void *); +void wihap_mgmt_input(struct wi_softc *, struct wi_frame *, struct mbuf *); +int wihap_data_input(struct wi_softc *, struct wi_frame *, struct mbuf *); +int wihap_check_tx(struct wihap_info *, u_int8_t [], u_int8_t *); +void wihap_init(struct wi_softc *); +void wihap_shutdown(struct wi_softc *); +int wihap_ioctl(struct wi_softc *, u_long, caddr_t); #endif /* _KERNEL */ #endif /* __WI_HOSTAP_H__ */ |