1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2007 by Lukas Turek <turek@ksvi.mff.cuni.cz> 8 * Copyright (c) 2007 by Jiri Svoboda <jirik.svoboda@seznam.cz> 9 * Copyright (c) 2007 by Martin Krulis <martin.krulis@matfyz.cz> 10 * Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr> 11 * Copyright (c) 2006 by Florian Stoehr <ich@florian-stoehr.de> 12 * 13 * Permission to use, copy, modify, and distribute this software for any 14 * purpose with or without fee is hereby granted, provided that the above 15 * copyright notice and this permission notice appear in all copies. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 18 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 20 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 23 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 * 25 */ 26 27 /* 28 * ZD1211 wLAN driver 29 * Driver major routines 30 */ 31 32 #include <sys/byteorder.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/conf.h> 36 #include <sys/modctl.h> 37 #include <sys/mac_provider.h> 38 #include <sys/mac_wifi.h> 39 #include <sys/strsun.h> 40 #include <sys/ksynch.h> 41 42 #include "zyd.h" 43 #include "zyd_reg.h" 44 45 static int zyd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 46 static int zyd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 47 48 static int zyd_m_stat(void *arg, uint_t stat, uint64_t *val); 49 static int zyd_m_start(void *arg); 50 static void zyd_m_stop(void *arg); 51 static int zyd_m_unicst(void *arg, const uint8_t *macaddr); 52 static int zyd_m_multicst(void *arg, boolean_t add, const uint8_t *m); 53 static int zyd_m_promisc(void *arg, boolean_t on); 54 static void zyd_m_ioctl(void *arg, queue_t *wq, mblk_t *mp); 55 static mblk_t *zyd_m_tx(void *arg, mblk_t *mp); 56 static int zyd_m_getprop(void *arg, const char *pr_name, 57 mac_prop_id_t wldp_pr_num, uint_t pr_flags, 58 uint_t wldp_length, void *wldp_buf, uint_t *perm); 59 static int zyd_m_setprop(void *arg, const char *pr_name, 60 mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf); 61 62 static int zyd_newstate(struct ieee80211com *ic, 63 enum ieee80211_state state, int arg); 64 65 /* Driver identification */ 66 static char zyd_ident[] = ZYD_DRV_DESC " " ZYD_DRV_REV; 67 68 /* Global state pointer for managing per-device soft states */ 69 void *zyd_ssp; 70 71 /* 72 * Mac Call Back entries 73 */ 74 static mac_callbacks_t zyd_m_callbacks = { 75 MC_IOCTL | MC_SETPROP | MC_GETPROP, 76 zyd_m_stat, /* Get the value of a statistic */ 77 zyd_m_start, /* Start the device */ 78 zyd_m_stop, /* Stop the device */ 79 zyd_m_promisc, /* Enable or disable promiscuous mode */ 80 zyd_m_multicst, /* Enable or disable a multicast addr */ 81 zyd_m_unicst, /* Set the unicast MAC address */ 82 zyd_m_tx, /* Transmit a packet */ 83 zyd_m_ioctl, /* Process an unknown ioctl */ 84 NULL, /* mc_getcapab */ 85 NULL, 86 NULL, 87 zyd_m_setprop, 88 zyd_m_getprop 89 }; 90 91 /* 92 * Module Loading Data & Entry Points 93 */ 94 DDI_DEFINE_STREAM_OPS(zyd_devops, /* name */ 95 nulldev, /* identify */ 96 nulldev, /* probe */ 97 zyd_attach, /* attach */ 98 zyd_detach, /* detach */ 99 nodev, /* reset */ 100 NULL, /* getinfo */ 101 D_MP, /* flag */ 102 NULL, /* stream_tab */ 103 ddi_quiesce_not_needed /* quiesce */ 104 ); 105 106 static struct modldrv zyd_modldrv = { 107 &mod_driverops, /* drv_modops */ 108 zyd_ident, /* drv_linkinfo */ 109 &zyd_devops /* drv_dev_ops */ 110 }; 111 112 static struct modlinkage zyd_ml = { 113 MODREV_1, /* ml_rev */ 114 {&zyd_modldrv, NULL} /* ml_linkage */ 115 }; 116 117 /* 118 * Wireless-specific structures 119 */ 120 static const struct ieee80211_rateset zyd_rateset_11b = { 121 4, {2, 4, 11, 22} /* units are 0.5Mbit! */ 122 }; 123 124 static const struct ieee80211_rateset zyd_rateset_11g = { 125 12, {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108} 126 }; 127 128 129 #ifdef DEBUG 130 uint32_t zyd_dbg_flags; 131 132 void 133 zyd_dbg(uint32_t dbg_mask, const int8_t *fmt, ...) 134 { 135 va_list args; 136 137 if (dbg_mask & zyd_dbg_flags) { 138 va_start(args, fmt); 139 vcmn_err(CE_CONT, fmt, args); 140 va_end(args); 141 } 142 } 143 #endif 144 145 void 146 zyd_warn(const int8_t *fmt, ...) 147 { 148 va_list args; 149 150 va_start(args, fmt); 151 vcmn_err(CE_WARN, fmt, args); 152 va_end(args); 153 } 154 155 /* 156 * Internal functions 157 */ 158 static uint8_t 159 zyd_plcp_signal(uint16_t rate) 160 { 161 switch (rate) { 162 /* CCK rates (returned values are device-dependent) */ 163 case 2: 164 return (0x0); 165 case 4: 166 return (0x1); 167 case 11: 168 return (0x2); 169 case 22: 170 return (0x3); 171 172 /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 173 case 12: 174 return (0xb); 175 case 18: 176 return (0xf); 177 case 24: 178 return (0xa); 179 case 36: 180 return (0xe); 181 case 48: 182 return (0x9); 183 case 72: 184 return (0xd); 185 case 96: 186 return (0x8); 187 case 108: 188 return (0xc); 189 190 /* unsupported rates (should not get there) */ 191 default: 192 return (0xff); 193 } 194 } 195 196 /* 197 * Timeout function for scanning. 198 * 199 * Called at the end of each scanning round. 200 */ 201 static void 202 zyd_next_scan(void *arg) 203 { 204 struct zyd_softc *sc = arg; 205 struct ieee80211com *ic = &sc->ic; 206 207 ZYD_DEBUG((ZYD_DBG_SCAN, "scan timer: fired\n")); 208 209 if (ic->ic_state == IEEE80211_S_SCAN) { 210 ieee80211_next_scan(ic); 211 } else { 212 ZYD_DEBUG((ZYD_DBG_SCAN, "scan timer: no work\n")); 213 } 214 } 215 216 /* 217 * Extract a 802.11 frame from the received packet and forward it to net80211. 218 */ 219 void 220 zyd_receive(struct zyd_softc *sc, const uint8_t *buf, uint16_t len) 221 { 222 const struct zyd_rx_stat *stat; 223 struct ieee80211com *ic = &sc->ic; 224 struct ieee80211_frame *wh; 225 struct ieee80211_node *in; 226 int rlen; /* Actual frame length */ 227 uint8_t rssi; 228 mblk_t *m; 229 230 if (len < ZYD_MIN_FRAGSZ) { 231 /* Packet is too short, silently drop it */ 232 sc->rx_err++; 233 return; 234 } 235 236 stat = (const struct zyd_rx_stat *) 237 (buf + len - sizeof (struct zyd_rx_stat)); 238 if (stat->flags & ZYD_RX_ERROR) { 239 /* Frame is corrupted, silently drop it */ 240 sc->rx_err++; 241 return; 242 } 243 244 /* compute actual frame length */ 245 rlen = len - sizeof (struct zyd_plcphdr) - 246 sizeof (struct zyd_rx_stat) - IEEE80211_CRC_LEN; 247 248 m = allocb(rlen, BPRI_MED); 249 if (m == NULL) { 250 sc->rx_nobuf++; 251 return; 252 } 253 254 /* Copy frame to new buffer */ 255 bcopy(buf + sizeof (struct zyd_plcphdr), m->b_wptr, rlen); 256 m->b_wptr += rlen; 257 258 /* Send frame to net80211 stack */ 259 wh = (struct ieee80211_frame *)m->b_rptr; 260 in = ieee80211_find_rxnode(ic, wh); 261 rssi = (stat->rssi < 25) ? 230 : (255 - stat->rssi) / 2; 262 263 (void) ieee80211_input(ic, m, in, (int32_t)rssi, 0); 264 265 ieee80211_free_node(in); 266 } 267 268 /* 269 * xxx_send callback for net80211. 270 * 271 * Transmit a 802.11 frame. 272 * 273 * Constructs a packet from zyd_tx_header and 802.11 frame data 274 * and sends it to the chip. 275 */ 276 /*ARGSUSED*/ 277 static int 278 zyd_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 279 { 280 struct zyd_softc *sc = ZYD_IC_TO_SOFTC(ic); 281 struct zyd_tx_header *buf_hdr; 282 struct ieee80211_frame *wh; 283 struct ieee80211_node *in; 284 struct ieee80211_key *k; 285 mblk_t *m, *m0; 286 int len, off, mblen; 287 uint16_t frame_size, additional_size, rate; 288 uint8_t service; 289 int res; 290 291 ASSERT(mp->b_next == NULL); 292 293 /* device not ready, drop all frames */ 294 if (!sc->usb.connected || sc->suspended || !sc->running) { 295 freemsg(mp); 296 if (type == IEEE80211_FC0_TYPE_DATA) 297 return (DDI_SUCCESS); 298 else 299 return (DDI_FAILURE); 300 } 301 302 /* device queue overrun */ 303 if (sc->tx_queued >= ZYD_TX_LIST_COUNT) { 304 /* drop management frames */ 305 if (type != IEEE80211_FC0_TYPE_DATA) { 306 freemsg(mp); 307 } else { 308 (void) zyd_serial_enter(sc, ZYD_NO_SIG); 309 sc->resched = B_TRUE; 310 zyd_serial_exit(sc); 311 } 312 return (DDI_FAILURE); 313 } 314 315 m = allocb(msgdsize(mp) + sizeof (struct zyd_tx_header) + 32, 316 BPRI_MED); 317 if (m == NULL) { 318 sc->tx_nobuf++; 319 (void) zyd_serial_enter(sc, ZYD_NO_SIG); 320 sc->resched = B_TRUE; 321 zyd_serial_exit(sc); 322 return (DDI_FAILURE); 323 } 324 m->b_rptr += sizeof (struct zyd_tx_header); 325 m->b_wptr = m->b_rptr; 326 327 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 328 mblen = MBLKL(m0); 329 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); 330 off += mblen; 331 } 332 m->b_wptr += off; 333 334 wh = (struct ieee80211_frame *)m->b_rptr; 335 in = ieee80211_find_txnode(ic, wh->i_addr1); 336 337 if (in == NULL) { 338 freemsg(m); 339 sc->tx_err++; 340 freemsg(mp); 341 return (DDI_SUCCESS); 342 } 343 in->in_inact = 0; 344 345 if (type == IEEE80211_FC0_TYPE_DATA) 346 (void) ieee80211_encap(ic, m, in); 347 348 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 349 k = ieee80211_crypto_encap(ic, m); 350 if (k == NULL) { 351 sc->tx_err++; 352 ieee80211_free_node(in); 353 freemsg(m); 354 freemsg(mp); 355 return (DDI_SUCCESS); 356 } 357 /* packet header may have moved, reset our local pointer */ 358 wh = (struct ieee80211_frame *)m->b_rptr; 359 } 360 361 /* 362 * pickup a rate. May need work to make adaptive - at present, 363 * picks best rate for mode. 364 */ 365 if (type == IEEE80211_FC0_TYPE_MGT) { 366 /* mgmt frames are sent at 1M */ 367 rate = (uint16_t)in->in_rates.ir_rates[0]; 368 } else if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { 369 rate = (uint16_t)ic->ic_sup_rates[ic->ic_curmode]. 370 ir_rates[ic->ic_fixed_rate]; 371 } else { 372 rate = (uint16_t)ic->ic_sup_rates[ic->ic_curmode]. 373 ir_rates[in->in_txrate]; 374 } 375 rate &= IEEE80211_RATE_VAL; 376 if (rate == 0) /* should not happen */ 377 rate = 2; 378 379 /* Get total length of frame */ 380 len = msgsize(m); 381 382 m->b_rptr -= sizeof (struct zyd_tx_header); 383 buf_hdr = (struct zyd_tx_header *)m->b_rptr; 384 385 frame_size = (uint16_t)len + 4; /* include CRC32 */ 386 buf_hdr->frame_size = LE_16(frame_size); 387 388 /* 389 * Compute "packet size". What the 10 stands for, 390 * nobody knows. 391 */ 392 additional_size = sizeof (struct zyd_tx_header) + 10; 393 if (sc->mac_rev == ZYD_ZD1211) 394 buf_hdr->packet_size = LE_16(frame_size + additional_size); 395 else 396 buf_hdr->packet_size = LE_16(additional_size); 397 398 buf_hdr->rate_mod_flags = LE_8(zyd_plcp_signal(rate)); 399 buf_hdr->type_flags = LE_8(ZYD_TX_FLAG_BACKOFF); 400 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 401 /* multicast frames are not sent at OFDM rates in 802.11b/g */ 402 if (frame_size > ic->ic_rtsthreshold) { 403 buf_hdr->type_flags |= ZYD_TX_FLAG_RTS; 404 } else if (ZYD_RATE_IS_OFDM(rate) && 405 (ic->ic_flags & IEEE80211_F_USEPROT)) { 406 if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 407 buf_hdr->type_flags |= 408 ZYD_TX_FLAG_CTS_TO_SELF; 409 else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 410 buf_hdr->type_flags |= ZYD_TX_FLAG_RTS; 411 } 412 } else 413 buf_hdr->type_flags |= ZYD_TX_FLAG_MULTICAST; 414 415 if ((type == IEEE80211_FC0_TYPE_CTL) && 416 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 417 == IEEE80211_FC0_SUBTYPE_PS_POLL) 418 buf_hdr->type_flags |= ZYD_TX_FLAG_TYPE(ZYD_TX_TYPE_PS_POLL); 419 420 if (ZYD_RATE_IS_OFDM(rate)) { 421 buf_hdr->rate_mod_flags |= ZYD_TX_RMF_OFDM; 422 if (ic->ic_curmode == IEEE80211_MODE_11A) 423 buf_hdr->rate_mod_flags |= ZYD_TX_RMF_5GHZ; 424 } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 425 buf_hdr->rate_mod_flags |= ZYD_TX_RMF_SH_PREAMBLE; 426 427 /* 428 * Compute frame duration and length-extension service flag. 429 */ 430 service = 0x00; 431 432 buf_hdr->frame_duration = LE_16((16 * frame_size + rate - 1) / rate); 433 buf_hdr->service = service; 434 buf_hdr->next_frame_duration = LE_16(0); 435 436 if (rate == 22) { 437 const int remainder = (16 * frame_size) % 22; 438 if (remainder != 0 && remainder < 7) 439 buf_hdr->service |= ZYD_TX_SERVICE_LENGTH_EXTENSION; 440 } 441 442 res = zyd_usb_send_packet(&sc->usb, m); 443 if (res != ZYD_SUCCESS) { 444 sc->tx_err++; 445 } else { 446 (void) zyd_serial_enter(sc, ZYD_NO_SIG); 447 sc->tx_queued++; 448 zyd_serial_exit(sc); 449 freemsg(mp); 450 ic->ic_stats.is_tx_frags++; 451 ic->ic_stats.is_tx_bytes += len; 452 } 453 454 ieee80211_free_node(in); 455 456 return (DDI_SUCCESS); 457 } 458 459 /* 460 * Register with the MAC layer. 461 */ 462 static zyd_res 463 zyd_mac_init(struct zyd_softc *sc) 464 { 465 struct ieee80211com *ic = &sc->ic; 466 mac_register_t *macp; 467 wifi_data_t wd = { 0 }; 468 int err; 469 470 /* 471 * Initialize mac structure 472 */ 473 macp = mac_alloc(MAC_VERSION); 474 if (macp == NULL) { 475 ZYD_WARN("failed to allocate MAC structure\n"); 476 return (ZYD_FAILURE); 477 } 478 479 /* 480 * Initialize pointer to device specific functions 481 */ 482 wd.wd_secalloc = WIFI_SEC_NONE; 483 wd.wd_opmode = sc->ic.ic_opmode; 484 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr); 485 486 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 487 macp->m_driver = sc; 488 macp->m_dip = sc->dip; 489 macp->m_src_addr = ic->ic_macaddr; 490 macp->m_callbacks = &zyd_m_callbacks; 491 macp->m_min_sdu = 0; 492 macp->m_max_sdu = IEEE80211_MTU; 493 macp->m_pdata = &wd; 494 macp->m_pdata_size = sizeof (wd); 495 496 /* 497 * Register the macp to mac 498 */ 499 err = mac_register(macp, &sc->ic.ic_mach); 500 mac_free(macp); 501 502 if (err != DDI_SUCCESS) { 503 ZYD_WARN("failed to register MAC structure\n"); 504 return (ZYD_FAILURE); 505 } 506 507 return (ZYD_SUCCESS); 508 } 509 510 /* 511 * Register with net80211. 512 */ 513 static void 514 zyd_wifi_init(struct zyd_softc *sc) 515 { 516 struct ieee80211com *ic = &sc->ic; 517 int i; 518 519 /* 520 * Initialize the WiFi part, which will be used by generic layer 521 */ 522 ic->ic_phytype = IEEE80211_T_OFDM; 523 ic->ic_opmode = IEEE80211_M_STA; 524 ic->ic_state = IEEE80211_S_INIT; 525 ic->ic_maxrssi = 255; 526 ic->ic_xmit = zyd_send; 527 528 /* set device capabilities */ 529 ic->ic_caps = IEEE80211_C_TXPMGT | /* tx power management */ 530 IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 531 IEEE80211_C_SHSLOT | IEEE80211_C_WPA; /* Support WPA/WPA2 */ 532 533 /* Copy MAC address */ 534 IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->macaddr); 535 536 /* 537 * set supported .11b and .11g rates 538 */ 539 ic->ic_sup_rates[IEEE80211_MODE_11B] = zyd_rateset_11b; 540 ic->ic_sup_rates[IEEE80211_MODE_11G] = zyd_rateset_11g; 541 542 /* 543 * set supported .11b and .11g channels(1 through 14) 544 */ 545 for (i = 1; i <= 14; i++) { 546 ic->ic_sup_channels[i].ich_freq = 547 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 548 ic->ic_sup_channels[i].ich_flags = 549 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 550 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 551 } 552 553 /* 554 * Init generic layer (it cannot fail) 555 */ 556 ieee80211_attach(ic); 557 558 /* register WPA door */ 559 ieee80211_register_door(ic, ddi_driver_name(sc->dip), 560 ddi_get_instance(sc->dip)); 561 562 /* Must be after attach! */ 563 sc->newstate = ic->ic_newstate; 564 ic->ic_newstate = zyd_newstate; 565 566 ieee80211_media_init(ic); 567 ic->ic_def_txkey = 0; 568 } 569 570 /* 571 * Device operations 572 */ 573 /* 574 * Binding the driver to a device. 575 * 576 * Concurrency: Until zyd_attach() returns with success, 577 * the only other entry point that can be executed is getinfo(). 578 * Thus no locking here yet. 579 */ 580 static int 581 zyd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 582 { 583 struct zyd_softc *sc; 584 char strbuf[32]; 585 int instance; 586 int err; 587 588 switch (cmd) { 589 case DDI_ATTACH: 590 break; 591 592 case DDI_RESUME: 593 sc = ddi_get_soft_state(zyd_ssp, ddi_get_instance(dip)); 594 ASSERT(sc != NULL); 595 596 (void) zyd_resume(sc); 597 return (DDI_SUCCESS); 598 599 default: 600 return (DDI_FAILURE); 601 } 602 603 instance = ddi_get_instance(dip); 604 err = ddi_soft_state_zalloc(zyd_ssp, instance); 605 606 if (err != DDI_SUCCESS) { 607 ZYD_WARN("failed to allocate soft state\n"); 608 return (DDI_FAILURE); 609 } 610 611 sc = ddi_get_soft_state(zyd_ssp, instance); 612 sc->dip = dip; 613 sc->timeout_id = 0; 614 615 if (zyd_usb_init(sc) != ZYD_SUCCESS) { 616 ddi_soft_state_free(zyd_ssp, instance); 617 return (DDI_FAILURE); 618 } 619 620 if (zyd_hw_init(sc) != ZYD_SUCCESS) { 621 zyd_usb_deinit(sc); 622 ddi_soft_state_free(zyd_ssp, instance); 623 return (DDI_FAILURE); 624 } 625 626 zyd_wifi_init(sc); 627 628 if (zyd_mac_init(sc) != DDI_SUCCESS) { 629 ieee80211_detach(&sc->ic); 630 zyd_usb_deinit(sc); 631 ddi_soft_state_free(zyd_ssp, instance); 632 return (DDI_FAILURE); 633 } 634 635 /* 636 * Create minor node of type DDI_NT_NET_WIFI 637 */ 638 (void) snprintf(strbuf, sizeof (strbuf), ZYD_DRV_NAME"%d", instance); 639 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 640 instance + 1, DDI_NT_NET_WIFI, 0); 641 if (err != DDI_SUCCESS) 642 ZYD_WARN("failed to create minor node\n"); 643 644 /* initialize locking */ 645 zyd_serial_init(sc); 646 647 return (DDI_SUCCESS); 648 } 649 650 /* 651 * Detach the driver from a device. 652 * 653 * Concurrency: Will be called only after a successful attach 654 * (and not concurrently). 655 */ 656 static int 657 zyd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 658 { 659 struct zyd_softc *sc = NULL; 660 661 switch (cmd) { 662 case DDI_DETACH: 663 break; 664 665 case DDI_SUSPEND: 666 sc = ddi_get_soft_state(zyd_ssp, ddi_get_instance(dip)); 667 ASSERT(sc != NULL); 668 669 return (zyd_suspend(sc)); 670 671 default: 672 return (DDI_FAILURE); 673 } 674 675 sc = ddi_get_soft_state(zyd_ssp, ddi_get_instance(dip)); 676 ASSERT(sc != NULL); 677 678 if (mac_disable(sc->ic.ic_mach) != 0) 679 return (DDI_FAILURE); 680 /* 681 * Unregister from the MAC layer subsystem 682 */ 683 (void) mac_unregister(sc->ic.ic_mach); 684 685 /* 686 * Detach ieee80211 687 */ 688 ieee80211_detach(&sc->ic); 689 690 zyd_hw_deinit(sc); 691 zyd_usb_deinit(sc); 692 693 /* At this point it should be safe to release & destroy the locks */ 694 zyd_serial_deinit(sc); 695 696 ddi_remove_minor_node(dip, NULL); 697 ddi_soft_state_free(zyd_ssp, ddi_get_instance(dip)); 698 return (DDI_SUCCESS); 699 } 700 701 /* 702 * Mac Call Back functions 703 */ 704 705 /* 706 * Read device statistic information. 707 */ 708 static int 709 zyd_m_stat(void *arg, uint_t stat, uint64_t *val) 710 { 711 struct zyd_softc *sc = (struct zyd_softc *)arg; 712 ieee80211com_t *ic = &sc->ic; 713 ieee80211_node_t *in; 714 715 switch (stat) { 716 case MAC_STAT_IFSPEED: 717 if (!sc->usb.connected || sc->suspended || !sc->running) 718 return (ENOTSUP); 719 in = ieee80211_ref_node(ic->ic_bss); 720 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 721 IEEE80211_RATE(in->in_txrate) : 722 ic->ic_fixed_rate) / 2 * 1000000; 723 ieee80211_free_node(in); 724 break; 725 case MAC_STAT_NOXMTBUF: 726 *val = sc->tx_nobuf; 727 break; 728 case MAC_STAT_NORCVBUF: 729 *val = sc->rx_nobuf; 730 break; 731 case MAC_STAT_IERRORS: 732 *val = sc->rx_err; 733 break; 734 case MAC_STAT_RBYTES: 735 *val = ic->ic_stats.is_rx_bytes; 736 break; 737 case MAC_STAT_IPACKETS: 738 *val = ic->ic_stats.is_rx_frags; 739 break; 740 case MAC_STAT_OBYTES: 741 *val = ic->ic_stats.is_tx_bytes; 742 break; 743 case MAC_STAT_OPACKETS: 744 *val = ic->ic_stats.is_tx_frags; 745 break; 746 case MAC_STAT_OERRORS: 747 case WIFI_STAT_TX_FAILED: 748 *val = sc->tx_err; 749 break; 750 case WIFI_STAT_TX_RETRANS: 751 case WIFI_STAT_FCS_ERRORS: 752 case WIFI_STAT_WEP_ERRORS: 753 case WIFI_STAT_TX_FRAGS: 754 case WIFI_STAT_MCAST_TX: 755 case WIFI_STAT_RTS_SUCCESS: 756 case WIFI_STAT_RTS_FAILURE: 757 case WIFI_STAT_ACK_FAILURE: 758 case WIFI_STAT_RX_FRAGS: 759 case WIFI_STAT_MCAST_RX: 760 case WIFI_STAT_RX_DUPS: 761 return (ieee80211_stat(ic, stat, val)); 762 default: 763 return (ENOTSUP); 764 } 765 return (0); 766 } 767 768 /* 769 * Start the device. 770 * 771 * Concurrency: Presumably fully concurrent, must lock. 772 */ 773 static int 774 zyd_m_start(void *arg) 775 { 776 struct zyd_softc *sc = (struct zyd_softc *)arg; 777 778 (void) zyd_serial_enter(sc, ZYD_NO_SIG); 779 if ((!sc->usb.connected) || (zyd_hw_start(sc) != ZYD_SUCCESS)) { 780 zyd_serial_exit(sc); 781 return (DDI_FAILURE); 782 } 783 zyd_serial_exit(sc); 784 785 ieee80211_new_state(&sc->ic, IEEE80211_S_INIT, -1); 786 sc->running = B_TRUE; 787 788 return (DDI_SUCCESS); 789 } 790 791 /* 792 * Stop the device. 793 */ 794 static void 795 zyd_m_stop(void *arg) 796 { 797 struct zyd_softc *sc = (struct zyd_softc *)arg; 798 799 sc->running = B_FALSE; 800 ieee80211_new_state(&sc->ic, IEEE80211_S_INIT, -1); 801 802 (void) zyd_serial_enter(sc, ZYD_NO_SIG); 803 sc->resched = B_FALSE; 804 zyd_hw_stop(sc); 805 zyd_serial_exit(sc); 806 } 807 808 /* 809 * Change the MAC address of the device. 810 */ 811 /*ARGSUSED*/ 812 static int 813 zyd_m_unicst(void *arg, const uint8_t *macaddr) 814 { 815 return (DDI_FAILURE); 816 } 817 818 /* 819 * Enable/disable multicast. 820 */ 821 /*ARGSUSED*/ 822 static int 823 zyd_m_multicst(void *arg, boolean_t add, const uint8_t *m) 824 { 825 ZYD_DEBUG((ZYD_DBG_GLD, "multicast not implemented\n")); 826 return (DDI_SUCCESS); 827 } 828 829 /* 830 * Enable/disable promiscuous mode. 831 */ 832 /*ARGSUSED*/ 833 static int 834 zyd_m_promisc(void *arg, boolean_t on) 835 { 836 ZYD_DEBUG((ZYD_DBG_GLD, "promiscuous not implemented\n")); 837 return (DDI_SUCCESS); 838 } 839 840 /* 841 * IOCTL request. 842 */ 843 static void 844 zyd_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 845 { 846 struct zyd_softc *sc = (struct zyd_softc *)arg; 847 struct ieee80211com *ic = &sc->ic; 848 849 if (!sc->usb.connected || sc->suspended || !sc->running) { 850 miocnak(wq, mp, 0, ENXIO); 851 return; 852 } 853 854 if (ieee80211_ioctl(ic, wq, mp) == ENETRESET) { 855 if (sc->running && ic->ic_des_esslen) { 856 zyd_m_stop(sc); 857 if (zyd_m_start(sc) != DDI_SUCCESS) 858 return; 859 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 860 } 861 } 862 } 863 864 /* 865 * callback functions for /get/set properties 866 */ 867 static int 868 zyd_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 869 uint_t wldp_length, const void *wldp_buf) 870 { 871 struct zyd_softc *sc = (struct zyd_softc *)arg; 872 struct ieee80211com *ic = &sc->ic; 873 int err; 874 875 if (!sc->usb.connected || sc->suspended || !sc->running) { 876 return (ENXIO); 877 } 878 879 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length, 880 wldp_buf); 881 if (err == ENETRESET) { 882 if (sc->running && ic->ic_des_esslen) { 883 zyd_m_stop(sc); 884 if (zyd_m_start(sc) != DDI_SUCCESS) 885 return (DDI_FAILURE); 886 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 887 } 888 err = 0; 889 } 890 891 return (err); 892 } 893 894 static int 895 zyd_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 896 uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 897 { 898 struct zyd_softc *sc = (struct zyd_softc *)arg; 899 int err; 900 901 if (!sc->usb.connected || sc->suspended || !sc->running) { 902 return (DDI_FAILURE); 903 } 904 905 err = ieee80211_getprop(&sc->ic, pr_name, wldp_pr_num, 906 pr_flags, wldp_length, wldp_buf, perm); 907 908 return (err); 909 } 910 911 /* 912 * Transmit a data frame. 913 */ 914 static mblk_t * 915 zyd_m_tx(void *arg, mblk_t *mp) 916 { 917 struct zyd_softc *sc = (struct zyd_softc *)arg; 918 struct ieee80211com *ic = &sc->ic; 919 mblk_t *next; 920 921 ASSERT(mp != NULL); 922 923 /* not associated, drop data frames */ 924 if (ic->ic_state != IEEE80211_S_RUN) { 925 freemsg(mp); 926 return (DDI_SUCCESS); 927 } 928 929 while (mp != NULL) { 930 next = mp->b_next; 931 mp->b_next = NULL; 932 933 if (zyd_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) { 934 mp->b_next = next; 935 break; 936 } 937 mp = next; 938 } 939 940 return (mp); 941 } 942 943 /* 944 * xxx_newstate callback for net80211. 945 * 946 * Called by net80211 whenever the ieee80211 state changes. 947 */ 948 static int 949 zyd_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 950 { 951 struct zyd_softc *sc = ZYD_IC_TO_SOFTC(ic); 952 struct ieee80211_node *in; 953 uint_t chan; 954 955 if (sc->timeout_id != 0) { 956 (void) untimeout(sc->timeout_id); 957 sc->timeout_id = 0; 958 } 959 960 if (!sc->usb.connected || sc->suspended || !sc->running) { 961 return (sc->newstate(ic, nstate, arg)); 962 } 963 964 switch (nstate) { 965 case IEEE80211_S_SCAN: 966 ZYD_DEBUG((ZYD_DBG_SCAN, "scan timer: starting next\n")); 967 sc->timeout_id = timeout(zyd_next_scan, sc, 968 drv_usectohz(ZYD_DWELL_TIME)); 969 /*FALLTHRU*/ 970 case IEEE80211_S_AUTH: 971 case IEEE80211_S_ASSOC: 972 case IEEE80211_S_RUN: 973 chan = ieee80211_chan2ieee(ic, ic->ic_curchan); 974 if (chan == 0 || chan == IEEE80211_CHAN_ANY) { 975 ZYD_WARN("invalid channel number\n"); 976 return (0); 977 } 978 (void) zyd_serial_enter(sc, ZYD_SER_SIG); 979 zyd_hw_set_channel(sc, chan); 980 zyd_serial_exit(sc); 981 982 in = ic->ic_bss; 983 in->in_txrate = in->in_rates.ir_nrates - 1; 984 default: 985 break; 986 } 987 988 return (sc->newstate(ic, nstate, arg)); 989 } 990 991 /* 992 * USB-safe synchronization. 993 * Debugging routines. 994 * 995 * Kmutexes should never be held when making calls to USBA 996 * or when sleeping. Thus, we implement our own "mutex" on top 997 * of kmutexes and kcondvars. 998 * 999 * Usage: Any (possibly concurrent) access to the soft state or device must 1000 * be serialized with a pair of zyd_serial_enter()/zyd_serial_exit(). 1001 */ 1002 /* 1003 * Initialize the serialization object. 1004 */ 1005 void 1006 zyd_serial_init(struct zyd_softc *sc) 1007 { 1008 mutex_init(&sc->serial.lock, NULL, MUTEX_DRIVER, 1009 sc->usb.cdata->dev_iblock_cookie); 1010 cv_init(&sc->serial.wait, NULL, CV_DRIVER, NULL); 1011 1012 sc->serial.held = B_FALSE; 1013 sc->serial.initialized = B_TRUE; 1014 } 1015 1016 /* 1017 * Wait for the serialization object. 1018 * 1019 * If wait_sig is ZYD_SER_SIG, the function may return 1020 * a signal is received. In this case, the serialization object 1021 * is not acquired (but the mutex is) and the return value is ZYD_FAILURE. 1022 * 1023 * In any other case the function returns ZYD_SUCCESS and the 1024 * serialization object is acquired. 1025 */ 1026 zyd_res 1027 zyd_serial_enter(struct zyd_softc *sc, boolean_t wait_sig) 1028 { 1029 zyd_res res; 1030 1031 mutex_enter(&sc->serial.lock); 1032 1033 res = ZYD_SUCCESS; 1034 1035 while (sc->serial.held != B_FALSE) { 1036 if (wait_sig == ZYD_SER_SIG) { 1037 res = cv_wait_sig(&sc->serial.wait, &sc->serial.lock); 1038 } else { 1039 cv_wait(&sc->serial.wait, &sc->serial.lock); 1040 } 1041 } 1042 sc->serial.held = B_TRUE; 1043 1044 mutex_exit(&sc->serial.lock); 1045 1046 return (res); 1047 } 1048 1049 /* 1050 * Release the serialization object. 1051 */ 1052 void 1053 zyd_serial_exit(struct zyd_softc *sc) 1054 { 1055 mutex_enter(&sc->serial.lock); 1056 sc->serial.held = B_FALSE; 1057 cv_broadcast(&sc->serial.wait); 1058 mutex_exit(&sc->serial.lock); 1059 } 1060 1061 /* 1062 * Destroy the serialization object. 1063 */ 1064 void 1065 zyd_serial_deinit(struct zyd_softc *sc) 1066 { 1067 cv_destroy(&sc->serial.wait); 1068 mutex_destroy(&sc->serial.lock); 1069 1070 sc->serial.initialized = B_FALSE; 1071 } 1072 1073 1074 /* 1075 * zyd_cb_lock: a special signal structure that is used for notification 1076 * that a callback function has been called. 1077 */ 1078 1079 /* Initializes the zyd_cb_lock structure. */ 1080 void 1081 zyd_cb_lock_init(struct zyd_cb_lock *lock) 1082 { 1083 ASSERT(lock != NULL); 1084 mutex_init(&lock->mutex, NULL, MUTEX_DRIVER, NULL); 1085 cv_init(&lock->cv, NULL, CV_DRIVER, NULL); 1086 lock->done = B_FALSE; 1087 } 1088 1089 /* Deinitalizes the zyd_cb_lock structure. */ 1090 void 1091 zyd_cb_lock_destroy(struct zyd_cb_lock *lock) 1092 { 1093 ASSERT(lock != NULL); 1094 mutex_destroy(&lock->mutex); 1095 cv_destroy(&lock->cv); 1096 } 1097 1098 /* 1099 * Wait on lock until someone calls the "signal" function or the timeout 1100 * expires. Note: timeout is in microseconds. 1101 */ 1102 zyd_res 1103 zyd_cb_lock_wait(struct zyd_cb_lock *lock, clock_t timeout) 1104 { 1105 zyd_res res; 1106 clock_t etime; 1107 int cv_res; 1108 1109 ASSERT(lock != NULL); 1110 1111 mutex_enter(&lock->mutex); 1112 1113 if (timeout < 0) { 1114 /* no timeout - wait as long as needed */ 1115 while (lock->done == B_FALSE) 1116 (void) cv_wait(&lock->cv, &lock->mutex); 1117 } else { 1118 /* wait with timeout (given in usec) */ 1119 etime = ddi_get_lbolt() + drv_usectohz(timeout); 1120 while (lock->done == B_FALSE) { 1121 cv_res = 1122 cv_timedwait_sig(&lock->cv, &lock->mutex, etime); 1123 if (cv_res <= 0) 1124 break; 1125 } 1126 } 1127 1128 res = (lock->done == B_TRUE) ? ZYD_SUCCESS : ZYD_FAILURE; 1129 1130 mutex_exit(&lock->mutex); 1131 1132 return (res); 1133 } 1134 1135 /* Signal that the job (eg. callback) is done and unblock anyone who waits. */ 1136 void 1137 zyd_cb_lock_signal(struct zyd_cb_lock *lock) 1138 { 1139 ASSERT(lock != NULL); 1140 1141 mutex_enter(&lock->mutex); 1142 1143 lock->done = B_TRUE; 1144 cv_broadcast(&lock->cv); 1145 1146 mutex_exit(&lock->mutex); 1147 } 1148 1149 /* 1150 * Loadable module configuration entry points 1151 */ 1152 1153 /* 1154 * _init module entry point. 1155 * 1156 * Called when the module is being loaded into memory. 1157 */ 1158 int 1159 _init(void) 1160 { 1161 int err; 1162 1163 err = ddi_soft_state_init(&zyd_ssp, sizeof (struct zyd_softc), 1); 1164 1165 if (err != DDI_SUCCESS) 1166 return (err); 1167 1168 mac_init_ops(&zyd_devops, ZYD_DRV_NAME); 1169 err = mod_install(&zyd_ml); 1170 1171 if (err != DDI_SUCCESS) { 1172 mac_fini_ops(&zyd_devops); 1173 ddi_soft_state_fini(&zyd_ssp); 1174 } 1175 1176 return (err); 1177 } 1178 1179 /* 1180 * _info module entry point. 1181 * 1182 * Called to obtain information about the module. 1183 */ 1184 int 1185 _info(struct modinfo *modinfop) 1186 { 1187 return (mod_info(&zyd_ml, modinfop)); 1188 } 1189 1190 /* 1191 * _fini module entry point. 1192 * 1193 * Called when the module is being unloaded. 1194 */ 1195 int 1196 _fini(void) 1197 { 1198 int err; 1199 1200 err = mod_remove(&zyd_ml); 1201 if (err == DDI_SUCCESS) { 1202 mac_fini_ops(&zyd_devops); 1203 ddi_soft_state_fini(&zyd_ssp); 1204 } 1205 1206 return (err); 1207 } 1208