xref: /illumos-gate/usr/src/uts/common/io/net80211/net80211.c (revision 3afe87ebb25691cb6d158edaa34a6fb9b703a691)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2001 Atsushi Onoe
8  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * Alternatively, this software may be distributed under the terms of the
23  * GNU General Public License ("GPL") version 2 as published by the Free
24  * Software Foundation.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * IEEE 802.11 generic handler
40  */
41 
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/cmn_err.h>
45 #include <sys/modctl.h>
46 #include <sys/stropts.h>
47 #include <sys/door.h>
48 #include <sys/mac_provider.h>
49 #include "net80211_impl.h"
50 
51 uint32_t ieee80211_debug = 0x0;	/* debug msg flags */
52 
53 const char *ieee80211_phymode_name[] = {
54 	"auto",		/* IEEE80211_MODE_AUTO */
55 	"11a",		/* IEEE80211_MODE_11A */
56 	"11b",		/* IEEE80211_MODE_11B */
57 	"11g",		/* IEEE80211_MODE_11G */
58 	"FH",		/* IEEE80211_MODE_FH */
59 	"turboA",	/* IEEE80211_MODE_TURBO_A */
60 	"turboG",	/* IEEE80211_MODE_TURBO_G */
61 };
62 
63 #define	IEEE80211_DPRINT(_level, _fmt)	do {	\
64 		_NOTE(CONSTCOND)		\
65 		va_list ap;			\
66 		va_start(ap, (_fmt));		\
67 		vcmn_err((_level), (_fmt), ap);	\
68 		va_end(ap);			\
69 		_NOTE(CONSTCOND)		\
70 	} while (0)
71 
72 /*
73  * Print error messages
74  */
75 void
76 ieee80211_err(const int8_t *fmt, ...)
77 {
78 	IEEE80211_DPRINT(CE_WARN, fmt);
79 }
80 
81 /*
82  * Print debug messages
83  */
84 void
85 ieee80211_dbg(uint32_t flag, const int8_t *fmt, ...)
86 {
87 	if (flag & ieee80211_debug)
88 		IEEE80211_DPRINT(CE_CONT, fmt);
89 }
90 
91 /*
92  * Alloc memory, and save the size
93  */
94 void *
95 ieee80211_malloc(size_t size)
96 {
97 	void *p = kmem_zalloc((size + 4), KM_SLEEP);
98 	*(int *)p = size;
99 	p = (char *)p + 4;
100 
101 	return (p);
102 }
103 
104 void
105 ieee80211_free(void *p)
106 {
107 	void *tp = (char *)p - 4;
108 	kmem_free((char *)p - 4, *(int *)tp + 4);
109 }
110 
111 void
112 ieee80211_mac_update(ieee80211com_t *ic)
113 {
114 	wifi_data_t wd = { 0 };
115 	ieee80211_node_t *in;
116 
117 	/*
118 	 * We can send data now; update the fastpath with our
119 	 * current associated BSSID and other relevant settings.
120 	 */
121 	in = ic->ic_bss;
122 	wd.wd_secalloc = ieee80211_crypto_getciphertype(ic);
123 	wd.wd_opmode = ic->ic_opmode;
124 	IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid);
125 	(void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
126 	mac_tx_update(ic->ic_mach);
127 	ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_mac_update"
128 	    "(cipher = %d)\n", wd.wd_secalloc);
129 }
130 
131 /*
132  * ieee80211_event_thread
133  * open door of wpa, send event to wpad service
134  */
135 static void
136 ieee80211_event_thread(void *arg)
137 {
138 	ieee80211com_t *ic = arg;
139 	door_handle_t event_door = NULL;	/* Door for upcalls */
140 	wl_events_t ev;
141 	door_arg_t darg;
142 
143 	mutex_enter(&ic->ic_doorlock);
144 
145 	ev.event = ic->ic_eventq[ic->ic_evq_head];
146 	ic->ic_evq_head ++;
147 	if (ic->ic_evq_head >= MAX_EVENT)
148 		ic->ic_evq_head = 0;
149 
150 	ieee80211_dbg(IEEE80211_MSG_DEBUG, "ieee80211_event(%d)\n", ev.event);
151 	/*
152 	 * Locate the door used for upcalls
153 	 */
154 	if (door_ki_open(ic->ic_wpadoor, &event_door) != 0) {
155 		ieee80211_err("ieee80211_event: door_ki_open(%s) failed\n",
156 		    ic->ic_wpadoor);
157 		goto out;
158 	}
159 
160 	darg.data_ptr = (char *)&ev;
161 	darg.data_size = sizeof (wl_events_t);
162 	darg.desc_ptr = NULL;
163 	darg.desc_num = 0;
164 	darg.rbuf = NULL;
165 	darg.rsize = 0;
166 
167 	if (door_ki_upcall_limited(event_door, &darg, NULL, SIZE_MAX, 0) != 0) {
168 		ieee80211_err("ieee80211_event: door_ki_upcall() failed\n");
169 	}
170 
171 	if (event_door) {	/* release our hold (if any) */
172 		door_ki_rele(event_door);
173 	}
174 
175 out:
176 	mutex_exit(&ic->ic_doorlock);
177 }
178 
179 /*
180  * Notify state transition event message to WPA daemon
181  */
182 void
183 ieee80211_notify(ieee80211com_t *ic, wpa_event_type event)
184 {
185 	if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
186 		return;		/* Not running on WPA mode */
187 
188 	ic->ic_eventq[ic->ic_evq_tail] = event;
189 	ic->ic_evq_tail ++;
190 	if (ic->ic_evq_tail >= MAX_EVENT) ic->ic_evq_tail = 0;
191 
192 	/* async */
193 	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
194 }
195 
196 /*
197  * Register WPA door
198  */
199 void
200 ieee80211_register_door(ieee80211com_t *ic, const char *drvname, int inst)
201 {
202 	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d",
203 	    WPA_DOOR, drvname, inst);
204 }
205 
206 /*
207  * Default reset method for use with the ioctl support.  This
208  * method is invoked after any state change in the 802.11
209  * layer that should be propagated to the hardware but not
210  * require re-initialization of the 802.11 state machine (e.g
211  * rescanning for an ap).  We always return ENETRESET which
212  * should cause the driver to re-initialize the device. Drivers
213  * can override this method to implement more optimized support.
214  */
215 /* ARGSUSED */
216 static int
217 ieee80211_default_reset(ieee80211com_t *ic)
218 {
219 	return (ENETRESET);
220 }
221 
222 /*
223  * Convert channel to IEEE channel number.
224  */
225 uint32_t
226 ieee80211_chan2ieee(ieee80211com_t *ic, struct ieee80211_channel *ch)
227 {
228 	if ((ic->ic_sup_channels <= ch) &&
229 	    (ch <= &ic->ic_sup_channels[IEEE80211_CHAN_MAX])) {
230 		return (ch - ic->ic_sup_channels);
231 	} else if (ch == IEEE80211_CHAN_ANYC) {
232 		return (IEEE80211_CHAN_ANY);
233 	} else if (ch != NULL) {
234 		ieee80211_err("invalid channel freq %u flags %x\n",
235 		    ch->ich_freq, ch->ich_flags);
236 		return (0);
237 	}
238 	ieee80211_err("invalid channel (NULL)\n");	/* ch == NULL */
239 	return (0);
240 }
241 
242 /*
243  * Convert IEEE channel number to MHz frequency.
244  *    chan    IEEE channel number
245  *    flags   specify whether the frequency is in the 2GHz ISM
246  *            band or the 5GHz band
247  *
248  * 802.11b 2GHz: 14 channels, each 5 MHz wide. Channel 1 is placed
249  * at 2.412 GHz, channel 2 at 2.417 GHz, and so on up to channel 13
250  * at 2.472 GHz. Channel 14 was defined especially for operation in
251  * Japan, and has a center frequency 2.484 GHz.
252  * 802.11g 2GHz: adopts the frequency plan of 802.11b. Japan only
253  * allows 802.11g operation in channels 1-13
254  * 802.11a 5GHz: starting every 5 MHz
255  * 802.11b/g channels 15-24 (2512-2692) are used by some implementation
256  * (Atheros etc.)
257  */
258 uint32_t
259 ieee80211_ieee2mhz(uint32_t chan, uint32_t flags)
260 {
261 	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
262 		if (chan == 14)
263 			return (2484);
264 		if (chan < 14)
265 			return (2412 + (chan - 1) * 5);
266 		else
267 			return (2512 + ((chan - 15) * 20));
268 	} else if (flags & IEEE80211_CHAN_5GHZ) {	/* 5Ghz band */
269 		return (5000 + (chan * 5));	/* OFDM */
270 	} else {				/* either, guess */
271 		if (chan == 14)
272 			return (2484);
273 		if (chan < 14)			/* 0-13 */
274 			return (2412 + (chan - 1) * 5);
275 		if (chan < 27)			/* 15-26 */
276 			return (2512 + ((chan - 15) * 20));
277 		return (5000 + (chan * 5));
278 	}
279 }
280 
281 /*
282  * Do late attach work. It must be called by the driver after
283  * calling ieee80211_attach() and before calling most ieee80211
284  * functions.
285  */
286 void
287 ieee80211_media_init(ieee80211com_t *ic)
288 {
289 	/*
290 	 * Do late attach work that must wait for any subclass
291 	 * (i.e. driver) work such as overriding methods.
292 	 */
293 	ieee80211_node_lateattach(ic);
294 }
295 
296 /*
297  * Start Watchdog timer. After count down timer(s), ic_watchdog
298  * will be called
299  */
300 void
301 ieee80211_start_watchdog(ieee80211com_t *ic, uint32_t timer)
302 {
303 	if (ic->ic_watchdog_timer == 0 && ic->ic_watchdog != NULL) {
304 		ic->ic_watchdog_timer = timeout(ic->ic_watchdog, ic,
305 		    drv_usectohz(1000000 * timer));
306 	}
307 }
308 
309 /*
310  * Stop watchdog timer.
311  */
312 void
313 ieee80211_stop_watchdog(ieee80211com_t *ic)
314 {
315 	if (ic->ic_watchdog_timer != 0) {
316 		if (ic->ic_watchdog != NULL)
317 			(void) untimeout(ic->ic_watchdog_timer);
318 		ic->ic_watchdog_timer = 0;
319 	}
320 }
321 
322 /*
323  * Called from a driver's xxx_watchdog routine. It is used to
324  * perform periodic cleanup of state for net80211, as well as
325  * timeout scans.
326  */
327 void
328 ieee80211_watchdog(void *arg)
329 {
330 	ieee80211com_t *ic = arg;
331 	struct ieee80211_impl *im = ic->ic_private;
332 	ieee80211_node_table_t *nt;
333 	int inact_timer = 0;
334 
335 	if (ic->ic_state == IEEE80211_S_INIT)
336 		return;
337 
338 	IEEE80211_LOCK(ic);
339 	if ((im->im_mgt_timer != 0) && (--im->im_mgt_timer == 0)) {
340 		IEEE80211_UNLOCK(ic);
341 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
342 		IEEE80211_LOCK(ic);
343 	}
344 
345 	nt = &ic->ic_scan;
346 	if (nt->nt_inact_timer != 0) {
347 		if (--nt->nt_inact_timer == 0)
348 			nt->nt_timeout(nt);
349 		inact_timer += nt->nt_inact_timer;
350 	}
351 	nt = &ic->ic_sta;
352 	if (nt->nt_inact_timer != 0) {
353 		if (--nt->nt_inact_timer == 0)
354 			nt->nt_timeout(nt);
355 		inact_timer += nt->nt_inact_timer;
356 	}
357 
358 	IEEE80211_UNLOCK(ic);
359 
360 	if (im->im_mgt_timer != 0 || inact_timer > 0)
361 		ieee80211_start_watchdog(ic, 1);
362 }
363 
364 /*
365  * Set the current phy mode and recalculate the active channel
366  * set and supported rates based on the available channels for
367  * this mode. Also select a new BSS channel if the current one
368  * is inappropriate for this mode.
369  * This function is called by net80211, and not intended to be
370  * called directly.
371  */
372 static int
373 ieee80211_setmode(ieee80211com_t *ic, enum ieee80211_phymode mode)
374 {
375 	static const uint32_t chanflags[] = {
376 		0,			/* IEEE80211_MODE_AUTO */
377 		IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
378 		IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
379 		IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
380 		IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
381 		IEEE80211_CHAN_T,	/* IEEE80211_MODE_TURBO_A */
382 		IEEE80211_CHAN_108G,	/* IEEE80211_MODE_TURBO_G */
383 	};
384 	struct ieee80211_channel *ch;
385 	uint32_t modeflags;
386 	int i;
387 	int achannels = 0;
388 
389 	/* validate new mode */
390 	if ((ic->ic_modecaps & (1 << mode)) == 0) {
391 		ieee80211_err("ieee80211_setmode(): mode %u not supported"
392 		    " (caps 0x%x)\n", mode, ic->ic_modecaps);
393 		return (EINVAL);
394 	}
395 
396 	/*
397 	 * Verify at least one channel is present in the available
398 	 * channel list before committing to the new mode.
399 	 * Calculate the active channel set.
400 	 */
401 	ASSERT(mode < IEEE80211_N(chanflags));
402 	modeflags = chanflags[mode];
403 	bzero(ic->ic_chan_active, sizeof (ic->ic_chan_active));
404 	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
405 		ch = &ic->ic_sup_channels[i];
406 		if (ch->ich_flags == 0)
407 			continue;
408 		if (mode == IEEE80211_MODE_AUTO) {
409 			/* take anything but pure turbo channels */
410 			if ((ch->ich_flags & ~IEEE80211_CHAN_TURBO) != 0) {
411 				ieee80211_setbit(ic->ic_chan_active, i);
412 				achannels++;
413 			}
414 		} else {
415 			if ((ch->ich_flags & modeflags) == modeflags) {
416 				ieee80211_setbit(ic->ic_chan_active, i);
417 				achannels++;
418 			}
419 		}
420 	}
421 	if (achannels == 0) {
422 		ieee80211_err("ieee80211_setmode(): "
423 		    "no channel found for mode %u\n", mode);
424 		return (EINVAL);
425 	}
426 
427 	/*
428 	 * If no current/default channel is setup or the current
429 	 * channel is wrong for the mode then pick the first
430 	 * available channel from the active list.  This is likely
431 	 * not the right one.
432 	 */
433 	if (ic->ic_ibss_chan == NULL ||
434 	    ieee80211_isclr(ic->ic_chan_active,
435 	    ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
436 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
437 			if (ieee80211_isset(ic->ic_chan_active, i)) {
438 				ic->ic_ibss_chan = &ic->ic_sup_channels[i];
439 				break;
440 			}
441 		}
442 	}
443 	/*
444 	 * If the desired channel is set but no longer valid then reset it.
445 	 */
446 	if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
447 	    ieee80211_isclr(ic->ic_chan_active,
448 	    ieee80211_chan2ieee(ic, ic->ic_des_chan))) {
449 		ic->ic_des_chan = IEEE80211_CHAN_ANYC;
450 	}
451 
452 	/*
453 	 * Do mode-specific rate setup.
454 	 */
455 	if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B)
456 		ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode);
457 
458 	/*
459 	 * Setup an initial rate set according to the
460 	 * current/default channel.  This will be changed
461 	 * when scanning but must exist now so drivers have
462 	 * consistent state of ic_bsschan.
463 	 */
464 	if (ic->ic_bss != NULL)
465 		ic->ic_bss->in_rates = ic->ic_sup_rates[mode];
466 	ic->ic_curmode = mode;
467 	ieee80211_reset_erp(ic);	/* reset ERP state */
468 
469 	return (0);
470 }
471 
472 /*
473  * Return the phy mode for with the specified channel so the
474  * caller can select a rate set.  This is problematic for channels
475  * where multiple operating modes are possible (e.g. 11g+11b).
476  * In those cases we defer to the current operating mode when set.
477  */
478 enum ieee80211_phymode
479 ieee80211_chan2mode(ieee80211com_t *ic, struct ieee80211_channel *chan)
480 {
481 	if (IEEE80211_IS_CHAN_T(chan)) {
482 		return (IEEE80211_MODE_TURBO_A);
483 	} else if (IEEE80211_IS_CHAN_5GHZ(chan)) {
484 		return (IEEE80211_MODE_11A);
485 	} else if (IEEE80211_IS_CHAN_FHSS(chan)) {
486 		return (IEEE80211_MODE_FH);
487 	} else if (chan->ich_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) {
488 		/*
489 		 * This assumes all 11g channels are also usable
490 		 * for 11b, which is currently true.
491 		 */
492 		if (ic->ic_curmode == IEEE80211_MODE_TURBO_G)
493 			return (IEEE80211_MODE_TURBO_G);
494 		if (ic->ic_curmode == IEEE80211_MODE_11B)
495 			return (IEEE80211_MODE_11B);
496 		return (IEEE80211_MODE_11G);
497 	} else {
498 		return (IEEE80211_MODE_11B);
499 	}
500 }
501 
502 /*
503  * Return the size of the 802.11 header for a management or data frame.
504  */
505 int
506 ieee80211_hdrspace(const void *data)
507 {
508 	const struct ieee80211_frame *wh = data;
509 	int size = sizeof (struct ieee80211_frame);
510 
511 	/* NB: we don't handle control frames */
512 	ASSERT((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) !=
513 	    IEEE80211_FC0_TYPE_CTL);
514 	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
515 		size += IEEE80211_ADDR_LEN;
516 
517 	return (size);
518 }
519 
520 /*
521  * Allocate and setup a management frame of the specified
522  * size.  We return the mblk and a pointer to the start
523  * of the contiguous data area that's been reserved based
524  * on the packet length.
525  */
526 mblk_t *
527 ieee80211_getmgtframe(uint8_t **frm, int pktlen)
528 {
529 	mblk_t *mp;
530 	int len;
531 
532 	len = sizeof (struct ieee80211_frame) + pktlen;
533 	mp = allocb(len, BPRI_MED);
534 	if (mp != NULL) {
535 		*frm = mp->b_rptr + sizeof (struct ieee80211_frame);
536 		mp->b_wptr = mp->b_rptr + len;
537 	} else {
538 		ieee80211_err("ieee80211_getmgtframe: "
539 		    "alloc frame failed, %d\n", len);
540 	}
541 	return (mp);
542 }
543 
544 /*
545  * Send system messages to notify the device has joined a WLAN.
546  * This is an OS specific function. Solaris marks link status
547  * as up.
548  */
549 void
550 ieee80211_notify_node_join(ieee80211com_t *ic, ieee80211_node_t *in)
551 {
552 	if (in == ic->ic_bss)
553 		mac_link_update(ic->ic_mach, LINK_STATE_UP);
554 	ieee80211_notify(ic, EVENT_ASSOC);	/* notify WPA service */
555 }
556 
557 /*
558  * Send system messages to notify the device has left a WLAN.
559  * This is an OS specific function. Solaris marks link status
560  * as down.
561  */
562 void
563 ieee80211_notify_node_leave(ieee80211com_t *ic, ieee80211_node_t *in)
564 {
565 	if (in == ic->ic_bss)
566 		mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
567 	ieee80211_notify(ic, EVENT_DISASSOC);	/* notify WPA service */
568 }
569 
570 /*
571  * Get 802.11 kstats defined in ieee802.11(5)
572  *
573  * Return 0 on success
574  */
575 int
576 ieee80211_stat(ieee80211com_t *ic, uint_t stat, uint64_t *val)
577 {
578 	ASSERT(val != NULL);
579 	IEEE80211_LOCK(ic);
580 	switch (stat) {
581 	case WIFI_STAT_TX_FRAGS:
582 		*val = ic->ic_stats.is_tx_frags;
583 		break;
584 	case WIFI_STAT_MCAST_TX:
585 		*val = ic->ic_stats.is_tx_mcast;
586 		break;
587 	case WIFI_STAT_TX_FAILED:
588 		*val = ic->ic_stats.is_tx_failed;
589 		break;
590 	case WIFI_STAT_TX_RETRANS:
591 		*val = ic->ic_stats.is_tx_retries;
592 		break;
593 	case WIFI_STAT_RTS_SUCCESS:
594 		*val = ic->ic_stats.is_rts_success;
595 		break;
596 	case WIFI_STAT_RTS_FAILURE:
597 		*val = ic->ic_stats.is_rts_failure;
598 		break;
599 	case WIFI_STAT_ACK_FAILURE:
600 		*val = ic->ic_stats.is_ack_failure;
601 		break;
602 	case WIFI_STAT_RX_FRAGS:
603 		*val = ic->ic_stats.is_rx_frags;
604 		break;
605 	case WIFI_STAT_MCAST_RX:
606 		*val = ic->ic_stats.is_rx_mcast;
607 		break;
608 	case WIFI_STAT_RX_DUPS:
609 		*val = ic->ic_stats.is_rx_dups;
610 		break;
611 	case WIFI_STAT_FCS_ERRORS:
612 		*val = ic->ic_stats.is_fcs_errors;
613 		break;
614 	case WIFI_STAT_WEP_ERRORS:
615 		*val = ic->ic_stats.is_wep_errors;
616 		break;
617 	}
618 	IEEE80211_UNLOCK(ic);
619 	return (0);
620 }
621 
622 /*
623  * Attach network interface to the 802.11 support module. This
624  * function must be called before using any of the ieee80211
625  * functionss. The parameter "ic" MUST be initialized to tell
626  * net80211 about interface's capabilities.
627  */
628 void
629 ieee80211_attach(ieee80211com_t *ic)
630 {
631 	struct ieee80211_impl		*im;
632 	struct ieee80211_channel	*ch;
633 	int				i;
634 
635 	/* Check mandatory callback functions not NULL */
636 	ASSERT(ic->ic_xmit != NULL);
637 
638 	mutex_init(&ic->ic_genlock, NULL, MUTEX_DRIVER, NULL);
639 	mutex_init(&ic->ic_doorlock, NULL, MUTEX_DRIVER, NULL);
640 
641 	im = kmem_alloc(sizeof (ieee80211_impl_t), KM_SLEEP);
642 	ic->ic_private = im;
643 	cv_init(&im->im_scan_cv, NULL, CV_DRIVER, NULL);
644 
645 	/*
646 	 * Fill in 802.11 available channel set, mark
647 	 * all available channels as active, and pick
648 	 * a default channel if not already specified.
649 	 */
650 	bzero(im->im_chan_avail, sizeof (im->im_chan_avail));
651 	ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO;
652 	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
653 		ch = &ic->ic_sup_channels[i];
654 		if (ch->ich_flags) {
655 			/* Verify driver passed us valid data */
656 			if (i != ieee80211_chan2ieee(ic, ch)) {
657 				ieee80211_err("bad channel ignored: "
658 				    "freq %u flags%x number %u\n",
659 				    ch->ich_freq, ch->ich_flags, i);
660 				ch->ich_flags = 0;
661 				continue;
662 			}
663 			ieee80211_setbit(im->im_chan_avail, i);
664 			/* Identify mode capabilities */
665 			if (IEEE80211_IS_CHAN_A(ch))
666 				ic->ic_modecaps |= 1 << IEEE80211_MODE_11A;
667 			if (IEEE80211_IS_CHAN_B(ch))
668 				ic->ic_modecaps |= 1 << IEEE80211_MODE_11B;
669 			if (IEEE80211_IS_CHAN_PUREG(ch))
670 				ic->ic_modecaps |= 1 << IEEE80211_MODE_11G;
671 			if (IEEE80211_IS_CHAN_FHSS(ch))
672 				ic->ic_modecaps |= 1 << IEEE80211_MODE_FH;
673 			if (IEEE80211_IS_CHAN_T(ch))
674 				ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_A;
675 			if (IEEE80211_IS_CHAN_108G(ch))
676 				ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_G;
677 			if (ic->ic_curchan == NULL) {
678 				/* arbitrarily pick the first channel */
679 				ic->ic_curchan = &ic->ic_sup_channels[i];
680 			}
681 		}
682 	}
683 	/* validate ic->ic_curmode */
684 	if ((ic->ic_modecaps & (1 << ic->ic_curmode)) == 0)
685 		ic->ic_curmode = IEEE80211_MODE_AUTO;
686 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;	/* any channel is ok */
687 	(void) ieee80211_setmode(ic, ic->ic_curmode);
688 
689 	if (ic->ic_caps & IEEE80211_C_BURST)
690 		ic->ic_flags |= IEEE80211_F_BURST;
691 	ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
692 	ic->ic_lintval = ic->ic_bintval;
693 	ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
694 	ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
695 
696 	ic->ic_reset = ieee80211_default_reset;
697 
698 	ieee80211_node_attach(ic);
699 	ieee80211_proto_attach(ic);
700 	ieee80211_crypto_attach(ic);
701 
702 	ic->ic_watchdog_timer = 0;
703 }
704 
705 /*
706  * Free any ieee80211 structures associated with the driver.
707  */
708 void
709 ieee80211_detach(ieee80211com_t *ic)
710 {
711 	struct ieee80211_impl *im = ic->ic_private;
712 
713 	ieee80211_stop_watchdog(ic);
714 	cv_destroy(&im->im_scan_cv);
715 	kmem_free(im, sizeof (ieee80211_impl_t));
716 
717 	if (ic->ic_opt_ie != NULL)
718 		ieee80211_free(ic->ic_opt_ie);
719 
720 	ieee80211_node_detach(ic);
721 	ieee80211_crypto_detach(ic);
722 
723 	mutex_destroy(&ic->ic_genlock);
724 	mutex_destroy(&ic->ic_doorlock);
725 }
726 
727 static struct modlmisc	i_wifi_modlmisc = {
728 	&mod_miscops,
729 	"IEEE80211 Kernel Module v1.3"
730 };
731 
732 static struct modlinkage	i_wifi_modlinkage = {
733 	MODREV_1,
734 	&i_wifi_modlmisc,
735 	NULL
736 };
737 
738 /*
739  * modlinkage functions
740  */
741 int
742 _init(void)
743 {
744 	return (mod_install(&i_wifi_modlinkage));
745 }
746 
747 int
748 _fini(void)
749 {
750 	return (mod_remove(&i_wifi_modlinkage));
751 }
752 
753 int
754 _info(struct modinfo *modinfop)
755 {
756 	return (mod_info(&i_wifi_modlinkage, modinfop));
757 }
758