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