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