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