Annotation of sys/dev/ic/if_wi_hostap.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_wi_hostap.c,v 1.37 2006/11/26 19:46:28 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 2002
5: * Thomas Skibo <skibo@pacbell.net>. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Thomas Skibo.
18: * 4. Neither the name of the author nor the names of any co-contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32: * THE POSSIBILITY OF SUCH DAMAGE.
33: *
34: */
35:
36: /* This is experimental Host AP software for Prism 2 802.11b interfaces.
37: *
38: * Much of this is based upon the "Linux Host AP driver Host AP driver
39: * for Intersil Prism2" by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>.
40: */
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/sockio.h>
45: #include <sys/mbuf.h>
46: #include <sys/malloc.h>
47: #include <sys/kernel.h>
48: #include <sys/timeout.h>
49: #include <sys/proc.h>
50: #include <sys/ucred.h>
51: #include <sys/socket.h>
52: #include <sys/queue.h>
53: #include <sys/syslog.h>
54: #include <sys/sysctl.h>
55: #include <sys/device.h>
56:
57: #include <machine/bus.h>
58:
59: #include <net/if.h>
60: #include <net/if_arp.h>
61: #include <net/if_dl.h>
62: #include <net/if_media.h>
63: #include <net/if_types.h>
64:
65: #include <netinet/in.h>
66: #include <netinet/in_systm.h>
67: #include <netinet/in_var.h>
68: #include <netinet/ip.h>
69: #include <netinet/if_ether.h>
70:
71: #include <net80211/ieee80211_var.h>
72: #include <net80211/ieee80211_ioctl.h>
73:
74: #include <dev/rndvar.h>
75:
76: #include <dev/ic/if_wireg.h>
77: #include <dev/ic/if_wi_ieee.h>
78: #include <dev/ic/if_wivar.h>
79:
80: void wihap_timeout(void *v);
81: void wihap_sta_timeout(void *v);
82: struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr);
83: void wihap_sta_delete(struct wihap_sta_info *sta);
84: struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr);
85: int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]);
86: void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
87: caddr_t pkt, int len);
88: void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[],
89: u_int16_t reason);
90: void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
91: caddr_t pkt, int len);
92: void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
93: caddr_t pkt, int len);
94: void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[],
95: u_int16_t reason);
96: void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
97: caddr_t pkt, int len);
98:
99: #ifndef SMALL_KERNEL
100: /*
101: * take_hword()
102: *
103: * Used for parsing management frames. The pkt pointer and length
104: * variables are updated after the value is removed.
105: */
106: static __inline u_int16_t
107: take_hword(caddr_t *ppkt, int *plen)
108: {
109: u_int16_t s = letoh16(* (u_int16_t *) *ppkt);
110: *ppkt += sizeof(u_int16_t);
111: *plen -= sizeof(u_int16_t);
112: return s;
113: }
114:
115: /* take_tlv()
116: *
117: * Parse out TLV element from a packet, check for underflow of packet
118: * or overflow of buffer, update pkt/len.
119: */
120: static int
121: take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen)
122: {
123: u_int8_t id, len;
124:
125: if (*plen < 2)
126: return -1;
127:
128: id = ((u_int8_t *)*ppkt)[0];
129: len = ((u_int8_t *)*ppkt)[1];
130:
131: if (id != id_expect || *plen < len+2 || maxlen < len)
132: return -1;
133:
134: bcopy(*ppkt + 2, dst, len);
135: *plen -= 2 + len;
136: *ppkt += 2 + len;
137:
138: return (len);
139: }
140:
141: /* put_hword()
142: * Put half-word element into management frames.
143: */
144: static __inline void
145: put_hword(caddr_t *ppkt, u_int16_t s)
146: {
147: * (u_int16_t *) *ppkt = htole16(s);
148: *ppkt += sizeof(u_int16_t);
149: }
150:
151: /* put_tlv()
152: * Put TLV elements into management frames.
153: */
154: static void
155: put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len)
156: {
157: (*ppkt)[0] = id;
158: (*ppkt)[1] = len;
159: bcopy(src, (*ppkt) + 2, len);
160: *ppkt += 2 + len;
161: }
162:
163: static int
164: put_rates(caddr_t *ppkt, u_int16_t rates)
165: {
166: u_int8_t ratebuf[8];
167: int len = 0;
168:
169: if (rates & WI_SUPPRATES_1M)
170: ratebuf[len++] = 0x82;
171: if (rates & WI_SUPPRATES_2M)
172: ratebuf[len++] = 0x84;
173: if (rates & WI_SUPPRATES_5M)
174: ratebuf[len++] = 0x8b;
175: if (rates & WI_SUPPRATES_11M)
176: ratebuf[len++] = 0x96;
177:
178: put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len);
179: return len;
180: }
181:
182: /* wihap_init()
183: *
184: * Initialize host AP data structures. Called even if port type is
185: * not AP. Caller MUST raise to splnet().
186: */
187: void
188: wihap_init(struct wi_softc *sc)
189: {
190: int i;
191: struct wihap_info *whi = &sc->wi_hostap_info;
192:
193: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
194: printf("wihap_init: sc=%p whi=%p\n", sc, whi);
195:
196: bzero(whi, sizeof(struct wihap_info));
197:
198: if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
199: return;
200:
201: whi->apflags = WIHAPFL_ACTIVE;
202:
203: TAILQ_INIT(&whi->sta_list);
204: for (i = 0; i < WI_STA_HASH_SIZE; i++)
205: LIST_INIT(&whi->sta_hash[i]);
206:
207: whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME;
208: timeout_set(&whi->tmo, wihap_timeout, sc);
209: }
210:
211: /* wihap_sta_disassoc()
212: *
213: * Send a disassociation frame to a specified station.
214: */
215: void
216: wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
217: {
218: struct wi_80211_hdr *resp_hdr;
219: caddr_t pkt;
220:
221: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
222: printf("Sending disassoc to sta %s\n", ether_sprintf(sta_addr));
223:
224: /* Send disassoc packet. */
225: resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
226: bzero(resp_hdr, sizeof(struct wi_80211_hdr));
227: resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS;
228: pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
229:
230: bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
231: bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
232: bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
233:
234: put_hword(&pkt, reason);
235:
236: wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
237: 2 + sizeof(struct wi_80211_hdr));
238: }
239:
240: /* wihap_sta_deauth()
241: *
242: * Send a deauthentication message to a specified station.
243: */
244: void
245: wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
246: {
247: struct wi_80211_hdr *resp_hdr;
248: caddr_t pkt;
249:
250: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
251: printf("Sending deauth to sta %s\n", ether_sprintf(sta_addr));
252:
253: /* Send deauth packet. */
254: resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
255: bzero(resp_hdr, sizeof(struct wi_80211_hdr));
256: resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH);
257: pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
258:
259: bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
260: bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
261: bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
262:
263: put_hword(&pkt, reason);
264:
265: wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
266: 2 + sizeof(struct wi_80211_hdr));
267: }
268:
269: /* wihap_shutdown()
270: *
271: * Disassociate all stations and free up data structures.
272: */
273: void
274: wihap_shutdown(struct wi_softc *sc)
275: {
276: struct wihap_info *whi = &sc->wi_hostap_info;
277: struct wihap_sta_info *sta, *next;
278: int i, s;
279:
280: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
281: printf("wihap_shutdown: sc=%p whi=%p\n", sc, whi);
282:
283: if (!(whi->apflags & WIHAPFL_ACTIVE))
284: return;
285: whi->apflags = 0;
286:
287: s = splnet();
288:
289: /* Disable wihap inactivity timer. */
290: timeout_del(&whi->tmo);
291:
292: /* Delete all stations from the list. */
293: for (sta = TAILQ_FIRST(&whi->sta_list);
294: sta != TAILQ_END(&whi->sta_list); sta = next) {
295: timeout_del(&sta->tmo);
296: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
297: printf("wihap_shutdown: FREE(sta=%p)\n", sta);
298: next = TAILQ_NEXT(sta, list);
299: if (sta->challenge)
300: FREE(sta->challenge, M_TEMP);
301: FREE(sta, M_DEVBUF);
302: }
303: TAILQ_INIT(&whi->sta_list);
304:
305: /* Broadcast disassoc and deauth to all the stations. */
306: if (sc->wi_flags & WI_FLAGS_ATTACHED) {
307: for (i = 0; i < 5; i++) {
308: wihap_sta_disassoc(sc, etherbroadcastaddr,
309: IEEE80211_REASON_ASSOC_LEAVE);
310: wihap_sta_deauth(sc, etherbroadcastaddr,
311: IEEE80211_REASON_AUTH_LEAVE);
312: DELAY(50);
313: }
314: }
315:
316: splx(s);
317: }
318:
319: /* sta_hash_func()
320: * Hash function for finding stations from ethernet address.
321: */
322: static __inline int
323: sta_hash_func(u_int8_t addr[])
324: {
325: return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE);
326: }
327:
328: /* addr_cmp(): Maybe this is a faster way to compare addresses? */
329: static __inline int
330: addr_cmp(u_int8_t a[], u_int8_t b[])
331: {
332: return (*(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4) &&
333: *(u_int16_t *)(a + 2) == *(u_int16_t *)(b + 2) &&
334: *(u_int16_t *)(a ) == *(u_int16_t *)(b));
335: }
336:
337: /* wihap_sta_movetail(): move sta to the tail of the station list in whi */
338: static __inline void
339: wihap_sta_movetail(struct wihap_info *whi, struct wihap_sta_info *sta)
340: {
341: TAILQ_REMOVE(&whi->sta_list, sta, list);
342: sta->flags &= ~WI_SIFLAGS_DEAD;
343: TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
344: }
345:
346: void
347: wihap_timeout(void *v)
348: {
349: struct wi_softc *sc = v;
350: struct wihap_info *whi = &sc->wi_hostap_info;
351: struct wihap_sta_info *sta, *next;
352: int i, s;
353:
354: s = splnet();
355:
356: for (i = 10, sta = TAILQ_FIRST(&whi->sta_list);
357: i != 0 && sta != TAILQ_END(&whi->sta_list) &&
358: (sta->flags & WI_SIFLAGS_DEAD); i--, sta = next) {
359: next = TAILQ_NEXT(sta, list);
360: if (timeout_pending(&sta->tmo)) {
361: /* Became alive again, move to end of list. */
362: wihap_sta_movetail(whi, sta);
363: } else if (sta->flags & WI_SIFLAGS_ASSOC) {
364: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
365: printf("wihap_timeout: disassoc due to inactivity: %s\n",
366: ether_sprintf(sta->addr));
367:
368: /* Disassoc station. */
369: wihap_sta_disassoc(sc, sta->addr,
370: IEEE80211_REASON_ASSOC_EXPIRE);
371: sta->flags &= ~WI_SIFLAGS_ASSOC;
372:
373: /*
374: * Move to end of the list and reset station timeout.
375: * We do this to make sure we don't get deauthed
376: * until inactivity_time seconds have passed.
377: */
378: wihap_sta_movetail(whi, sta);
379: timeout_add(&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: /* Deauthenticate station. */
386: wihap_sta_deauth(sc, sta->addr,
387: IEEE80211_REASON_AUTH_EXPIRE);
388: sta->flags &= ~WI_SIFLAGS_AUTHEN;
389:
390: /* Delete the station if it's not permanent. */
391: if (sta->flags & WI_SIFLAGS_PERM)
392: wihap_sta_movetail(whi, sta);
393: else
394: wihap_sta_delete(sta);
395: }
396: }
397:
398: /* Restart the timeout if there are still dead stations left. */
399: sta = TAILQ_FIRST(&whi->sta_list);
400: if (sta != NULL && (sta->flags & WI_SIFLAGS_DEAD))
401: timeout_add(&whi->tmo, 1); /* still work left, requeue */
402:
403: splx(s);
404: }
405:
406: void
407: wihap_sta_timeout(void *v)
408: {
409: struct wihap_sta_info *sta = v;
410: struct wi_softc *sc = sta->sc;
411: struct wihap_info *whi = &sc->wi_hostap_info;
412: int s;
413:
414: s = splnet();
415:
416: /* Mark sta as dead and move it to the head of the list. */
417: TAILQ_REMOVE(&whi->sta_list, sta, list);
418: sta->flags |= WI_SIFLAGS_DEAD;
419: TAILQ_INSERT_HEAD(&whi->sta_list, sta, list);
420:
421: /* Add wihap timeout if we have not already done so. */
422: if (!timeout_pending(&whi->tmo))
423: timeout_add(&whi->tmo, hz / 10);
424:
425: splx(s);
426: }
427:
428: /* wihap_sta_delete()
429: * Delete a single station and free up its data structure.
430: * Caller must raise to splnet().
431: */
432: void
433: wihap_sta_delete(struct wihap_sta_info *sta)
434: {
435: struct wi_softc *sc = sta->sc;
436: struct wihap_info *whi = &sc->wi_hostap_info;
437: int i = sta->asid - 0xc001;
438:
439: timeout_del(&sta->tmo);
440:
441: whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf));
442:
443: TAILQ_REMOVE(&whi->sta_list, sta, list);
444: LIST_REMOVE(sta, hash);
445: if (sta->challenge)
446: FREE(sta->challenge, M_TEMP);
447: FREE(sta, M_DEVBUF);
448: whi->n_stations--;
449: }
450:
451: /* wihap_sta_alloc()
452: *
453: * Create a new station data structure and put it in the list
454: * and hash table.
455: */
456: struct wihap_sta_info *
457: wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr)
458: {
459: struct wihap_info *whi = &sc->wi_hostap_info;
460: struct wihap_sta_info *sta;
461: int i, hash = sta_hash_func(addr);
462:
463: /* Allocate structure. */
464: 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 *
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: /* wihap_auth_req()
546: *
547: * Handle incoming authentication request.
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: /* 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_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: /* Ignore vendor private tlv (if any). */
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: /* Find or create station info. */
592: sta = wihap_sta_find(whi, rxfrm->wi_addr2);
593: if (sta == NULL) {
594:
595: /* Are we allowing new stations?
596: */
597: if (whi->apflags & WIHAPFL_MAC_FILT) {
598: status = IEEE80211_STATUS_OTHER; /* XXX */
599: goto fail;
600: }
601:
602: /* Check for too many stations.
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: /* Create new station. */
613: s = splnet();
614: sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
615: splx(s);
616: if (sta == NULL) {
617: /* Out of memory! */
618: status = IEEE80211_STATUS_TOOMANY;
619: goto fail;
620: }
621: }
622: timeout_add(&sta->tmo, hz * whi->inactivity_time);
623:
624: /* Note: it's okay to leave the station info structure around
625: * if the authen fails. It'll be timed out eventually.
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: /* Create a challenge frame. */
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: } /* switch (seq) */
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: } /* switch (algo) */
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: /* Send response. */
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: /* wihap_assoc_req()
723: *
724: * Handle incoming association and reassociation requests.
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: /* Pull out request parameters. */
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: /* Eat the MAC address of the current AP */
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: /* If SSID doesn't match, simply drop. */
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: /* Is this station authenticated yet? */
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: /* Check supported rates against ours. */
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: /* Check capinfo.
798: * Check for ESS, not IBSS.
799: * Check WEP/PRIVACY flags match.
800: * Refuse stations requesting to be put on CF-polling list.
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: /* Use ASID is allocated by whi_sta_alloc(). */
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: /* Send response. */
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: /* wihap_deauth_req()
863: *
864: * Handle deauthentication requests. Delete the station.
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: /* wihap_disassoc_req()
890: *
891: * Handle disassociation requests. Just reset the assoc flag.
892: * We'll free up the station resources when we get a deauth
893: * request or when it times out.
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: * If station is not authenticated, send deauthentication
917: * frame.
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: /* wihap_debug_frame_type()
928: *
929: * Print out frame type. Used in early debugging.
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: * wihap_mgmt_input:
990: *
991: * Called for each management frame received in host ap mode.
992: * wihap_mgmt_input() is expected to free the mbuf.
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: /* any of the following will mess w/ the station list */
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: /* wihap_sta_is_assoc()
1047: *
1048: * Determine if a station is assoc'ed. Update its activity
1049: * counter as a side-effect.
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: /* Keep it active. */
1059: timeout_add(&sta->tmo, hz * whi->inactivity_time);
1060: return (1);
1061: }
1062:
1063: return (0);
1064: }
1065:
1066: /* wihap_check_tx()
1067: *
1068: * Determine if a station is assoc'ed, get its tx rate, and update
1069: * its activity.
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; /* XXX: multicast rate? */
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: /* Keep it active. */
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: * wihap_data_input()
1099: *
1100: * Handle all data input on interface when in Host AP mode.
1101: * Some packets are destined for this machine, others are
1102: * repeated to other stations.
1103: *
1104: * If wihap_data_input() returns a non-zero, it has processed
1105: * the packet and will free the mbuf.
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: * TODS flag must be set. However, Lucent cards set NULLFUNC but
1118: * not TODS when probing an AP to see if it is alive after it has
1119: * been down for a while. We accept these probe packets and send a
1120: * disassoc packet later on if the station is not already associated.
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: /* Check BSSID. (Is this necessary?) */
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: /* Find source station. */
1143: sta = wihap_sta_find(whi, rxfrm->wi_addr2);
1144:
1145: /* Source station must be associated. */
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: /* Repeat this packet to BSS? */
1163: mcast = (rxfrm->wi_addr3[0] & 0x01) != 0;
1164: if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) {
1165:
1166: /* If it's multicast, make a copy.
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; /* XXX */
1173: }
1174:
1175: /* Queue up for repeating.
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: /* wihap_ioctl()
1196: *
1197: * Handle Host AP specific ioctls. Called from wi_ioctl().
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: /* Disassociate station. */
1229: if (sta->flags & WI_SIFLAGS_ASSOC)
1230: wihap_sta_disassoc(sc, sta->addr,
1231: IEEE80211_REASON_ASSOC_LEAVE);
1232: /* Deauth station. */
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
CVSweb