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