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
zyd_dbg(uint32_t dbg_mask,const int8_t * fmt,...)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
zyd_warn(const int8_t * fmt,...)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
zyd_plcp_signal(uint16_t rate)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
zyd_next_scan(void * arg)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
zyd_receive(struct zyd_softc * sc,const uint8_t * buf,uint16_t len)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
zyd_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)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
zyd_mac_init(struct zyd_softc * sc)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
zyd_wifi_init(struct zyd_softc * sc)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
zyd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
zyd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
zyd_m_stat(void * arg,uint_t stat,uint64_t * val)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
zyd_m_start(void * arg)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
zyd_m_stop(void * arg)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
zyd_m_unicst(void * arg,const uint8_t * macaddr)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
zyd_m_multicst(void * arg,boolean_t add,const uint8_t * m)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
zyd_m_promisc(void * arg,boolean_t on)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
zyd_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)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
zyd_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)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
zyd_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)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
zyd_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t mph)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 *
zyd_m_tx(void * arg,mblk_t * mp)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
zyd_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)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
zyd_serial_init(struct zyd_softc * sc)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
zyd_serial_enter(struct zyd_softc * sc,boolean_t wait_sig)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
zyd_serial_exit(struct zyd_softc * sc)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
zyd_serial_deinit(struct zyd_softc * sc)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
zyd_cb_lock_init(struct zyd_cb_lock * lock)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
zyd_cb_lock_destroy(struct zyd_cb_lock * lock)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
zyd_cb_lock_wait(struct zyd_cb_lock * lock,clock_t timeout)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
zyd_cb_lock_signal(struct zyd_cb_lock * lock)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
_init(void)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
_info(struct modinfo * modinfop)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
_fini(void)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