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