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