This source file includes following definitions.
- take_hword
- take_tlv
- put_hword
- put_tlv
- put_rates
- wihap_init
- wihap_sta_disassoc
- wihap_sta_deauth
- wihap_shutdown
- sta_hash_func
- addr_cmp
- wihap_sta_movetail
- wihap_timeout
- wihap_sta_timeout
- wihap_sta_delete
- wihap_sta_alloc
- wihap_sta_find
- wihap_check_rates
- wihap_auth_req
- wihap_assoc_req
- wihap_deauth_req
- wihap_disassoc_req
- wihap_debug_frame_type
- wihap_mgmt_input
- wihap_sta_is_assoc
- wihap_check_tx
- wihap_data_input
- wihap_ioctl
- wihap_init
- wihap_shutdown
- wihap_mgmt_input
- wihap_data_input
- wihap_ioctl
- wihap_check_tx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
102
103
104
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
116
117
118
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
142
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
152
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
183
184
185
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
212
213
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
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
241
242
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
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
270
271
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
290 timeout_del(&whi->tmo);
291
292
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
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
320
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
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
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
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
369 wihap_sta_disassoc(sc, sta->addr,
370 IEEE80211_REASON_ASSOC_EXPIRE);
371 sta->flags &= ~WI_SIFLAGS_ASSOC;
372
373
374
375
376
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_ic.ic_if.if_flags & IFF_DEBUG)
382 printf("wihap_timeout: deauth due to inactivity: %s\n",
383 ether_sprintf(sta->addr));
384
385
386 wihap_sta_deauth(sc, sta->addr,
387 IEEE80211_REASON_AUTH_EXPIRE);
388 sta->flags &= ~WI_SIFLAGS_AUTHEN;
389
390
391 if (sta->flags & WI_SIFLAGS_PERM)
392 wihap_sta_movetail(whi, sta);
393 else
394 wihap_sta_delete(sta);
395 }
396 }
397
398
399 sta = TAILQ_FIRST(&whi->sta_list);
400 if (sta != NULL && (sta->flags & WI_SIFLAGS_DEAD))
401 timeout_add(&whi->tmo, 1);
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
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
422 if (!timeout_pending(&whi->tmo))
423 timeout_add(&whi->tmo, hz / 10);
424
425 splx(s);
426 }
427
428
429
430
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
452
453
454
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
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
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
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
492
493
494
495 struct wihap_sta_info *
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
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
546
547
548
549 void
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_ic.ic_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
573 algo = take_hword(&pkt, &len);
574 seq = take_hword(&pkt, &len);
575 status = take_hword(&pkt, &len);
576 if (sc->sc_ic.ic_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
581 (void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge,
582 sizeof(challenge));
583
584 challenge_len = 0;
585 if (len > 0 && (challenge_len = take_tlv(&pkt, &len,
586 IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) {
587 status = IEEE80211_STATUS_CHALLENGE;
588 goto fail;
589 }
590
591
592 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
593 if (sta == NULL) {
594
595
596
597 if (whi->apflags & WIHAPFL_MAC_FILT) {
598 status = IEEE80211_STATUS_OTHER;
599 goto fail;
600 }
601
602
603
604 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
605 status = IEEE80211_STATUS_TOOMANY;
606 goto fail;
607 }
608
609 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
610 printf("wihap_auth_req: new station\n");
611
612
613 s = splnet();
614 sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
615 splx(s);
616 if (sta == NULL) {
617
618 status = IEEE80211_STATUS_TOOMANY;
619 goto fail;
620 }
621 }
622 timeout_add(&sta->tmo, hz * whi->inactivity_time);
623
624
625
626
627 switch (algo) {
628 case IEEE80211_AUTH_ALG_OPEN:
629 if (sc->wi_authtype != IEEE80211_AUTH_OPEN) {
630 status = IEEE80211_STATUS_ALG;
631 goto fail;
632 }
633 if (seq != 1) {
634 status = IEEE80211_STATUS_SEQUENCE;
635 goto fail;
636 }
637 challenge_len = 0;
638 sta->flags |= WI_SIFLAGS_AUTHEN;
639 break;
640 case IEEE80211_AUTH_ALG_SHARED:
641 if (sc->wi_authtype != IEEE80211_AUTH_SHARED) {
642 status = IEEE80211_STATUS_ALG;
643 goto fail;
644 }
645 switch (seq) {
646 case 1:
647
648 if (!sta->challenge) {
649 MALLOC(sta->challenge, u_int32_t *, 128,
650 M_TEMP, M_NOWAIT);
651 if (!sta->challenge)
652 return;
653 }
654 for (i = 0; i < 32; i++)
655 challenge[i] = sta->challenge[i] =
656 arc4random();
657
658 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
659 printf("\tchallenge: 0x%x 0x%x ...\n",
660 challenge[0], challenge[1]);
661 challenge_len = 128;
662 break;
663 case 3:
664 if (challenge_len != 128 || !sta->challenge ||
665 !(letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) {
666 status = IEEE80211_STATUS_CHALLENGE;
667 goto fail;
668 }
669
670 for (i=0; i<32; i++)
671 if (sta->challenge[i] != challenge[i]) {
672 status = IEEE80211_STATUS_CHALLENGE;
673 goto fail;
674 }
675
676 sta->flags |= WI_SIFLAGS_AUTHEN;
677 FREE(sta->challenge, M_TEMP);
678 sta->challenge = NULL;
679 challenge_len = 0;
680 break;
681 default:
682 status = IEEE80211_STATUS_SEQUENCE;
683 goto fail;
684 }
685 break;
686 default:
687 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
688 printf("wihap_auth_req: algorithm unsupported: 0x%x\n",
689 algo);
690 status = IEEE80211_STATUS_ALG;
691 goto fail;
692 }
693
694 status = IEEE80211_STATUS_SUCCESS;
695
696 fail:
697 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
698 printf("wihap_auth_req: returns status=0x%x\n", status);
699
700
701 resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
702 bzero(resp_hdr, sizeof(struct wi_80211_hdr));
703 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH);
704 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
705 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
706 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
707
708 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
709 put_hword(&pkt, algo);
710 put_hword(&pkt, seq + 1);
711 put_hword(&pkt, status);
712 if (challenge_len > 0)
713 put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE,
714 challenge, challenge_len);
715
716 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
717 6 + sizeof(struct wi_80211_hdr) +
718 (challenge_len > 0 ? challenge_len + 2 : 0));
719 }
720
721
722
723
724
725
726 void
727 wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
728 caddr_t pkt, int len)
729 {
730 struct wihap_info *whi = &sc->wi_hostap_info;
731 struct wihap_sta_info *sta;
732 struct wi_80211_hdr *resp_hdr;
733 u_int16_t capinfo;
734 u_int16_t lstintvl;
735 u_int8_t rates[12];
736 int ssid_len, rates_len;
737 struct ieee80211_nwid ssid;
738 u_int16_t status;
739 u_int16_t asid = 0;
740
741 if (len < 8)
742 return;
743
744
745 capinfo = take_hword(&pkt, &len);
746 lstintvl = take_hword(&pkt, &len);
747
748 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
749 htole16(WI_STYPE_MGMT_REASREQ)) {
750 if (len < 6)
751 return;
752
753 take_hword(&pkt, &len);
754 take_hword(&pkt, &len);
755 take_hword(&pkt, &len);
756 }
757
758 if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
759 ssid.i_nwid, sizeof(ssid))) < 0)
760 return;
761 ssid.i_len = ssid_len;
762 if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES,
763 rates, sizeof(rates))) < 0)
764 return;
765
766 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
767 printf("wihap_assoc_req: from station %s\n",
768 ether_sprintf(rxfrm->wi_addr2));
769
770
771 if (sc->wi_net_name.i_len != ssid.i_len ||
772 memcmp(sc->wi_net_name.i_nwid, ssid.i_nwid, ssid.i_len)) {
773
774 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
775 printf("wihap_assoc_req: bad ssid: '%.*s' != '%.*s'\n",
776 ssid.i_len, ssid.i_nwid, sc->wi_net_name.i_len,
777 sc->wi_net_name.i_nwid);
778 return;
779 }
780
781
782 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
783 if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) {
784 wihap_sta_deauth(sc, rxfrm->wi_addr2,
785 IEEE80211_REASON_NOT_AUTHED);
786 return;
787 }
788
789
790 if (wihap_check_rates(sta, rates, rates_len) < 0) {
791 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
792 printf("wihap_assoc_req: rates mismatch.\n");
793 status = IEEE80211_STATUS_BASIC_RATE;
794 goto fail;
795 }
796
797
798
799
800
801
802 sta->capinfo = capinfo;
803 status = IEEE80211_STATUS_CAPINFO;
804 if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) !=
805 IEEE80211_CAPINFO_ESS) {
806 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
807 printf("wihap_assoc_req: capinfo: not ESS: "
808 "capinfo=0x%x\n", capinfo);
809 goto fail;
810
811 }
812 if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) ||
813 (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) {
814 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
815 printf("wihap_assoc_req: WEP flag mismatch: "
816 "capinfo=0x%x\n", capinfo);
817 goto fail;
818 }
819 if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE |
820 IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) {
821 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
822 printf("wihap_assoc_req: polling not supported: "
823 "capinfo=0x%x\n", capinfo);
824 goto fail;
825 }
826
827
828 asid = sta->asid;
829
830 if (sta->flags & WI_SIFLAGS_ASSOC) {
831 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
832 printf("wihap_assoc_req: already assoc'ed?\n");
833 }
834
835 sta->flags |= WI_SIFLAGS_ASSOC;
836 timeout_add(&sta->tmo, hz * whi->inactivity_time);
837 status = IEEE80211_STATUS_SUCCESS;
838
839 fail:
840 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
841 printf("wihap_assoc_req: returns status=0x%x\n", status);
842
843
844 resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
845 bzero(resp_hdr, sizeof(struct wi_80211_hdr));
846 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
847 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
848
849 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
850 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
851 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
852
853 put_hword(&pkt, capinfo);
854 put_hword(&pkt, status);
855 put_hword(&pkt, asid);
856 rates_len = put_rates(&pkt, sc->wi_supprates);
857
858 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
859 8 + rates_len + sizeof(struct wi_80211_hdr));
860 }
861
862
863
864
865
866 void
867 wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
868 caddr_t pkt, int len)
869 {
870 struct wihap_info *whi = &sc->wi_hostap_info;
871 struct wihap_sta_info *sta;
872 u_int16_t reason;
873
874 if (len<2)
875 return;
876
877 reason = take_hword(&pkt, &len);
878
879 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
880 if (sta == NULL) {
881 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
882 printf("wihap_deauth_req: unknown station: %s\n",
883 ether_sprintf(rxfrm->wi_addr2));
884 }
885 else
886 wihap_sta_delete(sta);
887 }
888
889
890
891
892
893
894
895 void
896 wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
897 caddr_t pkt, int len)
898 {
899 struct wihap_info *whi = &sc->wi_hostap_info;
900 struct wihap_sta_info *sta;
901 u_int16_t reason;
902
903 if (len < 2)
904 return;
905
906 reason = take_hword(&pkt, &len);
907
908 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
909 if (sta == NULL) {
910 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
911 printf("wihap_disassoc_req: unknown station: %s\n",
912 ether_sprintf(rxfrm->wi_addr2));
913 }
914 else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) {
915
916
917
918
919 wihap_sta_deauth(sc, rxfrm->wi_addr2,
920 IEEE80211_REASON_NOT_AUTHED);
921 return;
922 }
923 else
924 sta->flags &= ~WI_SIFLAGS_ASSOC;
925 }
926
927
928
929
930
931 static __inline void
932 wihap_debug_frame_type(struct wi_frame *rxfrm)
933 {
934 printf("wihap_mgmt_input: len=%d ", letoh16(rxfrm->wi_dat_len));
935
936 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
937 htole16(WI_FTYPE_MGMT)) {
938
939 printf("MGMT: ");
940
941 switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
942 case WI_STYPE_MGMT_ASREQ:
943 printf("assoc req: \n");
944 break;
945 case WI_STYPE_MGMT_ASRESP:
946 printf("assoc resp: \n");
947 break;
948 case WI_STYPE_MGMT_REASREQ:
949 printf("reassoc req: \n");
950 break;
951 case WI_STYPE_MGMT_REASRESP:
952 printf("reassoc resp: \n");
953 break;
954 case WI_STYPE_MGMT_PROBEREQ:
955 printf("probe req: \n");
956 break;
957 case WI_STYPE_MGMT_PROBERESP:
958 printf("probe resp: \n");
959 break;
960 case WI_STYPE_MGMT_BEACON:
961 printf("beacon: \n");
962 break;
963 case WI_STYPE_MGMT_ATIM:
964 printf("ann traf ind \n");
965 break;
966 case WI_STYPE_MGMT_DISAS:
967 printf("disassociation: \n");
968 break;
969 case WI_STYPE_MGMT_AUTH:
970 printf("auth: \n");
971 break;
972 case WI_STYPE_MGMT_DEAUTH:
973 printf("deauth: \n");
974 break;
975 default:
976 printf("unknown (stype=0x%x)\n",
977 letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE);
978 }
979
980 }
981 else {
982 printf("ftype=0x%x (ctl=0x%x)\n",
983 letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE,
984 letoh16(rxfrm->wi_frame_ctl));
985 }
986 }
987
988
989
990
991
992
993
994 void
995 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
996 {
997 caddr_t pkt;
998 int s, len;
999
1000 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
1001 wihap_debug_frame_type(rxfrm);
1002
1003 pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW;
1004 len = m->m_len - WI_802_11_OFFSET_RAW;
1005
1006 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
1007 htole16(WI_FTYPE_MGMT)) {
1008
1009
1010 s = splsoftclock();
1011 switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
1012 case WI_STYPE_MGMT_ASREQ:
1013 wihap_assoc_req(sc, rxfrm, pkt, len);
1014 break;
1015 case WI_STYPE_MGMT_ASRESP:
1016 break;
1017 case WI_STYPE_MGMT_REASREQ:
1018 wihap_assoc_req(sc, rxfrm, pkt, len);
1019 break;
1020 case WI_STYPE_MGMT_REASRESP:
1021 break;
1022 case WI_STYPE_MGMT_PROBEREQ:
1023 break;
1024 case WI_STYPE_MGMT_PROBERESP:
1025 break;
1026 case WI_STYPE_MGMT_BEACON:
1027 break;
1028 case WI_STYPE_MGMT_ATIM:
1029 break;
1030 case WI_STYPE_MGMT_DISAS:
1031 wihap_disassoc_req(sc, rxfrm, pkt, len);
1032 break;
1033 case WI_STYPE_MGMT_AUTH:
1034 wihap_auth_req(sc, rxfrm, pkt, len);
1035 break;
1036 case WI_STYPE_MGMT_DEAUTH:
1037 wihap_deauth_req(sc, rxfrm, pkt, len);
1038 break;
1039 }
1040 splx(s);
1041 }
1042
1043 m_freem(m);
1044 }
1045
1046
1047
1048
1049
1050
1051 int
1052 wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[])
1053 {
1054 struct wihap_sta_info *sta;
1055
1056 sta = wihap_sta_find(whi, addr);
1057 if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
1058
1059 timeout_add(&sta->tmo, hz * whi->inactivity_time);
1060 return (1);
1061 }
1062
1063 return (0);
1064 }
1065
1066
1067
1068
1069
1070
1071 int
1072 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1073 {
1074 struct wihap_sta_info *sta;
1075 static u_int8_t txratetable[] = { 10, 20, 55, 110 };
1076 int s;
1077
1078 if (addr[0] & 0x01) {
1079 *txrate = 0;
1080 return (1);
1081 }
1082
1083 s = splsoftclock();
1084 sta = wihap_sta_find(whi, addr);
1085 if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
1086
1087 timeout_add(&sta->tmo, hz * whi->inactivity_time);
1088 *txrate = txratetable[sta->tx_curr_rate];
1089 splx(s);
1090 return (1);
1091 }
1092 splx(s);
1093
1094 return (0);
1095 }
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 int
1108 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1109 {
1110 struct ifnet *ifp = &sc->sc_ic.ic_if;
1111 struct wihap_info *whi = &sc->wi_hostap_info;
1112 struct wihap_sta_info *sta;
1113 int mcast, s;
1114 u_int16_t fctl;
1115
1116
1117
1118
1119
1120
1121
1122 fctl = letoh16(rxfrm->wi_frame_ctl);
1123 if (!(fctl & WI_FCTL_TODS) && !(fctl & WI_STYPE_NULLFUNC)) {
1124 if (ifp->if_flags & IFF_DEBUG)
1125 printf("wihap_data_input: no TODS src=%s, fctl=0x%x\n",
1126 ether_sprintf(rxfrm->wi_addr2), fctl);
1127 m_freem(m);
1128 return (1);
1129 }
1130
1131
1132 if (!addr_cmp(rxfrm->wi_addr1, sc->sc_ic.ic_myaddr)) {
1133 if (ifp->if_flags & IFF_DEBUG)
1134 printf("wihap_data_input: incorrect bss: %s\n",
1135 ether_sprintf(rxfrm->wi_addr1));
1136 m_freem(m);
1137 return (1);
1138 }
1139
1140 s = splsoftclock();
1141
1142
1143 sta = wihap_sta_find(whi, rxfrm->wi_addr2);
1144
1145
1146 if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) {
1147 if (ifp->if_flags & IFF_DEBUG)
1148 printf("wihap_data_input: dropping unassoc src %s\n",
1149 ether_sprintf(rxfrm->wi_addr2));
1150 wihap_sta_disassoc(sc, rxfrm->wi_addr2,
1151 IEEE80211_REASON_ASSOC_LEAVE);
1152 splx(s);
1153 m_freem(m);
1154 return (1);
1155 }
1156
1157 timeout_add(&sta->tmo, hz * whi->inactivity_time);
1158 sta->sig_info = letoh16(rxfrm->wi_q_info);
1159
1160 splx(s);
1161
1162
1163 mcast = (rxfrm->wi_addr3[0] & 0x01) != 0;
1164 if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) {
1165
1166
1167
1168 if (mcast) {
1169 m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1170 if (m == NULL)
1171 return (0);
1172 m->m_flags |= M_MCAST;
1173 }
1174
1175
1176
1177 if (IF_QFULL(&ifp->if_snd)) {
1178 IF_DROP(&ifp->if_snd);
1179 m_freem(m);
1180 }
1181 else {
1182 ifp->if_obytes += m->m_pkthdr.len;
1183 if (m->m_flags & M_MCAST)
1184 ifp->if_omcasts++;
1185 IF_ENQUEUE(&ifp->if_snd, m);
1186 if ((ifp->if_flags & IFF_OACTIVE) == 0)
1187 (*ifp->if_start)(ifp);
1188 }
1189 return (!mcast);
1190 }
1191
1192 return (0);
1193 }
1194
1195
1196
1197
1198
1199 int
1200 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1201 {
1202 struct proc *p = curproc;
1203 struct ifreq *ifr = (struct ifreq *) data;
1204 struct wihap_info *whi = &sc->wi_hostap_info;
1205 struct wihap_sta_info *sta;
1206 struct hostap_getall reqall;
1207 struct hostap_sta reqsta;
1208 struct hostap_sta stabuf;
1209 int s, error = 0, n, flag;
1210
1211 struct ieee80211_nodereq nr;
1212 struct ieee80211_nodereq_all *na;
1213
1214 if (!(sc->sc_ic.ic_if.if_flags & IFF_RUNNING))
1215 return ENODEV;
1216
1217 switch (command) {
1218 case SIOCHOSTAP_DEL:
1219 if ((error = suser(p, 0)))
1220 break;
1221 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1222 break;
1223 s = splnet();
1224 sta = wihap_sta_find(whi, reqsta.addr);
1225 if (sta == NULL)
1226 error = ENOENT;
1227 else {
1228
1229 if (sta->flags & WI_SIFLAGS_ASSOC)
1230 wihap_sta_disassoc(sc, sta->addr,
1231 IEEE80211_REASON_ASSOC_LEAVE);
1232
1233 if (sta->flags & WI_SIFLAGS_AUTHEN)
1234 wihap_sta_deauth(sc, sta->addr,
1235 IEEE80211_REASON_AUTH_LEAVE);
1236
1237 wihap_sta_delete(sta);
1238 }
1239 splx(s);
1240 break;
1241
1242 case SIOCHOSTAP_GET:
1243 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1244 break;
1245 s = splnet();
1246 sta = wihap_sta_find(whi, reqsta.addr);
1247 if (sta == NULL)
1248 error = ENOENT;
1249 else {
1250 reqsta.flags = sta->flags;
1251 reqsta.asid = sta->asid;
1252 reqsta.capinfo = sta->capinfo;
1253 reqsta.sig_info = sta->sig_info;
1254 reqsta.rates = sta->rates;
1255
1256 error = copyout(&reqsta, ifr->ifr_data,
1257 sizeof(reqsta));
1258 }
1259 splx(s);
1260 break;
1261
1262 case SIOCHOSTAP_ADD:
1263 if ((error = suser(p, 0)))
1264 break;
1265 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
1266 break;
1267 s = splnet();
1268 sta = wihap_sta_find(whi, reqsta.addr);
1269 if (sta != NULL) {
1270 error = EEXIST;
1271 splx(s);
1272 break;
1273 }
1274 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
1275 error = ENOSPC;
1276 splx(s);
1277 break;
1278 }
1279 sta = wihap_sta_alloc(sc, reqsta.addr);
1280 sta->flags = reqsta.flags;
1281 timeout_add(&sta->tmo, hz * whi->inactivity_time);
1282 splx(s);
1283 break;
1284
1285 case SIOCHOSTAP_SFLAGS:
1286 if ((error = suser(p, 0)))
1287 break;
1288 if ((error = copyin(ifr->ifr_data, &flag, sizeof(int))))
1289 break;
1290
1291 whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) |
1292 (flag & ~WIHAPFL_CANTCHANGE);
1293 break;
1294
1295 case SIOCHOSTAP_GFLAGS:
1296 flag = (int) whi->apflags;
1297 error = copyout(&flag, ifr->ifr_data, sizeof(int));
1298 break;
1299
1300 case SIOCHOSTAP_GETALL:
1301 if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall))))
1302 break;
1303
1304 reqall.nstations = whi->n_stations;
1305 n = 0;
1306 s = splnet();
1307 sta = TAILQ_FIRST(&whi->sta_list);
1308 while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
1309
1310 bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
1311 stabuf.asid = sta->asid;
1312 stabuf.flags = sta->flags;
1313 stabuf.capinfo = sta->capinfo;
1314 stabuf.sig_info = sta->sig_info;
1315 stabuf.rates = sta->rates;
1316
1317 error = copyout(&stabuf, (caddr_t) reqall.addr + n,
1318 sizeof(struct hostap_sta));
1319 if (error)
1320 break;
1321
1322 sta = TAILQ_NEXT(sta, list);
1323 n += sizeof(struct hostap_sta);
1324 }
1325 splx(s);
1326
1327 if (!error)
1328 error = copyout(&reqall, ifr->ifr_data,
1329 sizeof(reqall));
1330 break;
1331
1332 case SIOCG80211ALLNODES:
1333 na = (struct ieee80211_nodereq_all *)data;
1334 na->na_nodes = n = 0;
1335 s = splnet();
1336 sta = TAILQ_FIRST(&whi->sta_list);
1337 while (sta && na->na_size >=
1338 n + sizeof(struct ieee80211_nodereq)) {
1339 bzero(&nr, sizeof(nr));
1340 IEEE80211_ADDR_COPY(nr.nr_macaddr, sta->addr);
1341 IEEE80211_ADDR_COPY(nr.nr_bssid,
1342 &sc->sc_ic.ic_myaddr);
1343 nr.nr_channel = sc->wi_channel;
1344 nr.nr_chan_flags = IEEE80211_CHAN_B;
1345 nr.nr_associd = sta->asid;
1346 nr.nr_rssi = sta->sig_info >> 8;
1347 nr.nr_max_rssi = 0;
1348 nr.nr_capinfo = sta->capinfo;
1349 nr.nr_nrates = 0;
1350 if (sta->rates & WI_SUPPRATES_1M)
1351 nr.nr_rates[nr.nr_nrates++] = 2;
1352 if (sta->rates & WI_SUPPRATES_2M)
1353 nr.nr_rates[nr.nr_nrates++] = 4;
1354 if (sta->rates & WI_SUPPRATES_5M)
1355 nr.nr_rates[nr.nr_nrates++] = 11;
1356 if (sta->rates & WI_SUPPRATES_11M)
1357 nr.nr_rates[nr.nr_nrates++] = 22;
1358
1359 error = copyout(&nr, (caddr_t)na->na_node + n,
1360 sizeof(struct ieee80211_nodereq));
1361 if (error)
1362 break;
1363 n += sizeof(struct ieee80211_nodereq);
1364 na->na_nodes++;
1365 sta = TAILQ_NEXT(sta, list);
1366 }
1367 splx(s);
1368 break;
1369
1370 default:
1371 printf("wihap_ioctl: i shouldn't get other ioctls!\n");
1372 error = EINVAL;
1373 }
1374
1375 return (error);
1376 }
1377
1378 #else
1379 void
1380 wihap_init(struct wi_softc *sc)
1381 {
1382 return;
1383 }
1384
1385 void
1386 wihap_shutdown(struct wi_softc *sc)
1387 {
1388 return;
1389 }
1390
1391 void
1392 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1393 {
1394 return;
1395 }
1396
1397 int
1398 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
1399 {
1400 return (0);
1401 }
1402
1403 int
1404 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
1405 {
1406 return (EINVAL);
1407 }
1408
1409 int
1410 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
1411 {
1412 return (0);
1413 }
1414 #endif