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