Annotation of sys/dev/ic/if_wi_hostap.c, Revision 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