3 * Thomas Skibo <skibo@pacbell.net>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Thomas Skibo.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $FreeBSD: src/sys/dev/wi/wi_hostap.c,v 1.7.2.4 2002/08/02 07:11:34 imp Exp $
33 * $DragonFly: src/sys/dev/netif/owi/Attic/owi_hostap.c,v 1.3 2005/02/11 22:25:56 joerg Exp $
36 /* This is experimental Host AP software for Prism 2 802.11b interfaces.
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>.
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #if defined(__FreeBSD__) && __FreeBSD_version >= 500033
45 #include <sys/endian.h>
47 #include <sys/sockio.h>
49 #include <sys/malloc.h>
50 #include <sys/kernel.h>
52 #include <sys/ucred.h>
53 #include <sys/socket.h>
54 #include <sys/module.h>
55 #include <sys/queue.h>
57 #include <sys/syslog.h>
58 #include <sys/sysctl.h>
60 #include <machine/bus.h>
61 #include <machine/resource.h>
62 #include <machine/clock.h>
63 #include <machine/md_var.h>
64 #include <machine/bus_pio.h>
68 #include <net/ifq_var.h>
69 #include <net/if_arp.h>
70 #include <net/ethernet.h>
71 #include <net/if_dl.h>
72 #include <net/if_media.h>
73 #include <net/if_types.h>
74 #include <netproto/802_11/ieee80211.h>
75 #include <netproto/802_11/ieee80211_ioctl.h>
76 #include <netproto/802_11/if_wavelan_ieee.h>
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/in_var.h>
81 #include <netinet/ip.h>
82 #include <netinet/if_ether.h>
84 #include "wi_hostap.h"
88 static MALLOC_DEFINE(M_HAP_STA, "hostap_sta", "if_wi host AP mode station entry");
90 static void wihap_sta_timeout(void *v);
91 static struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc,
93 static void wihap_sta_delete(struct wihap_sta_info *sta);
94 static struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi,
96 static int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]);
97 static void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
98 caddr_t pkt, int len);
99 static void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[],
101 static void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
102 caddr_t pkt, int len);
103 static void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
104 caddr_t pkt, int len);
105 static void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[],
107 static void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
108 caddr_t pkt, int len);
111 * Spl use in this driver.
113 * splnet is used everywhere here to block timeouts when we need to do
120 * Used for parsing management frames. The pkt pointer and length
121 * variables are updated after the value is removed.
123 static __inline u_int16_t
124 take_hword(caddr_t *ppkt, int *plen)
126 u_int16_t s = le16toh(* (u_int16_t *) *ppkt);
127 *ppkt += sizeof(u_int16_t);
128 *plen -= sizeof(u_int16_t);
134 * Parse out TLV element from a packet, check for underflow of packet
135 * or overflow of buffer, update pkt/len.
138 take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen)
145 id = ((u_int8_t *)*ppkt)[0];
146 len = ((u_int8_t *)*ppkt)[1];
148 if (id != id_expect || *plen < len+2 || maxlen < len)
151 bcopy(*ppkt + 2, dst, len);
159 * Put half-word element into management frames.
162 put_hword(caddr_t *ppkt, u_int16_t s)
164 * (u_int16_t *) *ppkt = htole16(s);
165 *ppkt += sizeof(u_int16_t);
169 * Put TLV elements into management frames.
172 put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len)
176 bcopy(src, (*ppkt) + 2, len);
181 put_rates(caddr_t *ppkt, u_int16_t rates)
186 if (rates & WI_SUPPRATES_1M)
187 ratebuf[len++] = 0x82;
188 if (rates & WI_SUPPRATES_2M)
189 ratebuf[len++] = 0x84;
190 if (rates & WI_SUPPRATES_5M)
191 ratebuf[len++] = 0x8b;
192 if (rates & WI_SUPPRATES_11M)
193 ratebuf[len++] = 0x96;
195 put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len);
201 * Initialize host AP data structures. Called even if port type is
205 owihap_init(struct wi_softc *sc)
208 struct wihap_info *whi = &sc->wi_hostap_info;
210 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
211 printf("wihap_init: sc=0x%x whi=0x%x\n", (int)sc, (int)whi);
213 bzero(whi, sizeof(struct wihap_info));
215 if (sc->wi_ptype != WI_PORTTYPE_AP)
218 whi->apflags = WIHAPFL_ACTIVE;
220 LIST_INIT(&whi->sta_list);
221 for (i = 0; i < WI_STA_HASH_SIZE; i++)
222 LIST_INIT(&whi->sta_hash[i]);
224 whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME;
227 /* wihap_sta_disassoc()
229 * Send a disassociation frame to a specified station.
232 wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
234 struct wi_80211_hdr *resp_hdr;
237 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
238 printf("Sending disassoc to sta %6D\n", sta_addr, ":");
240 /* Send disassoc packet. */
241 resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
242 bzero(resp_hdr, sizeof(struct wi_80211_hdr));
243 resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS;
244 pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr);
246 bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
247 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
248 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN);
250 put_hword(&pkt, reason);
252 owi_mgmt_xmit(sc, sc->wi_txbuf, 2 + sizeof(struct wi_80211_hdr));
255 /* wihap_sta_deauth()
257 * Send a deauthentication message to a specified station.
260 wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
262 struct wi_80211_hdr *resp_hdr;
265 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
266 printf("Sending deauth to sta %6D\n", sta_addr, ":");
268 /* Send deauth packet. */
269 resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
270 bzero(resp_hdr, sizeof(struct wi_80211_hdr));
271 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH);
272 pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr);
274 bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
275 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
276 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN);
278 put_hword(&pkt, reason);
280 owi_mgmt_xmit(sc, sc->wi_txbuf, 2 + sizeof(struct wi_80211_hdr));
285 * Disassociate all stations and free up data structures.
288 owihap_shutdown(struct wi_softc *sc)
290 struct wihap_info *whi = &sc->wi_hostap_info;
291 struct wihap_sta_info *sta, *next;
294 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
295 printf("wihap_shutdown: sc=0x%x whi=0x%x\n",
298 if (!(whi->apflags & WIHAPFL_ACTIVE))
301 /* XXX: I read somewhere you can deauth all the stations with
302 * a single broadcast. Maybe try that someday.
306 sta = LIST_FIRST(&whi->sta_list);
308 callout_stop(&sta->tmo);
310 /* Disassociate station. */
311 if (sta->flags & WI_SIFLAGS_ASSOC)
312 wihap_sta_disassoc(sc, sta->addr,
313 IEEE80211_REASON_ASSOC_LEAVE);
314 /* Deauth station. */
315 if (sta->flags & WI_SIFLAGS_AUTHEN)
316 wihap_sta_deauth(sc, sta->addr,
317 IEEE80211_REASON_AUTH_LEAVE);
320 /* Delete the structure. */
321 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
322 printf("wihap_shutdown: FREE(sta=0x%x)\n", (int)sta);
323 next = LIST_NEXT(sta, list);
324 FREE(sta, M_HAP_STA);
333 * Hash function for finding stations from ethernet address.
336 sta_hash_func(u_int8_t addr[])
338 return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE);
341 /* addr_cmp(): Maybe this is a faster way to compare addresses? */
343 addr_cmp(u_int8_t a[], u_int8_t b[])
345 return (*(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4) &&
346 *(u_int32_t *)(a ) == *(u_int32_t *)(b));
350 wihap_sta_timeout(void *v)
352 struct wihap_sta_info *sta = v;
353 struct wi_softc *sc = sta->sc;
354 struct wihap_info *whi = &sc->wi_hostap_info;
358 if (sta->flags & WI_SIFLAGS_ASSOC) {
359 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
360 device_printf(sc->dev, "inactivity disassoc: %6D\n",
363 /* Disassoc station. */
364 wihap_sta_disassoc(sc, sta->addr,
365 IEEE80211_REASON_ASSOC_EXPIRE);
366 sta->flags &= ~WI_SIFLAGS_ASSOC;
368 callout_reset(&sta->tmo, hz * whi->inactivity_time,
369 wihap_sta_timeout, sta);
371 } else if (sta->flags & WI_SIFLAGS_AUTHEN) {
373 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
374 device_printf(sc->dev, "inactivity disassoc: %6D\n",
377 /* Deauthenticate station. */
378 wihap_sta_deauth(sc, sta->addr, IEEE80211_REASON_AUTH_EXPIRE);
379 sta->flags &= ~WI_SIFLAGS_AUTHEN;
381 /* Delete the station if it's not permanent. */
382 if (!(sta->flags & WI_SIFLAGS_PERM))
383 wihap_sta_delete(sta);
388 /* wihap_sta_delete()
389 * Delete a single station and free up its data structure.
392 wihap_sta_delete(struct wihap_sta_info *sta)
394 struct wi_softc *sc = sta->sc;
395 struct wihap_info *whi = &sc->wi_hostap_info;
396 int i = sta->asid - 0xc001;
398 callout_stop(&sta->tmo);
400 whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf));
402 LIST_REMOVE(sta, list);
403 LIST_REMOVE(sta, hash);
405 FREE(sta->challenge, M_TEMP);
406 FREE(sta, M_HAP_STA);
412 * Create a new station data structure and put it in the list
415 static struct wihap_sta_info *
416 wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr)
418 struct wihap_info *whi = &sc->wi_hostap_info;
419 struct wihap_sta_info *sta;
420 int i, hash = sta_hash_func(addr);
422 /* Allocate structure. */
423 MALLOC(sta, struct wihap_sta_info *, sizeof(struct wihap_sta_info),
424 M_HAP_STA, M_INTWAIT);
428 bzero(sta, sizeof(struct wihap_sta_info));
429 callout_init(&sta->tmo);
431 /* Allocate an ASID. */
433 while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
434 i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
435 whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
436 sta->asid = 0xc001 + i;
438 /* Insert in list and hash list. */
439 LIST_INSERT_HEAD(&whi->sta_list, sta, list);
440 LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash);
444 bcopy(addr, &sta->addr, ETHER_ADDR_LEN);
451 * Find station structure given address.
453 static struct wihap_sta_info *
454 wihap_sta_find(struct wihap_info *whi, u_int8_t *addr)
457 struct wihap_sta_info *sta;
459 i = sta_hash_func(addr);
460 LIST_FOREACH(sta, &whi->sta_hash[i], hash)
461 if (addr_cmp(addr,sta->addr))
468 wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
470 struct wi_softc *sc = sta->sc;
474 sta->tx_max_rate = 0;
475 for (i=0; i<rates_len; i++)
476 switch (rates[i] & 0x7f) {
478 sta->rates |= WI_SUPPRATES_1M;
481 sta->rates |= WI_SUPPRATES_2M;
482 if (sta->tx_max_rate<1)
483 sta->tx_max_rate = 1;
486 sta->rates |= WI_SUPPRATES_5M;
487 if (sta->tx_max_rate<2)
488 sta->tx_max_rate = 2;
491 sta->rates |= WI_SUPPRATES_11M;
492 sta->tx_max_rate = 3;
496 sta->rates &= sc->wi_supprates;
497 sta->tx_curr_rate = sta->tx_max_rate;
499 return (sta->rates == 0 ? -1 : 0);
505 * Handle incoming authentication request. Only handle OPEN
509 wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
510 caddr_t pkt, int len)
512 struct wihap_info *whi = &sc->wi_hostap_info;
513 struct wihap_sta_info *sta;
518 int i, challenge_len;
519 u_int32_t challenge[32];
521 struct wi_80211_hdr *resp_hdr;
526 /* Break open packet. */
527 algo = take_hword(&pkt, &len);
528 seq = take_hword(&pkt, &len);
529 status = take_hword(&pkt, &len);
531 if (len > 0 && (challenge_len = take_tlv(&pkt, &len,
532 IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0)
535 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
536 printf("wihap_auth_req: station %6D algo=0x%x seq=0x%x\n",
537 rxfrm->wi_addr2, ":", algo, seq);
539 /* Find or create station info. */
540 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
543 /* Are we allowing new stations?
545 if (whi->apflags & WIHAPFL_MAC_FILT) {
546 status = IEEE80211_STATUS_OTHER; /* XXX */
550 /* Check for too many stations.
552 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
553 status = IEEE80211_STATUS_TOO_MANY_STATIONS;
557 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
558 printf("wihap_auth_req: new station\n");
560 /* Create new station. */
561 sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
564 status = IEEE80211_STATUS_TOO_MANY_STATIONS;
569 /* Note: it's okay to leave the station info structure around
570 * if the authen fails. It'll be timed out eventually.
573 case IEEE80211_AUTH_ALG_OPEN:
574 if (sc->wi_authmode != IEEE80211_AUTH_OPEN) {
576 status = IEEE80211_STATUS_ALG;
581 status = IEEE80211_STATUS_SEQUENCE;
586 sta->flags |= WI_SIFLAGS_AUTHEN;
588 case IEEE80211_AUTH_ALG_SHARED:
589 if (sc->wi_authmode != IEEE80211_AUTH_SHARED) {
591 status = IEEE80211_STATUS_ALG;
596 /* Create a challenge frame. */
597 if (!sta->challenge) {
598 MALLOC(sta->challenge, u_int32_t *, 128,
603 for (i = 0; i < 32; i++)
604 challenge[i] = sta->challenge[i] =
610 if (challenge_len != 128 || !sta->challenge ||
611 !(le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) {
612 status = IEEE80211_STATUS_CHALLENGE;
618 /* Check the challenge text. (Was decrypted by
622 if (sta->challenge[i] != challenge[i]) {
623 status = IEEE80211_STATUS_CHALLENGE;
624 FREE(sta->challenge, M_TEMP);
625 sta->challenge = NULL;
629 sta->flags |= WI_SIFLAGS_AUTHEN;
630 FREE(sta->challenge, M_TEMP);
631 sta->challenge = NULL;
635 status = IEEE80211_STATUS_SEQUENCE;
640 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
641 printf("wihap_auth_req: algorithm unsupported: 0x%x\n",
643 status = IEEE80211_STATUS_ALG;
645 } /* switch (algo) */
647 status = IEEE80211_STATUS_SUCCESS;
650 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
651 printf("wihap_auth_req: returns status=0x%x\n", status);
654 resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
655 bzero(resp_hdr, sizeof(struct wi_80211_hdr));
656 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH);
657 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
658 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
659 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN);
660 pkt = &sc->wi_txbuf[sizeof(struct wi_80211_hdr)];
661 put_hword(&pkt, algo);
662 put_hword(&pkt, seq);
663 put_hword(&pkt, status);
664 if (challenge_len > 0)
665 put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE,
666 challenge, challenge_len);
667 owi_mgmt_xmit(sc, sc->wi_txbuf, (char *) pkt - (char *) sc->wi_txbuf);
672 * Handle incoming association and reassociation requests.
675 wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
676 caddr_t pkt, int len)
678 struct wihap_info *whi = &sc->wi_hostap_info;
679 struct wihap_sta_info *sta;
680 struct wi_80211_hdr *resp_hdr;
684 int ssid_len, rates_len;
692 /* Pull out request parameters. */
693 capinfo = take_hword(&pkt, &len);
694 lstintvl = take_hword(&pkt, &len);
696 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
697 htole16(WI_STYPE_MGMT_REASREQ)) {
700 /* Eat the MAC address of the current AP */
701 take_hword(&pkt, &len);
702 take_hword(&pkt, &len);
703 take_hword(&pkt, &len);
706 if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
707 ssid, sizeof(ssid) - 1))<0)
709 ssid[ssid_len] = '\0';
710 if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES,
711 rates, sizeof(rates)))<0)
714 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
715 printf("wihap_assoc_req: from station %6D\n",
716 rxfrm->wi_addr2, ":");
718 /* If SSID doesn't match, simply drop. */
719 if (strcmp(sc->wi_net_name, ssid) != 0) {
720 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
721 printf("wihap_assoc_req: bad ssid: '%s' != '%s'\n",
722 ssid, sc->wi_net_name);
726 /* Is this station authenticated yet? */
727 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
728 if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) {
729 wihap_sta_deauth(sc, rxfrm->wi_addr2,
730 IEEE80211_REASON_NOT_AUTHED);
734 /* Check supported rates against ours. */
735 if (wihap_check_rates(sta, rates, rates_len) < 0) {
736 status = IEEE80211_STATUS_RATES;
741 * Check for ESS, not IBSS.
742 * Check WEP/PRIVACY flags match.
743 * Refuse stations requesting to be put on CF-polling list.
745 sta->capinfo = capinfo;
746 status = IEEE80211_STATUS_CAPINFO;
747 if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) !=
748 IEEE80211_CAPINFO_ESS) {
749 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
750 printf("wihap_assoc_req: capinfo mismatch: "
751 "client using IBSS mode\n");
755 if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) ||
756 (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) {
757 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
758 printf("wihap_assoc_req: capinfo mismatch: client "
759 "%susing WEP\n", sc->wi_use_wep ? "not " : "");
762 if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE |
763 IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) {
764 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
765 printf("wihap_assoc_req: capinfo mismatch: "
766 "client requested CF polling\n");
770 /* Use ASID is allocated by whi_sta_alloc(). */
773 if (sta->flags & WI_SIFLAGS_ASSOC) {
774 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
775 printf("wihap_assoc_req: already assoc'ed?\n");
778 sta->flags |= WI_SIFLAGS_ASSOC;
779 sta->inactivity_timer = whi->inactivity_time;
780 status = IEEE80211_STATUS_SUCCESS;
783 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
784 printf("wihap_assoc_req: returns status=0x%x\n", status);
787 resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
788 bzero(resp_hdr, sizeof(struct wi_80211_hdr));
789 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
790 pkt = sc->wi_txbuf + sizeof(struct wi_80211_hdr);
792 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
793 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
794 bcopy(sc->arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN);
796 put_hword(&pkt, capinfo);
797 put_hword(&pkt, status);
798 put_hword(&pkt, asid);
799 rates_len = put_rates(&pkt, sc->wi_supprates);
801 owi_mgmt_xmit(sc, sc->wi_txbuf,
802 8 + rates_len + sizeof(struct wi_80211_hdr));
805 /* wihap_deauth_req()
807 * Handle deauthentication requests. Delete the station.
810 wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
811 caddr_t pkt, int len)
813 struct wihap_info *whi = &sc->wi_hostap_info;
814 struct wihap_sta_info *sta;
820 reason = take_hword(&pkt, &len);
822 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
824 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
825 printf("wihap_deauth_req: unknown station: %6D\n",
826 rxfrm->wi_addr2, ":");
829 wihap_sta_delete(sta);
832 /* wihap_disassoc_req()
834 * Handle disassociation requests. Just reset the assoc flag.
835 * We'll free up the station resources when we get a deauth
836 * request or when it times out.
839 wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
840 caddr_t pkt, int len)
842 struct wihap_info *whi = &sc->wi_hostap_info;
843 struct wihap_sta_info *sta;
849 reason = take_hword(&pkt, &len);
851 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
853 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
854 printf("wihap_disassoc_req: unknown station: %6D\n",
855 rxfrm->wi_addr2, ":");
857 else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) {
859 * If station is not authenticated, send deauthentication
862 wihap_sta_deauth(sc, rxfrm->wi_addr2,
863 IEEE80211_REASON_NOT_AUTHED);
867 sta->flags &= ~WI_SIFLAGS_ASSOC;
870 /* wihap_debug_frame_type()
872 * Print out frame type. Used in early debugging.
875 wihap_debug_frame_type(struct wi_frame *rxfrm)
877 printf("wihap_mgmt_input: len=%d ", le16toh(rxfrm->wi_dat_len));
879 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
880 htole16(WI_FTYPE_MGMT)) {
884 switch (le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
885 case WI_STYPE_MGMT_ASREQ:
886 printf("assoc req: \n");
888 case WI_STYPE_MGMT_ASRESP:
889 printf("assoc resp: \n");
891 case WI_STYPE_MGMT_REASREQ:
892 printf("reassoc req: \n");
894 case WI_STYPE_MGMT_REASRESP:
895 printf("reassoc resp: \n");
897 case WI_STYPE_MGMT_PROBEREQ:
898 printf("probe req: \n");
900 case WI_STYPE_MGMT_PROBERESP:
901 printf("probe resp: \n");
903 case WI_STYPE_MGMT_BEACON:
904 printf("beacon: \n");
906 case WI_STYPE_MGMT_ATIM:
907 printf("ann traf ind \n");
909 case WI_STYPE_MGMT_DISAS:
910 printf("disassociation: \n");
912 case WI_STYPE_MGMT_AUTH:
915 case WI_STYPE_MGMT_DEAUTH:
916 printf("deauth: \n");
919 printf("unknown (stype=0x%x)\n",
920 le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE);
925 printf("ftype=0x%x (ctl=0x%x)\n",
926 le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE,
927 le16toh(rxfrm->wi_frame_ctl));
933 * Called for each management frame received in host ap mode.
934 * wihap_mgmt_input() is expected to free the mbuf.
937 owihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
942 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
943 wihap_debug_frame_type(rxfrm);
945 pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW;
946 len = m->m_len - WI_802_11_OFFSET_RAW;
948 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
949 htole16(WI_FTYPE_MGMT)) {
951 /* any of the following will mess w/ the station list */
953 switch (le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
954 case WI_STYPE_MGMT_ASREQ:
955 wihap_assoc_req(sc, rxfrm, pkt, len);
957 case WI_STYPE_MGMT_ASRESP:
959 case WI_STYPE_MGMT_REASREQ:
960 wihap_assoc_req(sc, rxfrm, pkt, len);
962 case WI_STYPE_MGMT_REASRESP:
964 case WI_STYPE_MGMT_PROBEREQ:
966 case WI_STYPE_MGMT_PROBERESP:
968 case WI_STYPE_MGMT_BEACON:
970 case WI_STYPE_MGMT_ATIM:
972 case WI_STYPE_MGMT_DISAS:
973 wihap_disassoc_req(sc, rxfrm, pkt, len);
975 case WI_STYPE_MGMT_AUTH:
976 wihap_auth_req(sc, rxfrm, pkt, len);
978 case WI_STYPE_MGMT_DEAUTH:
979 wihap_deauth_req(sc, rxfrm, pkt, len);
988 /* wihap_sta_is_assoc()
990 * Determine if a station is assoc'ed. Update its activity
991 * counter as a side-effect.
994 wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[])
996 struct wihap_sta_info *sta;
1001 sta = wihap_sta_find(whi, addr);
1002 if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
1003 /* Keep it active. */
1004 callout_reset(&sta->tmo, hz * whi->inactivity_time,
1005 wihap_sta_timeout, sta);
1014 * Determine if a station is assoc'ed, get its tx rate, and update
1018 owihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1020 struct wihap_sta_info *sta;
1021 static u_int8_t txratetable[] = { 10, 20, 55, 110 };
1024 if (addr[0] & 0x01) {
1025 *txrate = 0; /* XXX: multicast rate? */
1029 sta = wihap_sta_find(whi, addr);
1030 if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
1031 /* Keep it active. */
1032 callout_reset(&sta->tmo, hz * whi->inactivity_time,
1033 wihap_sta_timeout, sta);
1034 *txrate = txratetable[ sta->tx_curr_rate ];
1044 * wihap_data_input()
1046 * Handle all data input on interface when in Host AP mode.
1047 * Some packets are destined for this machine, others are
1048 * repeated to other stations.
1050 * If wihap_data_input() returns a non-zero, it has processed
1051 * the packet and will free the mbuf.
1054 owihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1056 struct ifnet *ifp = &sc->arpcom.ac_if;
1057 struct wihap_info *whi = &sc->wi_hostap_info;
1058 struct wihap_sta_info *sta;
1061 /* TODS flag must be set. */
1062 if (!(rxfrm->wi_frame_ctl & htole16(WI_FCTL_TODS))) {
1063 if (ifp->if_flags & IFF_DEBUG)
1064 printf("wihap_data_input: no TODS src=%6D\n",
1065 rxfrm->wi_addr2, ":");
1070 /* Check BSSID. (Is this necessary?) */
1071 if (!addr_cmp(rxfrm->wi_addr1, sc->arpcom.ac_enaddr)) {
1072 if (ifp->if_flags & IFF_DEBUG)
1073 printf("wihap_data_input: incorrect bss: %6D\n",
1074 rxfrm->wi_addr1, ":");
1081 /* Find source station. */
1082 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
1084 /* Source station must be associated. */
1085 if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) {
1086 if (ifp->if_flags & IFF_DEBUG)
1087 printf("wihap_data_input: dropping unassoc src %6D\n",
1088 rxfrm->wi_addr2, ":");
1089 wihap_sta_disassoc(sc, rxfrm->wi_addr2,
1090 IEEE80211_REASON_ASSOC_LEAVE);
1096 callout_reset(&sta->tmo, hz * whi->inactivity_time,
1097 wihap_sta_timeout, sta);
1098 sta->sig_info = le16toh(rxfrm->wi_q_info);
1102 /* Repeat this packet to BSS? */
1103 mcast = (rxfrm->wi_addr3[0] & 0x01) != 0;
1104 if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) {
1106 /* If it's multicast, make a copy.
1109 m = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
1112 m->m_flags |= M_MCAST; /* XXX */
1115 /* Queue up for repeating.
1117 ifq_handoff(ifp, m, NULL);
1126 * Handle Host AP specific ioctls. Called from wi_ioctl().
1129 owihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1131 struct ifreq *ifr = (struct ifreq *) data;
1132 struct wihap_info *whi = &sc->wi_hostap_info;
1133 struct wihap_sta_info *sta;
1134 struct hostap_getall reqall;
1135 struct hostap_sta reqsta;
1136 struct hostap_sta stabuf;
1137 int s, error = 0, n, flag;
1138 struct thread *td = curthread;
1140 if (!(sc->arpcom.ac_if.if_flags & IFF_RUNNING))
1144 case SIOCHOSTAP_DEL:
1145 if ((error = suser(td)))
1147 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1150 sta = wihap_sta_find(whi, reqsta.addr);
1154 /* Disassociate station. */
1155 if (sta->flags & WI_SIFLAGS_ASSOC)
1156 wihap_sta_disassoc(sc, sta->addr,
1157 IEEE80211_REASON_ASSOC_LEAVE);
1158 /* Deauth station. */
1159 if (sta->flags & WI_SIFLAGS_AUTHEN)
1160 wihap_sta_deauth(sc, sta->addr,
1161 IEEE80211_REASON_AUTH_LEAVE);
1163 wihap_sta_delete(sta);
1168 case SIOCHOSTAP_GET:
1169 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1172 sta = wihap_sta_find(whi, reqsta.addr);
1177 reqsta.flags = sta->flags;
1178 reqsta.asid = sta->asid;
1179 reqsta.capinfo = sta->capinfo;
1180 reqsta.sig_info = sta->sig_info;
1181 reqsta.rates = sta->rates;
1183 error = copyout(&reqsta, ifr->ifr_data,
1188 case SIOCHOSTAP_ADD:
1189 if ((error = suser(td)))
1191 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1194 sta = wihap_sta_find(whi, reqsta.addr);
1200 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
1205 sta = wihap_sta_alloc(sc, reqsta.addr);
1206 sta->flags = reqsta.flags;
1207 callout_reset(&sta->tmo, hz * whi->inactivity_time,
1208 wihap_sta_timeout, sta);
1212 case SIOCHOSTAP_SFLAGS:
1213 if ((error = suser(td)))
1215 if ((error = copyin(ifr->ifr_data, &flag, sizeof(int))))
1218 whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) |
1219 (flag & ~WIHAPFL_CANTCHANGE);
1222 case SIOCHOSTAP_GFLAGS:
1223 flag = (int) whi->apflags;
1224 error = copyout(&flag, ifr->ifr_data, sizeof(int));
1227 case SIOCHOSTAP_GETALL:
1228 if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall))))
1231 reqall.nstations = whi->n_stations;
1234 sta = LIST_FIRST(&whi->sta_list);
1235 while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
1237 bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
1238 stabuf.asid = sta->asid;
1239 stabuf.flags = sta->flags;
1240 stabuf.capinfo = sta->capinfo;
1241 stabuf.sig_info = sta->sig_info;
1242 stabuf.rates = sta->rates;
1244 error = copyout(&stabuf, (caddr_t) reqall.addr + n,
1245 sizeof(struct hostap_sta));
1249 sta = LIST_NEXT(sta, list);
1250 n += sizeof(struct hostap_sta);
1255 error = copyout(&reqall, ifr->ifr_data,
1259 printf("wihap_ioctl: i shouldn't get other ioctls!\n");