1 /* $OpenBSD: if_wi_hostap.c,v 1.41 2008/10/15 19:12:19 blambert 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_sec(&sta->tmo, 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 sta = malloc(sizeof(*sta), M_DEVBUF, M_NOWAIT | M_ZERO); 465 if (sta == NULL) 466 return (NULL); 467 468 /* Allocate an ASID. */ 469 i=hash<<4; 470 while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf))) 471 i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1); 472 whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf)); 473 sta->asid = 0xc001 + i; 474 475 /* Insert in list and hash list. */ 476 TAILQ_INSERT_TAIL(&whi->sta_list, sta, list); 477 LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash); 478 479 sta->sc = sc; 480 whi->n_stations++; 481 bcopy(addr, &sta->addr, ETHER_ADDR_LEN); 482 timeout_set(&sta->tmo, wihap_sta_timeout, sta); 483 timeout_add_sec(&sta->tmo, whi->inactivity_time); 484 485 return (sta); 486 } 487 488 /* wihap_sta_find() 489 * 490 * Find station structure given address. 491 */ 492 struct wihap_sta_info * 493 wihap_sta_find(struct wihap_info *whi, u_int8_t *addr) 494 { 495 int i; 496 struct wihap_sta_info *sta; 497 498 i = sta_hash_func(addr); 499 LIST_FOREACH(sta, &whi->sta_hash[i], hash) 500 if (addr_cmp(addr, sta->addr)) 501 return sta; 502 503 return (NULL); 504 } 505 506 static __inline int 507 wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len) 508 { 509 struct wi_softc *sc = sta->sc; 510 int i; 511 512 sta->rates = 0; 513 sta->tx_max_rate = 0; 514 for (i = 0; i < rates_len; i++) 515 switch (rates[i] & 0x7f) { 516 case 0x02: 517 sta->rates |= WI_SUPPRATES_1M; 518 break; 519 case 0x04: 520 sta->rates |= WI_SUPPRATES_2M; 521 if (sta->tx_max_rate < 1) 522 sta->tx_max_rate = 1; 523 break; 524 case 0x0b: 525 sta->rates |= WI_SUPPRATES_5M; 526 if (sta->tx_max_rate < 2) 527 sta->tx_max_rate = 2; 528 break; 529 case 0x16: 530 sta->rates |= WI_SUPPRATES_11M; 531 sta->tx_max_rate = 3; 532 break; 533 } 534 535 sta->rates &= sc->wi_supprates; 536 sta->tx_curr_rate = sta->tx_max_rate; 537 538 return (sta->rates == 0 ? -1 : 0); 539 } 540 541 542 /* wihap_auth_req() 543 * 544 * Handle incoming authentication request. 545 */ 546 void 547 wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, 548 caddr_t pkt, int len) 549 { 550 struct wihap_info *whi = &sc->wi_hostap_info; 551 struct wihap_sta_info *sta; 552 int i, s; 553 554 u_int16_t algo; 555 u_int16_t seq; 556 u_int16_t status; 557 int challenge_len; 558 u_int32_t challenge[32]; 559 560 struct wi_80211_hdr *resp_hdr; 561 562 if (len < 6) { 563 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 564 printf("wihap_auth_req: station %s short request\n", 565 ether_sprintf(rxfrm->wi_addr2)); 566 return; 567 } 568 569 /* Break open packet. */ 570 algo = take_hword(&pkt, &len); 571 seq = take_hword(&pkt, &len); 572 status = take_hword(&pkt, &len); 573 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 574 printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n", 575 ether_sprintf(rxfrm->wi_addr2), algo, seq); 576 577 /* Ignore vendor private tlv (if any). */ 578 (void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge, 579 sizeof(challenge)); 580 581 challenge_len = 0; 582 if (len > 0 && (challenge_len = take_tlv(&pkt, &len, 583 IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) { 584 status = IEEE80211_STATUS_CHALLENGE; 585 goto fail; 586 } 587 588 /* Find or create station info. */ 589 sta = wihap_sta_find(whi, rxfrm->wi_addr2); 590 if (sta == NULL) { 591 592 /* Are we allowing new stations? 593 */ 594 if (whi->apflags & WIHAPFL_MAC_FILT) { 595 status = IEEE80211_STATUS_OTHER; /* XXX */ 596 goto fail; 597 } 598 599 /* Check for too many stations. 600 */ 601 if (whi->n_stations >= WIHAP_MAX_STATIONS) { 602 status = IEEE80211_STATUS_TOOMANY; 603 goto fail; 604 } 605 606 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 607 printf("wihap_auth_req: new station\n"); 608 609 /* Create new station. */ 610 s = splnet(); 611 sta = wihap_sta_alloc(sc, rxfrm->wi_addr2); 612 splx(s); 613 if (sta == NULL) { 614 /* Out of memory! */ 615 status = IEEE80211_STATUS_TOOMANY; 616 goto fail; 617 } 618 } 619 timeout_add_sec(&sta->tmo, whi->inactivity_time); 620 621 /* Note: it's okay to leave the station info structure around 622 * if the authen fails. It'll be timed out eventually. 623 */ 624 switch (algo) { 625 case IEEE80211_AUTH_ALG_OPEN: 626 if (sc->wi_authtype != IEEE80211_AUTH_OPEN) { 627 status = IEEE80211_STATUS_ALG; 628 goto fail; 629 } 630 if (seq != 1) { 631 status = IEEE80211_STATUS_SEQUENCE; 632 goto fail; 633 } 634 challenge_len = 0; 635 sta->flags |= WI_SIFLAGS_AUTHEN; 636 break; 637 case IEEE80211_AUTH_ALG_SHARED: 638 if (sc->wi_authtype != IEEE80211_AUTH_SHARED) { 639 status = IEEE80211_STATUS_ALG; 640 goto fail; 641 } 642 switch (seq) { 643 case 1: 644 /* Create a challenge frame. */ 645 if (!sta->challenge) { 646 sta->challenge = malloc(128, M_TEMP, M_NOWAIT); 647 if (!sta->challenge) 648 return; 649 } 650 for (i = 0; i < 32; i++) 651 challenge[i] = sta->challenge[i] = 652 arc4random(); 653 654 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 655 printf("\tchallenge: 0x%x 0x%x ...\n", 656 challenge[0], challenge[1]); 657 challenge_len = 128; 658 break; 659 case 3: 660 if (challenge_len != 128 || !sta->challenge || 661 !(letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) { 662 status = IEEE80211_STATUS_CHALLENGE; 663 goto fail; 664 } 665 666 for (i=0; i<32; i++) 667 if (sta->challenge[i] != challenge[i]) { 668 status = IEEE80211_STATUS_CHALLENGE; 669 goto fail; 670 } 671 672 sta->flags |= WI_SIFLAGS_AUTHEN; 673 free(sta->challenge, M_TEMP); 674 sta->challenge = NULL; 675 challenge_len = 0; 676 break; 677 default: 678 status = IEEE80211_STATUS_SEQUENCE; 679 goto fail; 680 } /* switch (seq) */ 681 break; 682 default: 683 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 684 printf("wihap_auth_req: algorithm unsupported: 0x%x\n", 685 algo); 686 status = IEEE80211_STATUS_ALG; 687 goto fail; 688 } /* switch (algo) */ 689 690 status = IEEE80211_STATUS_SUCCESS; 691 692 fail: 693 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 694 printf("wihap_auth_req: returns status=0x%x\n", status); 695 696 /* Send response. */ 697 resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf; 698 bzero(resp_hdr, sizeof(struct wi_80211_hdr)); 699 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH); 700 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); 701 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN); 702 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN); 703 704 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr); 705 put_hword(&pkt, algo); 706 put_hword(&pkt, seq + 1); 707 put_hword(&pkt, status); 708 if (challenge_len > 0) 709 put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE, 710 challenge, challenge_len); 711 712 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf, 713 6 + sizeof(struct wi_80211_hdr) + 714 (challenge_len > 0 ? challenge_len + 2 : 0)); 715 } 716 717 718 /* wihap_assoc_req() 719 * 720 * Handle incoming association and reassociation requests. 721 */ 722 void 723 wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, 724 caddr_t pkt, int len) 725 { 726 struct wihap_info *whi = &sc->wi_hostap_info; 727 struct wihap_sta_info *sta; 728 struct wi_80211_hdr *resp_hdr; 729 u_int16_t capinfo; 730 u_int16_t lstintvl; 731 u_int8_t rates[12]; 732 int ssid_len, rates_len; 733 struct ieee80211_nwid ssid; 734 u_int16_t status; 735 u_int16_t asid = 0; 736 737 if (len < 8) 738 return; 739 740 /* Pull out request parameters. */ 741 capinfo = take_hword(&pkt, &len); 742 lstintvl = take_hword(&pkt, &len); 743 744 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) == 745 htole16(WI_STYPE_MGMT_REASREQ)) { 746 if (len < 6) 747 return; 748 /* Eat the MAC address of the current AP */ 749 take_hword(&pkt, &len); 750 take_hword(&pkt, &len); 751 take_hword(&pkt, &len); 752 } 753 754 if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID, 755 ssid.i_nwid, sizeof(ssid))) < 0) 756 return; 757 ssid.i_len = ssid_len; 758 if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES, 759 rates, sizeof(rates))) < 0) 760 return; 761 762 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 763 printf("wihap_assoc_req: from station %s\n", 764 ether_sprintf(rxfrm->wi_addr2)); 765 766 /* If SSID doesn't match, simply drop. */ 767 if (sc->wi_net_name.i_len != ssid.i_len || 768 memcmp(sc->wi_net_name.i_nwid, ssid.i_nwid, ssid.i_len)) { 769 770 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 771 printf("wihap_assoc_req: bad ssid: '%.*s' != '%.*s'\n", 772 ssid.i_len, ssid.i_nwid, sc->wi_net_name.i_len, 773 sc->wi_net_name.i_nwid); 774 return; 775 } 776 777 /* Is this station authenticated yet? */ 778 sta = wihap_sta_find(whi, rxfrm->wi_addr2); 779 if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) { 780 wihap_sta_deauth(sc, rxfrm->wi_addr2, 781 IEEE80211_REASON_NOT_AUTHED); 782 return; 783 } 784 785 /* Check supported rates against ours. */ 786 if (wihap_check_rates(sta, rates, rates_len) < 0) { 787 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 788 printf("wihap_assoc_req: rates mismatch.\n"); 789 status = IEEE80211_STATUS_BASIC_RATE; 790 goto fail; 791 } 792 793 /* Check capinfo. 794 * Check for ESS, not IBSS. 795 * Check WEP/PRIVACY flags match. 796 * Refuse stations requesting to be put on CF-polling list. 797 */ 798 sta->capinfo = capinfo; 799 status = IEEE80211_STATUS_CAPINFO; 800 if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) != 801 IEEE80211_CAPINFO_ESS) { 802 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 803 printf("wihap_assoc_req: capinfo: not ESS: " 804 "capinfo=0x%x\n", capinfo); 805 goto fail; 806 807 } 808 if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) || 809 (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) { 810 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 811 printf("wihap_assoc_req: WEP flag mismatch: " 812 "capinfo=0x%x\n", capinfo); 813 goto fail; 814 } 815 if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE | 816 IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) { 817 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 818 printf("wihap_assoc_req: polling not supported: " 819 "capinfo=0x%x\n", capinfo); 820 goto fail; 821 } 822 823 /* Use ASID is allocated by whi_sta_alloc(). */ 824 asid = sta->asid; 825 826 if (sta->flags & WI_SIFLAGS_ASSOC) { 827 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 828 printf("wihap_assoc_req: already assoc'ed?\n"); 829 } 830 831 sta->flags |= WI_SIFLAGS_ASSOC; 832 timeout_add_sec(&sta->tmo, whi->inactivity_time); 833 status = IEEE80211_STATUS_SUCCESS; 834 835 fail: 836 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 837 printf("wihap_assoc_req: returns status=0x%x\n", status); 838 839 /* Send response. */ 840 resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf; 841 bzero(resp_hdr, sizeof(struct wi_80211_hdr)); 842 resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP); 843 pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr); 844 845 bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); 846 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN); 847 bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN); 848 849 put_hword(&pkt, capinfo); 850 put_hword(&pkt, status); 851 put_hword(&pkt, asid); 852 rates_len = put_rates(&pkt, sc->wi_supprates); 853 854 wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf, 855 8 + rates_len + sizeof(struct wi_80211_hdr)); 856 } 857 858 /* wihap_deauth_req() 859 * 860 * Handle deauthentication requests. Delete the station. 861 */ 862 void 863 wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, 864 caddr_t pkt, int len) 865 { 866 struct wihap_info *whi = &sc->wi_hostap_info; 867 struct wihap_sta_info *sta; 868 u_int16_t reason; 869 870 if (len<2) 871 return; 872 873 reason = take_hword(&pkt, &len); 874 875 sta = wihap_sta_find(whi, rxfrm->wi_addr2); 876 if (sta == NULL) { 877 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 878 printf("wihap_deauth_req: unknown station: %s\n", 879 ether_sprintf(rxfrm->wi_addr2)); 880 } 881 else 882 wihap_sta_delete(sta); 883 } 884 885 /* wihap_disassoc_req() 886 * 887 * Handle disassociation requests. Just reset the assoc flag. 888 * We'll free up the station resources when we get a deauth 889 * request or when it times out. 890 */ 891 void 892 wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, 893 caddr_t pkt, int len) 894 { 895 struct wihap_info *whi = &sc->wi_hostap_info; 896 struct wihap_sta_info *sta; 897 u_int16_t reason; 898 899 if (len < 2) 900 return; 901 902 reason = take_hword(&pkt, &len); 903 904 sta = wihap_sta_find(whi, rxfrm->wi_addr2); 905 if (sta == NULL) { 906 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 907 printf("wihap_disassoc_req: unknown station: %s\n", 908 ether_sprintf(rxfrm->wi_addr2)); 909 } 910 else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) { 911 /* 912 * If station is not authenticated, send deauthentication 913 * frame. 914 */ 915 wihap_sta_deauth(sc, rxfrm->wi_addr2, 916 IEEE80211_REASON_NOT_AUTHED); 917 return; 918 } 919 else 920 sta->flags &= ~WI_SIFLAGS_ASSOC; 921 } 922 923 /* wihap_debug_frame_type() 924 * 925 * Print out frame type. Used in early debugging. 926 */ 927 static __inline void 928 wihap_debug_frame_type(struct wi_frame *rxfrm) 929 { 930 printf("wihap_mgmt_input: len=%d ", letoh16(rxfrm->wi_dat_len)); 931 932 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) == 933 htole16(WI_FTYPE_MGMT)) { 934 935 printf("MGMT: "); 936 937 switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { 938 case WI_STYPE_MGMT_ASREQ: 939 printf("assoc req: \n"); 940 break; 941 case WI_STYPE_MGMT_ASRESP: 942 printf("assoc resp: \n"); 943 break; 944 case WI_STYPE_MGMT_REASREQ: 945 printf("reassoc req: \n"); 946 break; 947 case WI_STYPE_MGMT_REASRESP: 948 printf("reassoc resp: \n"); 949 break; 950 case WI_STYPE_MGMT_PROBEREQ: 951 printf("probe req: \n"); 952 break; 953 case WI_STYPE_MGMT_PROBERESP: 954 printf("probe resp: \n"); 955 break; 956 case WI_STYPE_MGMT_BEACON: 957 printf("beacon: \n"); 958 break; 959 case WI_STYPE_MGMT_ATIM: 960 printf("ann traf ind \n"); 961 break; 962 case WI_STYPE_MGMT_DISAS: 963 printf("disassociation: \n"); 964 break; 965 case WI_STYPE_MGMT_AUTH: 966 printf("auth: \n"); 967 break; 968 case WI_STYPE_MGMT_DEAUTH: 969 printf("deauth: \n"); 970 break; 971 default: 972 printf("unknown (stype=0x%x)\n", 973 letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE); 974 } 975 976 } 977 else { 978 printf("ftype=0x%x (ctl=0x%x)\n", 979 letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE, 980 letoh16(rxfrm->wi_frame_ctl)); 981 } 982 } 983 984 /* 985 * wihap_mgmt_input: 986 * 987 * Called for each management frame received in host ap mode. 988 * wihap_mgmt_input() is expected to free the mbuf. 989 */ 990 void 991 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) 992 { 993 caddr_t pkt; 994 int s, len; 995 996 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG) 997 wihap_debug_frame_type(rxfrm); 998 999 pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW; 1000 len = m->m_len - WI_802_11_OFFSET_RAW; 1001 1002 if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) == 1003 htole16(WI_FTYPE_MGMT)) { 1004 1005 /* any of the following will mess w/ the station list */ 1006 s = splsoftclock(); 1007 switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { 1008 case WI_STYPE_MGMT_ASREQ: 1009 wihap_assoc_req(sc, rxfrm, pkt, len); 1010 break; 1011 case WI_STYPE_MGMT_ASRESP: 1012 break; 1013 case WI_STYPE_MGMT_REASREQ: 1014 wihap_assoc_req(sc, rxfrm, pkt, len); 1015 break; 1016 case WI_STYPE_MGMT_REASRESP: 1017 break; 1018 case WI_STYPE_MGMT_PROBEREQ: 1019 break; 1020 case WI_STYPE_MGMT_PROBERESP: 1021 break; 1022 case WI_STYPE_MGMT_BEACON: 1023 break; 1024 case WI_STYPE_MGMT_ATIM: 1025 break; 1026 case WI_STYPE_MGMT_DISAS: 1027 wihap_disassoc_req(sc, rxfrm, pkt, len); 1028 break; 1029 case WI_STYPE_MGMT_AUTH: 1030 wihap_auth_req(sc, rxfrm, pkt, len); 1031 break; 1032 case WI_STYPE_MGMT_DEAUTH: 1033 wihap_deauth_req(sc, rxfrm, pkt, len); 1034 break; 1035 } 1036 splx(s); 1037 } 1038 1039 m_freem(m); 1040 } 1041 1042 /* wihap_sta_is_assoc() 1043 * 1044 * Determine if a station is assoc'ed. Update its activity 1045 * counter as a side-effect. 1046 */ 1047 int 1048 wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]) 1049 { 1050 struct wihap_sta_info *sta; 1051 1052 sta = wihap_sta_find(whi, addr); 1053 if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { 1054 /* Keep it active. */ 1055 timeout_add_sec(&sta->tmo, whi->inactivity_time); 1056 return (1); 1057 } 1058 1059 return (0); 1060 } 1061 1062 /* wihap_check_tx() 1063 * 1064 * Determine if a station is assoc'ed, get its tx rate, and update 1065 * its activity. 1066 */ 1067 int 1068 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate) 1069 { 1070 struct wihap_sta_info *sta; 1071 static u_int8_t txratetable[] = { 10, 20, 55, 110 }; 1072 int s; 1073 1074 if (addr[0] & 0x01) { 1075 *txrate = 0; /* XXX: multicast rate? */ 1076 return (1); 1077 } 1078 1079 s = splsoftclock(); 1080 sta = wihap_sta_find(whi, addr); 1081 if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { 1082 /* Keep it active. */ 1083 timeout_add_sec(&sta->tmo, whi->inactivity_time); 1084 *txrate = txratetable[sta->tx_curr_rate]; 1085 splx(s); 1086 return (1); 1087 } 1088 splx(s); 1089 1090 return (0); 1091 } 1092 1093 /* 1094 * wihap_data_input() 1095 * 1096 * Handle all data input on interface when in Host AP mode. 1097 * Some packets are destined for this machine, others are 1098 * repeated to other stations. 1099 * 1100 * If wihap_data_input() returns a non-zero, it has processed 1101 * the packet and will free the mbuf. 1102 */ 1103 int 1104 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) 1105 { 1106 struct ifnet *ifp = &sc->sc_ic.ic_if; 1107 struct wihap_info *whi = &sc->wi_hostap_info; 1108 struct wihap_sta_info *sta; 1109 int mcast, s; 1110 u_int16_t fctl; 1111 1112 /* 1113 * TODS flag must be set. However, Lucent cards set NULLFUNC but 1114 * not TODS when probing an AP to see if it is alive after it has 1115 * been down for a while. We accept these probe packets and send a 1116 * disassoc packet later on if the station is not already associated. 1117 */ 1118 fctl = letoh16(rxfrm->wi_frame_ctl); 1119 if (!(fctl & WI_FCTL_TODS) && !(fctl & WI_STYPE_NULLFUNC)) { 1120 if (ifp->if_flags & IFF_DEBUG) 1121 printf("wihap_data_input: no TODS src=%s, fctl=0x%x\n", 1122 ether_sprintf(rxfrm->wi_addr2), fctl); 1123 m_freem(m); 1124 return (1); 1125 } 1126 1127 /* Check BSSID. (Is this necessary?) */ 1128 if (!addr_cmp(rxfrm->wi_addr1, sc->sc_ic.ic_myaddr)) { 1129 if (ifp->if_flags & IFF_DEBUG) 1130 printf("wihap_data_input: incorrect bss: %s\n", 1131 ether_sprintf(rxfrm->wi_addr1)); 1132 m_freem(m); 1133 return (1); 1134 } 1135 1136 s = splsoftclock(); 1137 1138 /* Find source station. */ 1139 sta = wihap_sta_find(whi, rxfrm->wi_addr2); 1140 1141 /* Source station must be associated. */ 1142 if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) { 1143 if (ifp->if_flags & IFF_DEBUG) 1144 printf("wihap_data_input: dropping unassoc src %s\n", 1145 ether_sprintf(rxfrm->wi_addr2)); 1146 wihap_sta_disassoc(sc, rxfrm->wi_addr2, 1147 IEEE80211_REASON_ASSOC_LEAVE); 1148 splx(s); 1149 m_freem(m); 1150 return (1); 1151 } 1152 1153 timeout_add_sec(&sta->tmo, whi->inactivity_time); 1154 sta->sig_info = letoh16(rxfrm->wi_q_info); 1155 1156 splx(s); 1157 1158 /* Repeat this packet to BSS? */ 1159 mcast = (rxfrm->wi_addr3[0] & 0x01) != 0; 1160 if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) { 1161 1162 /* If it's multicast, make a copy. 1163 */ 1164 if (mcast) { 1165 m = m_copym(m, 0, M_COPYALL, M_DONTWAIT); 1166 if (m == NULL) 1167 return (0); 1168 m->m_flags |= M_MCAST; /* XXX */ 1169 } 1170 1171 /* Queue up for repeating. 1172 */ 1173 if (IF_QFULL(&ifp->if_snd)) { 1174 IF_DROP(&ifp->if_snd); 1175 m_freem(m); 1176 } 1177 else { 1178 ifp->if_obytes += m->m_pkthdr.len; 1179 if (m->m_flags & M_MCAST) 1180 ifp->if_omcasts++; 1181 IF_ENQUEUE(&ifp->if_snd, m); 1182 if ((ifp->if_flags & IFF_OACTIVE) == 0) 1183 (*ifp->if_start)(ifp); 1184 } 1185 return (!mcast); 1186 } 1187 1188 return (0); 1189 } 1190 1191 /* wihap_ioctl() 1192 * 1193 * Handle Host AP specific ioctls. Called from wi_ioctl(). 1194 */ 1195 int 1196 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) 1197 { 1198 struct proc *p = curproc; 1199 struct ifreq *ifr = (struct ifreq *) data; 1200 struct wihap_info *whi = &sc->wi_hostap_info; 1201 struct wihap_sta_info *sta; 1202 struct hostap_getall reqall; 1203 struct hostap_sta reqsta; 1204 struct hostap_sta stabuf; 1205 int s, error = 0, n, flag; 1206 1207 struct ieee80211_nodereq nr; 1208 struct ieee80211_nodereq_all *na; 1209 1210 if (!(sc->sc_ic.ic_if.if_flags & IFF_RUNNING)) 1211 return ENODEV; 1212 1213 switch (command) { 1214 case SIOCHOSTAP_DEL: 1215 if ((error = suser(p, 0))) 1216 break; 1217 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) 1218 break; 1219 s = splnet(); 1220 sta = wihap_sta_find(whi, reqsta.addr); 1221 if (sta == NULL) 1222 error = ENOENT; 1223 else { 1224 /* Disassociate station. */ 1225 if (sta->flags & WI_SIFLAGS_ASSOC) 1226 wihap_sta_disassoc(sc, sta->addr, 1227 IEEE80211_REASON_ASSOC_LEAVE); 1228 /* Deauth station. */ 1229 if (sta->flags & WI_SIFLAGS_AUTHEN) 1230 wihap_sta_deauth(sc, sta->addr, 1231 IEEE80211_REASON_AUTH_LEAVE); 1232 1233 wihap_sta_delete(sta); 1234 } 1235 splx(s); 1236 break; 1237 1238 case SIOCHOSTAP_GET: 1239 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) 1240 break; 1241 s = splnet(); 1242 sta = wihap_sta_find(whi, reqsta.addr); 1243 if (sta == NULL) 1244 error = ENOENT; 1245 else { 1246 reqsta.flags = sta->flags; 1247 reqsta.asid = sta->asid; 1248 reqsta.capinfo = sta->capinfo; 1249 reqsta.sig_info = sta->sig_info; 1250 reqsta.rates = sta->rates; 1251 1252 error = copyout(&reqsta, ifr->ifr_data, 1253 sizeof(reqsta)); 1254 } 1255 splx(s); 1256 break; 1257 1258 case SIOCHOSTAP_ADD: 1259 if ((error = suser(p, 0))) 1260 break; 1261 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) 1262 break; 1263 s = splnet(); 1264 sta = wihap_sta_find(whi, reqsta.addr); 1265 if (sta != NULL) { 1266 error = EEXIST; 1267 splx(s); 1268 break; 1269 } 1270 if (whi->n_stations >= WIHAP_MAX_STATIONS) { 1271 error = ENOSPC; 1272 splx(s); 1273 break; 1274 } 1275 sta = wihap_sta_alloc(sc, reqsta.addr); 1276 sta->flags = reqsta.flags; 1277 timeout_add_sec(&sta->tmo, whi->inactivity_time); 1278 splx(s); 1279 break; 1280 1281 case SIOCHOSTAP_SFLAGS: 1282 if ((error = suser(p, 0))) 1283 break; 1284 if ((error = copyin(ifr->ifr_data, &flag, sizeof(int)))) 1285 break; 1286 1287 whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) | 1288 (flag & ~WIHAPFL_CANTCHANGE); 1289 break; 1290 1291 case SIOCHOSTAP_GFLAGS: 1292 flag = (int) whi->apflags; 1293 error = copyout(&flag, ifr->ifr_data, sizeof(int)); 1294 break; 1295 1296 case SIOCHOSTAP_GETALL: 1297 if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall)))) 1298 break; 1299 1300 reqall.nstations = whi->n_stations; 1301 n = 0; 1302 s = splnet(); 1303 sta = TAILQ_FIRST(&whi->sta_list); 1304 while (sta && reqall.size >= n+sizeof(struct hostap_sta)) { 1305 1306 bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN); 1307 stabuf.asid = sta->asid; 1308 stabuf.flags = sta->flags; 1309 stabuf.capinfo = sta->capinfo; 1310 stabuf.sig_info = sta->sig_info; 1311 stabuf.rates = sta->rates; 1312 1313 error = copyout(&stabuf, (caddr_t) reqall.addr + n, 1314 sizeof(struct hostap_sta)); 1315 if (error) 1316 break; 1317 1318 sta = TAILQ_NEXT(sta, list); 1319 n += sizeof(struct hostap_sta); 1320 } 1321 splx(s); 1322 1323 if (!error) 1324 error = copyout(&reqall, ifr->ifr_data, 1325 sizeof(reqall)); 1326 break; 1327 1328 case SIOCG80211ALLNODES: 1329 na = (struct ieee80211_nodereq_all *)data; 1330 na->na_nodes = n = 0; 1331 s = splnet(); 1332 sta = TAILQ_FIRST(&whi->sta_list); 1333 while (sta && na->na_size >= 1334 n + sizeof(struct ieee80211_nodereq)) { 1335 bzero(&nr, sizeof(nr)); 1336 IEEE80211_ADDR_COPY(nr.nr_macaddr, sta->addr); 1337 IEEE80211_ADDR_COPY(nr.nr_bssid, 1338 &sc->sc_ic.ic_myaddr); 1339 nr.nr_channel = sc->wi_channel; 1340 nr.nr_chan_flags = IEEE80211_CHAN_B; 1341 nr.nr_associd = sta->asid; 1342 nr.nr_rssi = sta->sig_info >> 8; 1343 nr.nr_max_rssi = 0; 1344 nr.nr_capinfo = sta->capinfo; 1345 nr.nr_nrates = 0; 1346 if (sta->rates & WI_SUPPRATES_1M) 1347 nr.nr_rates[nr.nr_nrates++] = 2; 1348 if (sta->rates & WI_SUPPRATES_2M) 1349 nr.nr_rates[nr.nr_nrates++] = 4; 1350 if (sta->rates & WI_SUPPRATES_5M) 1351 nr.nr_rates[nr.nr_nrates++] = 11; 1352 if (sta->rates & WI_SUPPRATES_11M) 1353 nr.nr_rates[nr.nr_nrates++] = 22; 1354 1355 error = copyout(&nr, (caddr_t)na->na_node + n, 1356 sizeof(struct ieee80211_nodereq)); 1357 if (error) 1358 break; 1359 n += sizeof(struct ieee80211_nodereq); 1360 na->na_nodes++; 1361 sta = TAILQ_NEXT(sta, list); 1362 } 1363 splx(s); 1364 break; 1365 1366 default: 1367 printf("wihap_ioctl: i shouldn't get other ioctls!\n"); 1368 error = EINVAL; 1369 } 1370 1371 return (error); 1372 } 1373 1374 #else 1375 void 1376 wihap_init(struct wi_softc *sc) 1377 { 1378 return; 1379 } 1380 1381 void 1382 wihap_shutdown(struct wi_softc *sc) 1383 { 1384 return; 1385 } 1386 1387 void 1388 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) 1389 { 1390 return; 1391 } 1392 1393 int 1394 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) 1395 { 1396 return (0); 1397 } 1398 1399 int 1400 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) 1401 { 1402 return (EINVAL); 1403 } 1404 1405 int 1406 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate) 1407 { 1408 return (0); 1409 } 1410 #endif 1411