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