1 /** $MirOS: src/sys/dev/ic/if_wi_hostap.c,v 1.2 2005/03/06 21:27:40 tg Exp $ */
2 /* $OpenBSD: if_wi_hostap.c,v 1.29 2004/03/15 21:53:28 millert Exp $ */
3
4 /*
5 * Copyright (c) 2002
6 * Thomas Skibo <skibo@pacbell.net>. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Thomas Skibo.
19 * 4. Neither the name of the author nor the names of any co-contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 /* This is experimental Host AP software for Prism 2 802.11b interfaces.
38 *
39 * Much of this is based upon the "Linux Host AP driver Host AP driver
40 * for Intersil Prism2" by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>.
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/sockio.h>
46 #include <sys/mbuf.h>
47 #include <sys/malloc.h>
48 #include <sys/kernel.h>
49 #include <sys/timeout.h>
50 #include <sys/proc.h>
51 #include <sys/ucred.h>
52 #include <sys/socket.h>
53 #include <sys/queue.h>
54 #include <sys/syslog.h>
55 #include <sys/sysctl.h>
56 #include <sys/device.h>
57
58 #include <machine/bus.h>
59
60 #include <net/if.h>
61 #include <net/if_arp.h>
62 #include <net/if_dl.h>
63 #include <net/if_media.h>
64 #include <net/if_types.h>
65
66 #include <netinet/in.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/in_var.h>
69 #include <netinet/ip.h>
70 #include <netinet/if_ether.h>
71
72 #include <net/if_ieee80211.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
take_hword(caddr_t * ppkt,int * plen)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
take_tlv(caddr_t * ppkt,int * plen,int id_expect,void * dst,int maxlen)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
put_hword(caddr_t * ppkt,u_int16_t s)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
put_tlv(caddr_t * ppkt,u_int8_t id,void * src,u_int8_t len)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
put_rates(caddr_t * ppkt,u_int16_t rates)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 splimp().
186 */
187 void
wihap_init(struct wi_softc * sc)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_arpcom.ac_if.if_flags & IFF_DEBUG)
194 printf("wihap_init: sc=0x%lx whi=0x%lx\n", (long)sc, (long)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
wihap_sta_disassoc(struct wi_softc * sc,u_int8_t sta_addr[],u_int16_t reason)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_arpcom.ac_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_arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
232 bcopy(sc->sc_arpcom.ac_enaddr, resp_hdr->addr3, ETHER_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
wihap_sta_deauth(struct wi_softc * sc,u_int8_t sta_addr[],u_int16_t reason)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_arpcom.ac_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_arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
261 bcopy(sc->sc_arpcom.ac_enaddr, resp_hdr->addr3, ETHER_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
wihap_shutdown(struct wi_softc * sc)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_arpcom.ac_if.if_flags & IFF_DEBUG)
281 printf("wihap_shutdown: sc=0x%lx whi=0x%lx\n", (long)sc, (long)whi);
282
283 if (!(whi->apflags & WIHAPFL_ACTIVE))
284 return;
285 whi->apflags = 0;
286
287 s = splimp();
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_arpcom.ac_if.if_flags & IFF_DEBUG)
297 printf("wihap_shutdown: FREE(sta=0x%lx)\n", (long)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
sta_hash_func(u_int8_t addr[])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
addr_cmp(u_int8_t a[],u_int8_t b[])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
wihap_sta_movetail(struct wihap_info * whi,struct wihap_sta_info * sta)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
wihap_timeout(void * v)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 = splimp();
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_arpcom.ac_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(&sta->tmo, hz * whi->inactivity_time);
380 } else if (sta->flags & WI_SIFLAGS_AUTHEN) {
381 if (sc->sc_arpcom.ac_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
wihap_sta_timeout(void * v)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 = splimp();
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 splimp().
431 */
432 void
wihap_sta_delete(struct wihap_sta_info * sta)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 *
wihap_sta_alloc(struct wi_softc * sc,u_int8_t * addr)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 MALLOC(sta, struct wihap_sta_info *, sizeof(struct wihap_sta_info),
465 M_DEVBUF, M_NOWAIT);
466 if (sta == NULL)
467 return (NULL);
468
469 bzero(sta, sizeof(struct wihap_sta_info));
470
471 /* Allocate an ASID. */
472 i=hash<<4;
473 while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
474 i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
475 whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
476 sta->asid = 0xc001 + i;
477
478 /* Insert in list and hash list. */
479 TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
480 LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash);
481
482 sta->sc = sc;
483 whi->n_stations++;
484 bcopy(addr, &sta->addr, ETHER_ADDR_LEN);
485 timeout_set(&sta->tmo, wihap_sta_timeout, sta);
486 timeout_add(&sta->tmo, hz * whi->inactivity_time);
487
488 return (sta);
489 }
490
491 /* wihap_sta_find()
492 *
493 * Find station structure given address.
494 */
495 struct wihap_sta_info *
wihap_sta_find(struct wihap_info * whi,u_int8_t * addr)496 wihap_sta_find(struct wihap_info *whi, u_int8_t *addr)
497 {
498 int i;
499 struct wihap_sta_info *sta;
500
501 i = sta_hash_func(addr);
502 LIST_FOREACH(sta, &whi->sta_hash[i], hash)
503 if (addr_cmp(addr, sta->addr))
504 return sta;
505
506 return (NULL);
507 }
508
509 static __inline int
wihap_check_rates(struct wihap_sta_info * sta,u_int8_t rates[],int rates_len)510 wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
511 {
512 struct wi_softc *sc = sta->sc;
513 int i;
514
515 sta->rates = 0;
516 sta->tx_max_rate = 0;
517 for (i = 0; i < rates_len; i++)
518 switch (rates[i] & 0x7f) {
519 case 0x02:
520 sta->rates |= WI_SUPPRATES_1M;
521 break;
522 case 0x04:
523 sta->rates |= WI_SUPPRATES_2M;
524 if (sta->tx_max_rate < 1)
525 sta->tx_max_rate = 1;
526 break;
527 case 0x0b:
528 sta->rates |= WI_SUPPRATES_5M;
529 if (sta->tx_max_rate < 2)
530 sta->tx_max_rate = 2;
531 break;
532 case 0x16:
533 sta->rates |= WI_SUPPRATES_11M;
534 sta->tx_max_rate = 3;
535 break;
536 }
537
538 sta->rates &= sc->wi_supprates;
539 sta->tx_curr_rate = sta->tx_max_rate;
540
541 return (sta->rates == 0 ? -1 : 0);
542 }
543
544
545 /* wihap_auth_req()
546 *
547 * Handle incoming authentication request.
548 */
549 void
wihap_auth_req(struct wi_softc * sc,struct wi_frame * rxfrm,caddr_t pkt,int len)550 wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
551 caddr_t pkt, int len)
552 {
553 struct wihap_info *whi = &sc->wi_hostap_info;
554 struct wihap_sta_info *sta;
555 int i, s;
556
557 u_int16_t algo;
558 u_int16_t seq;
559 u_int16_t status;
560 int challenge_len;
561 u_int32_t challenge[32];
562
563 struct wi_80211_hdr *resp_hdr;
564
565 if (len < 6) {
566 if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
567 printf("wihap_auth_req: station %s short request\n",
568 ether_sprintf(rxfrm->wi_addr2));
569 return;
570 }
571
572 /* Break open packet. */
573 algo = take_hword(&pkt, &len);
574 seq = take_hword(&pkt, &len);
575 status = take_hword(&pkt, &len);
576 if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
577 printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n",
578 ether_sprintf(rxfrm->wi_addr2), algo, seq);
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_arpcom.ac_if.if_flags & IFF_DEBUG)
606 printf("wihap_auth_req: new station\n");
607
608 /* Create new station. */
609 s = splimp();
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(&sta->tmo, hz * 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 MALLOC(sta->challenge, u_int32_t *, 128,
646 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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
702 bcopy(sc->sc_arpcom.ac_enaddr, resp_hdr->addr3, ETHER_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
wihap_assoc_req(struct wi_softc * sc,struct wi_frame * rxfrm,caddr_t pkt,int len)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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_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_arpcom.ac_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(&sta->tmo, hz * whi->inactivity_time);
833 status = IEEE80211_STATUS_SUCCESS;
834
835 fail:
836 if (sc->sc_arpcom.ac_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_arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);
847 bcopy(sc->sc_arpcom.ac_enaddr, resp_hdr->addr3, ETHER_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
wihap_deauth_req(struct wi_softc * sc,struct wi_frame * rxfrm,caddr_t pkt,int len)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_arpcom.ac_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
wihap_disassoc_req(struct wi_softc * sc,struct wi_frame * rxfrm,caddr_t pkt,int len)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_arpcom.ac_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
wihap_debug_frame_type(struct wi_frame * rxfrm)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
wihap_mgmt_input(struct wi_softc * sc,struct wi_frame * rxfrm,struct mbuf * m)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_arpcom.ac_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
wihap_sta_is_assoc(struct wihap_info * whi,u_int8_t addr[])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(&sta->tmo, hz * 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
wihap_check_tx(struct wihap_info * whi,u_int8_t addr[],u_int8_t * txrate)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(&sta->tmo, hz * 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
wihap_data_input(struct wi_softc * sc,struct wi_frame * rxfrm,struct mbuf * m)1104 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1105 {
1106 struct ifnet *ifp = &sc->sc_arpcom.ac_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_arpcom.ac_enaddr)) {
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(&sta->tmo, hz * 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
wihap_ioctl(struct wi_softc * sc,u_long command,caddr_t data)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 if (!(sc->sc_arpcom.ac_if.if_flags & IFF_RUNNING))
1208 return ENODEV;
1209
1210 switch (command) {
1211 case SIOCHOSTAP_DEL:
1212 if ((error = suser(p, 0)))
1213 break;
1214 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1215 break;
1216 s = splimp();
1217 sta = wihap_sta_find(whi, reqsta.addr);
1218 if (sta == NULL)
1219 error = ENOENT;
1220 else {
1221 /* Disassociate station. */
1222 if (sta->flags & WI_SIFLAGS_ASSOC)
1223 wihap_sta_disassoc(sc, sta->addr,
1224 IEEE80211_REASON_ASSOC_LEAVE);
1225 /* Deauth station. */
1226 if (sta->flags & WI_SIFLAGS_AUTHEN)
1227 wihap_sta_deauth(sc, sta->addr,
1228 IEEE80211_REASON_AUTH_LEAVE);
1229
1230 wihap_sta_delete(sta);
1231 }
1232 splx(s);
1233 break;
1234
1235 case SIOCHOSTAP_GET:
1236 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1237 break;
1238 s = splimp();
1239 sta = wihap_sta_find(whi, reqsta.addr);
1240 if (sta == NULL)
1241 error = ENOENT;
1242 else {
1243 reqsta.flags = sta->flags;
1244 reqsta.asid = sta->asid;
1245 reqsta.capinfo = sta->capinfo;
1246 reqsta.sig_info = sta->sig_info;
1247 reqsta.rates = sta->rates;
1248
1249 error = copyout(&reqsta, ifr->ifr_data,
1250 sizeof(reqsta));
1251 }
1252 splx(s);
1253 break;
1254
1255 case SIOCHOSTAP_ADD:
1256 if ((error = suser(p, 0)))
1257 break;
1258 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1259 break;
1260 s = splimp();
1261 sta = wihap_sta_find(whi, reqsta.addr);
1262 if (sta != NULL) {
1263 error = EEXIST;
1264 splx(s);
1265 break;
1266 }
1267 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
1268 error = ENOSPC;
1269 splx(s);
1270 break;
1271 }
1272 sta = wihap_sta_alloc(sc, reqsta.addr);
1273 sta->flags = reqsta.flags;
1274 timeout_add(&sta->tmo, hz * whi->inactivity_time);
1275 splx(s);
1276 break;
1277
1278 case SIOCHOSTAP_SFLAGS:
1279 if ((error = suser(p, 0)))
1280 break;
1281 if ((error = copyin(ifr->ifr_data, &flag, sizeof(int))))
1282 break;
1283
1284 whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) |
1285 (flag & ~WIHAPFL_CANTCHANGE);
1286 break;
1287
1288 case SIOCHOSTAP_GFLAGS:
1289 flag = (int) whi->apflags;
1290 error = copyout(&flag, ifr->ifr_data, sizeof(int));
1291 break;
1292
1293 case SIOCHOSTAP_GETALL:
1294 if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall))))
1295 break;
1296
1297 reqall.nstations = whi->n_stations;
1298 n = 0;
1299 s = splimp();
1300 sta = TAILQ_FIRST(&whi->sta_list);
1301 while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
1302
1303 bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
1304 stabuf.asid = sta->asid;
1305 stabuf.flags = sta->flags;
1306 stabuf.capinfo = sta->capinfo;
1307 stabuf.sig_info = sta->sig_info;
1308 stabuf.rates = sta->rates;
1309
1310 error = copyout(&stabuf, (caddr_t) reqall.addr + n,
1311 sizeof(struct hostap_sta));
1312 if (error)
1313 break;
1314
1315 sta = TAILQ_NEXT(sta, list);
1316 n += sizeof(struct hostap_sta);
1317 }
1318 splx(s);
1319
1320 if (!error)
1321 error = copyout(&reqall, ifr->ifr_data,
1322 sizeof(reqall));
1323 break;
1324 default:
1325 printf("wihap_ioctl: i shouldn't get other ioctls!\n");
1326 error = EINVAL;
1327 }
1328
1329 return (error);
1330 }
1331
1332 #else
1333 void
wihap_init(struct wi_softc * sc)1334 wihap_init(struct wi_softc *sc)
1335 {
1336 return;
1337 }
1338
1339 void
wihap_shutdown(struct wi_softc * sc)1340 wihap_shutdown(struct wi_softc *sc)
1341 {
1342 return;
1343 }
1344
1345 void
wihap_mgmt_input(struct wi_softc * sc,struct wi_frame * rxfrm,struct mbuf * m)1346 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1347 {
1348 return;
1349 }
1350
1351 int
wihap_data_input(struct wi_softc * sc,struct wi_frame * rxfrm,struct mbuf * m)1352 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1353 {
1354 return (0);
1355 }
1356
1357 int
wihap_ioctl(struct wi_softc * sc,u_long command,caddr_t data)1358 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1359 {
1360 return (EINVAL);
1361 }
1362
1363 int
wihap_check_tx(struct wihap_info * whi,u_int8_t addr[],u_int8_t * txrate)1364 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1365 {
1366 return (0);
1367 }
1368 #endif
1369