xref: /openbsd-src/sys/dev/ic/if_wi_hostap.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: if_wi_hostap.c,v 1.42 2013/08/07 01:06:30 bluhm 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/ip.h>
68 #include <netinet/if_ether.h>
69 
70 #include <net80211/ieee80211_var.h>
71 #include <net80211/ieee80211_ioctl.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 
79 void wihap_timeout(void *v);
80 void wihap_sta_timeout(void *v);
81 struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr);
82 void wihap_sta_delete(struct wihap_sta_info *sta);
83 struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr);
84 int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]);
85 void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
86     caddr_t pkt, int len);
87 void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[],
88     u_int16_t reason);
89 void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
90     caddr_t pkt, int len);
91 void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
92     caddr_t pkt, int len);
93 void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[],
94     u_int16_t reason);
95 void 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  */
105 static __inline u_int16_t
106 take_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  */
119 static int
120 take_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  */
143 static __inline void
144 put_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  */
153 static void
154 put_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 
162 static int
163 put_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 splnet().
185  */
186 void
187 wihap_init(struct wi_softc *sc)
188 {
189 	int i;
190 	struct wihap_info *whi = &sc->wi_hostap_info;
191 
192 	if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
193 		printf("wihap_init: sc=%p whi=%p\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  */
214 void
215 wihap_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_ic.ic_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_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
231 	bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_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  */
243 void
244 wihap_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_ic.ic_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_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
260 	bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_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  */
272 void
273 wihap_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_ic.ic_if.if_flags & IFF_DEBUG)
280 		printf("wihap_shutdown: sc=%p whi=%p\n", sc, whi);
281 
282 	if (!(whi->apflags & WIHAPFL_ACTIVE))
283 		return;
284 	whi->apflags = 0;
285 
286 	s = splnet();
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_ic.ic_if.if_flags & IFF_DEBUG)
296 			printf("wihap_shutdown: free(sta=%p)\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  */
321 static __inline int
322 sta_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? */
328 static __inline int
329 addr_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 */
337 static __inline void
338 wihap_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 
345 void
346 wihap_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 = splnet();
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_ic.ic_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_sec(&sta->tmo, whi->inactivity_time);
379 		} else if (sta->flags & WI_SIFLAGS_AUTHEN) {
380 			if (sc->sc_ic.ic_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 
405 void
406 wihap_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 = splnet();
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 splnet().
430  */
431 void
432 wihap_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  */
455 struct wihap_sta_info *
456 wihap_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 	sta = malloc(sizeof(*sta), M_DEVBUF, M_NOWAIT | M_ZERO);
464 	if (sta == NULL)
465 		return (NULL);
466 
467 	/* Allocate an ASID. */
468 	i=hash<<4;
469 	while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
470 		i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
471 	whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
472 	sta->asid = 0xc001 + i;
473 
474 	/* Insert in list and hash list. */
475 	TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
476 	LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash);
477 
478 	sta->sc = sc;
479 	whi->n_stations++;
480 	bcopy(addr, &sta->addr, ETHER_ADDR_LEN);
481 	timeout_set(&sta->tmo, wihap_sta_timeout, sta);
482 	timeout_add_sec(&sta->tmo, whi->inactivity_time);
483 
484 	return (sta);
485 }
486 
487 /* wihap_sta_find()
488  *
489  *	Find station structure given address.
490  */
491 struct wihap_sta_info *
492 wihap_sta_find(struct wihap_info *whi, u_int8_t *addr)
493 {
494 	int i;
495 	struct wihap_sta_info *sta;
496 
497 	i = sta_hash_func(addr);
498 	LIST_FOREACH(sta, &whi->sta_hash[i], hash)
499 		if (addr_cmp(addr, sta->addr))
500 			return sta;
501 
502 	return (NULL);
503 }
504 
505 static __inline int
506 wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
507 {
508 	struct wi_softc *sc = sta->sc;
509 	int	i;
510 
511 	sta->rates = 0;
512 	sta->tx_max_rate = 0;
513 	for (i = 0; i < rates_len; i++)
514 		switch (rates[i] & 0x7f) {
515 		case 0x02:
516 			sta->rates |= WI_SUPPRATES_1M;
517 			break;
518 		case 0x04:
519 			sta->rates |= WI_SUPPRATES_2M;
520 			if (sta->tx_max_rate < 1)
521 				sta->tx_max_rate = 1;
522 			break;
523 		case 0x0b:
524 			sta->rates |= WI_SUPPRATES_5M;
525 			if (sta->tx_max_rate < 2)
526 				sta->tx_max_rate = 2;
527 			break;
528 		case 0x16:
529 			sta->rates |= WI_SUPPRATES_11M;
530 			sta->tx_max_rate = 3;
531 			break;
532 		}
533 
534 	sta->rates &= sc->wi_supprates;
535 	sta->tx_curr_rate = sta->tx_max_rate;
536 
537 	return (sta->rates == 0 ? -1 : 0);
538 }
539 
540 
541 /* wihap_auth_req()
542  *
543  *	Handle incoming authentication request.
544  */
545 void
546 wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
547     caddr_t pkt, int len)
548 {
549 	struct wihap_info	*whi = &sc->wi_hostap_info;
550 	struct wihap_sta_info	*sta;
551 	int			i, s;
552 
553 	u_int16_t		algo;
554 	u_int16_t		seq;
555 	u_int16_t		status;
556 	int			challenge_len;
557 	u_int32_t		challenge[32];
558 
559 	struct wi_80211_hdr	*resp_hdr;
560 
561 	if (len < 6) {
562 		if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
563 			printf("wihap_auth_req: station %s short request\n",
564 			    ether_sprintf(rxfrm->wi_addr2));
565 		return;
566 	}
567 
568 	/* Break open packet. */
569 	algo = take_hword(&pkt, &len);
570 	seq = take_hword(&pkt, &len);
571 	status = take_hword(&pkt, &len);
572 	if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
573 		printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n",
574 		    ether_sprintf(rxfrm->wi_addr2), algo, seq);
575 
576 	/* Ignore vendor private tlv (if any). */
577 	(void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge,
578 	    sizeof(challenge));
579 
580 	challenge_len = 0;
581 	if (len > 0 && (challenge_len = take_tlv(&pkt, &len,
582 	    IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) {
583 		status = IEEE80211_STATUS_CHALLENGE;
584 		goto fail;
585 	}
586 
587 	/* Find or create station info. */
588 	sta = wihap_sta_find(whi, rxfrm->wi_addr2);
589 	if (sta == NULL) {
590 
591 		/* Are we allowing new stations?
592 		 */
593 		if (whi->apflags & WIHAPFL_MAC_FILT) {
594 			status = IEEE80211_STATUS_OTHER; /* XXX */
595 			goto fail;
596 		}
597 
598 		/* Check for too many stations.
599 		 */
600 		if (whi->n_stations >= WIHAP_MAX_STATIONS) {
601 			status = IEEE80211_STATUS_TOOMANY;
602 			goto fail;
603 		}
604 
605 		if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
606 			printf("wihap_auth_req: new station\n");
607 
608 		/* Create new station. */
609 		s = splnet();
610 		sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
611 		splx(s);
612 		if (sta == NULL) {
613 			/* Out of memory! */
614 			status = IEEE80211_STATUS_TOOMANY;
615 			goto fail;
616 		}
617 	}
618 	timeout_add_sec(&sta->tmo, whi->inactivity_time);
619 
620 	/* Note: it's okay to leave the station info structure around
621 	 * if the authen fails.  It'll be timed out eventually.
622 	 */
623 	switch (algo) {
624 	case IEEE80211_AUTH_ALG_OPEN:
625 		if (sc->wi_authtype != IEEE80211_AUTH_OPEN) {
626 			status = IEEE80211_STATUS_ALG;
627 			goto fail;
628 		}
629 		if (seq != 1) {
630 			status = IEEE80211_STATUS_SEQUENCE;
631 			goto fail;
632 		}
633 		challenge_len = 0;
634 		sta->flags |= WI_SIFLAGS_AUTHEN;
635 		break;
636 	case IEEE80211_AUTH_ALG_SHARED:
637 		if (sc->wi_authtype != IEEE80211_AUTH_SHARED) {
638 			status = IEEE80211_STATUS_ALG;
639 			goto fail;
640 		}
641 		switch (seq) {
642 		case 1:
643 			/* Create a challenge frame. */
644 			if (!sta->challenge) {
645 				sta->challenge = malloc(128, 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_ic.ic_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_ic.ic_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 
691 fail:
692 	if (sc->sc_ic.ic_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_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
701 	bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_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  */
721 void
722 wihap_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_ic.ic_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_ic.ic_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_ic.ic_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_ic.ic_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_ic.ic_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_ic.ic_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_ic.ic_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_sec(&sta->tmo, whi->inactivity_time);
832 	status = IEEE80211_STATUS_SUCCESS;
833 
834 fail:
835 	if (sc->sc_ic.ic_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_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
846 	bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_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  */
861 void
862 wihap_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_ic.ic_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  */
890 void
891 wihap_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_ic.ic_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  */
926 static __inline void
927 wihap_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  */
989 void
990 wihap_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_ic.ic_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  */
1046 int
1047 wihap_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_sec(&sta->tmo, 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  */
1066 int
1067 wihap_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_sec(&sta->tmo, 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  */
1102 int
1103 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1104 {
1105 	struct ifnet		*ifp = &sc->sc_ic.ic_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_ic.ic_myaddr)) {
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_sec(&sta->tmo, 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  */
1194 int
1195 wihap_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 	struct ieee80211_nodereq nr;
1207 	struct ieee80211_nodereq_all *na;
1208 
1209 	if (!(sc->sc_ic.ic_if.if_flags & IFF_RUNNING))
1210 		return ENODEV;
1211 
1212 	switch (command) {
1213 	case SIOCHOSTAP_DEL:
1214 		if ((error = suser(p, 0)))
1215 			break;
1216 		if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1217 			break;
1218 		s = splnet();
1219 		sta = wihap_sta_find(whi, reqsta.addr);
1220 		if (sta == NULL)
1221 			error = ENOENT;
1222 		else {
1223 			/* Disassociate station. */
1224 			if (sta->flags & WI_SIFLAGS_ASSOC)
1225 				wihap_sta_disassoc(sc, sta->addr,
1226 				    IEEE80211_REASON_ASSOC_LEAVE);
1227 			/* Deauth station. */
1228 			if (sta->flags & WI_SIFLAGS_AUTHEN)
1229 				wihap_sta_deauth(sc, sta->addr,
1230 				    IEEE80211_REASON_AUTH_LEAVE);
1231 
1232 			wihap_sta_delete(sta);
1233 		}
1234 		splx(s);
1235 		break;
1236 
1237 	case SIOCHOSTAP_GET:
1238 		if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1239 			break;
1240 		s = splnet();
1241 		sta = wihap_sta_find(whi, reqsta.addr);
1242 		if (sta == NULL)
1243 			error = ENOENT;
1244 		else {
1245 			reqsta.flags = sta->flags;
1246 			reqsta.asid = sta->asid;
1247 			reqsta.capinfo = sta->capinfo;
1248 			reqsta.sig_info = sta->sig_info;
1249 			reqsta.rates = sta->rates;
1250 
1251 			error = copyout(&reqsta, ifr->ifr_data,
1252 			    sizeof(reqsta));
1253 		}
1254 		splx(s);
1255 		break;
1256 
1257 	case SIOCHOSTAP_ADD:
1258 		if ((error = suser(p, 0)))
1259 			break;
1260 		if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1261 			break;
1262 		s = splnet();
1263 		sta = wihap_sta_find(whi, reqsta.addr);
1264 		if (sta != NULL) {
1265 			error = EEXIST;
1266 			splx(s);
1267 			break;
1268 		}
1269 		if (whi->n_stations >= WIHAP_MAX_STATIONS) {
1270 			error = ENOSPC;
1271 			splx(s);
1272 			break;
1273 		}
1274 		sta = wihap_sta_alloc(sc, reqsta.addr);
1275 		sta->flags = reqsta.flags;
1276 		timeout_add_sec(&sta->tmo, whi->inactivity_time);
1277 		splx(s);
1278 		break;
1279 
1280 	case SIOCHOSTAP_SFLAGS:
1281 		if ((error = suser(p, 0)))
1282 			break;
1283 		if ((error = copyin(ifr->ifr_data, &flag, sizeof(int))))
1284 			break;
1285 
1286 		whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) |
1287 		    (flag & ~WIHAPFL_CANTCHANGE);
1288 		break;
1289 
1290 	case SIOCHOSTAP_GFLAGS:
1291 		flag = (int) whi->apflags;
1292 		error = copyout(&flag, ifr->ifr_data, sizeof(int));
1293 		break;
1294 
1295 	case SIOCHOSTAP_GETALL:
1296 		if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall))))
1297 			break;
1298 
1299 		reqall.nstations = whi->n_stations;
1300 		n = 0;
1301 		s = splnet();
1302 		sta = TAILQ_FIRST(&whi->sta_list);
1303 		while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
1304 
1305 			bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
1306 			stabuf.asid = sta->asid;
1307 			stabuf.flags = sta->flags;
1308 			stabuf.capinfo = sta->capinfo;
1309 			stabuf.sig_info = sta->sig_info;
1310 			stabuf.rates = sta->rates;
1311 
1312 			error = copyout(&stabuf, (caddr_t) reqall.addr + n,
1313 			    sizeof(struct hostap_sta));
1314 			if (error)
1315 				break;
1316 
1317 			sta = TAILQ_NEXT(sta, list);
1318 			n += sizeof(struct hostap_sta);
1319 		}
1320 		splx(s);
1321 
1322 		if (!error)
1323 			error = copyout(&reqall, ifr->ifr_data,
1324 			    sizeof(reqall));
1325 		break;
1326 
1327 	case SIOCG80211ALLNODES:
1328 		na = (struct ieee80211_nodereq_all *)data;
1329 		na->na_nodes = n = 0;
1330 		s = splnet();
1331 		sta = TAILQ_FIRST(&whi->sta_list);
1332 		while (sta && na->na_size >=
1333 		    n + sizeof(struct ieee80211_nodereq)) {
1334 			bzero(&nr, sizeof(nr));
1335 			IEEE80211_ADDR_COPY(nr.nr_macaddr, sta->addr);
1336 			IEEE80211_ADDR_COPY(nr.nr_bssid,
1337 			    &sc->sc_ic.ic_myaddr);
1338 			nr.nr_channel = sc->wi_channel;
1339 			nr.nr_chan_flags = IEEE80211_CHAN_B;
1340 			nr.nr_associd = sta->asid;
1341 			nr.nr_rssi = sta->sig_info >> 8;
1342 			nr.nr_max_rssi = 0;
1343 			nr.nr_capinfo = sta->capinfo;
1344 			nr.nr_nrates = 0;
1345 			if (sta->rates & WI_SUPPRATES_1M)
1346 				nr.nr_rates[nr.nr_nrates++] = 2;
1347 			if (sta->rates & WI_SUPPRATES_2M)
1348 				nr.nr_rates[nr.nr_nrates++] = 4;
1349 			if (sta->rates & WI_SUPPRATES_5M)
1350 				nr.nr_rates[nr.nr_nrates++] = 11;
1351 			if (sta->rates & WI_SUPPRATES_11M)
1352 				nr.nr_rates[nr.nr_nrates++] = 22;
1353 
1354 			error = copyout(&nr, (caddr_t)na->na_node + n,
1355 			    sizeof(struct ieee80211_nodereq));
1356 			if (error)
1357 				break;
1358 			n += sizeof(struct ieee80211_nodereq);
1359 			na->na_nodes++;
1360 			sta = TAILQ_NEXT(sta, list);
1361 		}
1362 		splx(s);
1363 		break;
1364 
1365 	default:
1366 		printf("wihap_ioctl: i shouldn't get other ioctls!\n");
1367 		error = EINVAL;
1368 	}
1369 
1370 	return (error);
1371 }
1372 
1373 #else
1374 void
1375 wihap_init(struct wi_softc *sc)
1376 {
1377 	return;
1378 }
1379 
1380 void
1381 wihap_shutdown(struct wi_softc *sc)
1382 {
1383 	return;
1384 }
1385 
1386 void
1387 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1388 {
1389 	return;
1390 }
1391 
1392 int
1393 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1394 {
1395 	return (0);
1396 }
1397 
1398 int
1399 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1400 {
1401 	return (EINVAL);
1402 }
1403 
1404 int
1405 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1406 {
1407 	return (0);
1408 }
1409 #endif
1410