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