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