xref: /illumos-gate/usr/src/uts/common/io/net80211/net80211_ioctl.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * Alternatively, this software may be distributed under the terms of the
19  * GNU General Public License ("GPL") version 2 as published by the Free
20  * Software Foundation.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/errno.h>
38 #include <sys/strsun.h>
39 #include <sys/policy.h>
40 #include <inet/common.h>
41 #include <inet/nd.h>
42 #include <inet/mi.h>
43 #include <sys/note.h>
44 #include <sys/mac_provider.h>
45 #include <inet/wifi_ioctl.h>
46 #include "net80211_impl.h"
47 
48 static int wl_set_essid(struct ieee80211com *, const void *);
49 static void wl_get_essid(struct ieee80211com *, void *);
50 static int wl_set_bssid(struct ieee80211com *, const void *);
51 static void wl_get_bssid(struct ieee80211com *, void *);
52 static int wl_set_bsstype(struct ieee80211com *, const void *);
53 static void wl_get_bsstype(struct ieee80211com *, void *);
54 static void wl_get_linkstatus(struct ieee80211com *, void *);
55 static int wl_set_desrates(struct ieee80211com *, const void *);
56 static void wl_get_desrates(struct ieee80211com *, void *);
57 static int wl_set_authmode(struct ieee80211com *, const void *);
58 static void wl_get_authmode(struct ieee80211com *, void *);
59 static int wl_set_encrypt(struct ieee80211com *, const void *);
60 static void wl_get_encrypt(struct ieee80211com *, void *);
61 static void wl_get_rssi(struct ieee80211com *, void *);
62 static int wl_set_phy(struct ieee80211com *, const void *);
63 static int wl_get_phy(struct ieee80211com *, void *);
64 static void wl_get_capability(struct ieee80211com *, void *);
65 static int wl_set_wpa(struct ieee80211com *, const void *);
66 static void wl_get_wpa(struct ieee80211com *, void *);
67 static void wl_get_scanresults(struct ieee80211com *, void *);
68 static void wl_get_esslist(struct ieee80211com *, void *);
69 static int wl_set_wepkey(struct ieee80211com *, const void *);
70 static int wl_set_optie(struct ieee80211com *, const void *);
71 static int wl_set_delkey(struct ieee80211com *, const void *);
72 static int wl_set_mlme(struct ieee80211com *, const void *);
73 static int wl_set_wpakey(struct ieee80211com *, const void *);
74 static void wl_get_suprates(struct ieee80211com *, void *);
75 
76 static size_t
77 wifi_strnlen(const char *s, size_t n)
78 {
79 	size_t i;
80 
81 	for (i = 0; i < n && s[i] != '\0'; i++)
82 		/* noop */;
83 	return (i);
84 }
85 
86 /*
87  * Initialize an output message block by copying from an
88  * input message block. The message is of type wldp_t.
89  *    mp     input message block
90  *    buflen length of wldp_buf
91  */
92 static void
93 wifi_setupoutmsg(mblk_t *mp, int buflen)
94 {
95 	wldp_t *wp;
96 
97 	wp = (wldp_t *)mp->b_rptr;
98 	wp->wldp_length = WIFI_BUF_OFFSET + buflen;
99 	wp->wldp_result = WL_SUCCESS;
100 	mp->b_wptr = mp->b_rptr + wp->wldp_length;
101 }
102 
103 /*
104  * Allocate and initialize an output message.
105  */
106 static mblk_t *
107 wifi_getoutmsg(mblk_t *mp, uint32_t cmd, int buflen)
108 {
109 	mblk_t *mp1;
110 	int size;
111 
112 	size = WIFI_BUF_OFFSET;
113 	if (cmd == WLAN_GET_PARAM)
114 		size += buflen;	/* to hold output parameters */
115 	mp1 = allocb(size, BPRI_HI);
116 	if (mp1 == NULL) {
117 		ieee80211_err("wifi_getoutbuf: allocb %d bytes failed!\n",
118 		    size);
119 		return (NULL);
120 	}
121 
122 	bzero(mp1->b_rptr, size);
123 	bcopy(mp->b_rptr, mp1->b_rptr, WIFI_BUF_OFFSET);
124 	wifi_setupoutmsg(mp1, size - WIFI_BUF_OFFSET);
125 
126 	return (mp1);
127 }
128 
129 static int
130 wifi_cfg_essid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
131 {
132 	mblk_t *omp;
133 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
134 	wldp_t *outp;
135 	wl_essid_t *iw_essid = (wl_essid_t *)inp->wldp_buf;
136 	wl_essid_t *ow_essid;
137 	int err = 0;
138 
139 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_essid_t))) == NULL)
140 		return (ENOMEM);
141 	outp = (wldp_t *)omp->b_rptr;
142 	ow_essid = (wl_essid_t *)outp->wldp_buf;
143 
144 	switch (cmd) {
145 	case WLAN_GET_PARAM:
146 		wl_get_essid(ic, ow_essid);
147 		break;
148 	case WLAN_SET_PARAM:
149 		err = wl_set_essid(ic, iw_essid);
150 		break;
151 	default:
152 		ieee80211_err("wifi_cfg_essid: unknown command %x\n", cmd);
153 		outp->wldp_result = WL_NOTSUPPORTED;
154 		err = EINVAL;
155 		break;
156 	}
157 
158 	freemsg(*mp);
159 	*mp = omp;
160 	return (err);
161 }
162 
163 static int
164 wifi_cfg_bssid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
165 {
166 	mblk_t *omp;
167 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
168 	wldp_t *outp;
169 	int err = 0;
170 
171 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bssid_t))) == NULL)
172 		return (ENOMEM);
173 	outp = (wldp_t *)omp->b_rptr;
174 
175 	switch (cmd) {
176 	case  WLAN_GET_PARAM:
177 		wl_get_bssid(ic, outp->wldp_buf);
178 		break;
179 	case WLAN_SET_PARAM:
180 		err = wl_set_bssid(ic, inp->wldp_buf);
181 		ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_bssid: "
182 		    "set bssid=%s\n",
183 		    ieee80211_macaddr_sprintf(inp->wldp_buf));
184 		break;
185 	default:
186 		ieee80211_err("wifi_cfg_bssid: unknown command %x\n", cmd);
187 		outp->wldp_result = WL_NOTSUPPORTED;
188 		err = EINVAL;
189 		break;
190 	}
191 
192 	freemsg(*mp);
193 	*mp = omp;
194 	return (err);
195 }
196 
197 static int
198 wifi_cfg_nodename(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
199 {
200 	mblk_t *omp;
201 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
202 	wldp_t *outp;
203 	wl_nodename_t *iw_name = (wl_nodename_t *)inp->wldp_buf;
204 	wl_nodename_t *ow_name;
205 	char *nodename;
206 	int len, err;
207 
208 	err = 0;
209 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_nodename_t))) == NULL)
210 		return (ENOMEM);
211 	outp = (wldp_t *)omp->b_rptr;
212 	ow_name = (wl_nodename_t *)outp->wldp_buf;
213 
214 	switch (cmd) {
215 	case WLAN_GET_PARAM:
216 		len = wifi_strnlen((const char *)ic->ic_nickname,
217 		    IEEE80211_NWID_LEN);
218 		ow_name->wl_nodename_length = len;
219 		bcopy(ic->ic_nickname, ow_name->wl_nodename_name, len);
220 		break;
221 	case WLAN_SET_PARAM:
222 		if (iw_name->wl_nodename_length > IEEE80211_NWID_LEN) {
223 			ieee80211_err("wifi_cfg_nodename: "
224 			    "node name too long, %u\n",
225 			    iw_name->wl_nodename_length);
226 			outp->wldp_result = WL_NOTSUPPORTED;
227 			err = EINVAL;
228 			break;
229 		}
230 		nodename = iw_name->wl_nodename_name;
231 		nodename[IEEE80211_NWID_LEN] = 0;
232 		ieee80211_dbg(IEEE80211_MSG_CONFIG,
233 		    "wifi_cfg_nodename: set nodename %s, len=%d\n",
234 		    nodename, iw_name->wl_nodename_length);
235 
236 		len = iw_name->wl_nodename_length;
237 		if (len > 0)
238 			bcopy(nodename, ic->ic_nickname, len);
239 		if (len < IEEE80211_NWID_LEN)
240 			ic->ic_nickname[len] = 0;
241 		break;
242 	default:
243 		ieee80211_err("wifi_cfg_nodename: unknown command %x\n", cmd);
244 		outp->wldp_result = WL_NOTSUPPORTED;
245 		err = EINVAL;
246 		break;
247 	}
248 
249 	freemsg(*mp);
250 	*mp = omp;
251 	return (err);
252 }
253 
254 static int
255 wifi_cfg_phy(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
256 {
257 	mblk_t *omp;
258 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
259 	wldp_t *outp;
260 	wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)inp->wldp_buf;
261 	wl_phy_conf_t *ow_phy;
262 	int err = 0;
263 
264 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_phy_conf_t))) == NULL)
265 		return (ENOMEM);
266 	outp = (wldp_t *)omp->b_rptr;
267 	ow_phy = (wl_phy_conf_t *)outp->wldp_buf;
268 
269 	switch (cmd) {
270 	case WLAN_GET_PARAM:
271 		err = wl_get_phy(ic, ow_phy);
272 		break;
273 
274 	case WLAN_SET_PARAM:
275 		err = wl_set_phy(ic, iw_phy);
276 		break;
277 
278 	default:
279 		ieee80211_err("wifi_cfg_phy: unknown command %x\n", cmd);
280 		outp->wldp_result = WL_NOTSUPPORTED;
281 		err = EINVAL;
282 		break;
283 	} /* switch (cmd) */
284 
285 	freemsg(*mp);
286 	*mp = omp;
287 	return (err);
288 }
289 
290 static int
291 wifi_cfg_wepkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
292 {
293 	mblk_t *omp;
294 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
295 	wldp_t *outp;
296 	wl_wep_key_t *iw_wepkey = (wl_wep_key_t *)inp->wldp_buf;
297 	int err = 0;
298 
299 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
300 		return (ENOMEM);
301 	outp = (wldp_t *)omp->b_rptr;
302 
303 	switch (cmd) {
304 	case WLAN_GET_PARAM:
305 		outp->wldp_result = WL_WRITEONLY;
306 		err = EINVAL;
307 		break;
308 	case WLAN_SET_PARAM:
309 		if (inp->wldp_length < sizeof (wl_wep_key_tab_t)) {
310 			ieee80211_err("wifi_cfg_wepkey: "
311 			    "parameter too short, %d, expected %d\n",
312 			    inp->wldp_length, sizeof (wl_wep_key_tab_t));
313 			outp->wldp_result = WL_NOTSUPPORTED;
314 			err = EINVAL;
315 			break;
316 		}
317 
318 		err = wl_set_wepkey(ic, iw_wepkey);
319 		break;
320 	default:
321 		ieee80211_err("wifi_cfg_wepkey: unknown command %x\n", cmd);
322 		outp->wldp_result = WL_NOTSUPPORTED;
323 		err = EINVAL;
324 		break;
325 	}
326 
327 	freemsg(*mp);
328 	*mp = omp;
329 	return (err);
330 }
331 
332 static int
333 wifi_cfg_keyid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
334 {
335 	mblk_t *omp;
336 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
337 	wldp_t *outp;
338 	wl_wep_key_id_t *iw_kid = (wl_wep_key_id_t *)inp->wldp_buf;
339 	wl_wep_key_id_t *ow_kid;
340 	int err = 0;
341 
342 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wep_key_id_t))) == NULL)
343 		return (ENOMEM);
344 	outp = (wldp_t *)omp->b_rptr;
345 	ow_kid = (wl_wep_key_id_t *)outp->wldp_buf;
346 
347 	switch (cmd) {
348 	case WLAN_GET_PARAM:
349 		*ow_kid = (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) ?
350 		    0 : ic->ic_def_txkey;
351 		break;
352 	case  WLAN_SET_PARAM:
353 		if (*iw_kid >= MAX_NWEPKEYS) {
354 			ieee80211_err("wifi_cfg_keyid: "
355 			    "keyid too large, %u\n", *iw_kid);
356 			outp->wldp_result = WL_NOTSUPPORTED;
357 			err = EINVAL;
358 		} else {
359 			ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_keyid: "
360 			    "set keyid=%u\n", *iw_kid);
361 			ic->ic_def_txkey = *iw_kid;
362 			err = ENETRESET;
363 		}
364 		break;
365 	default:
366 		ieee80211_err("wifi_cfg_keyid: unknown command %x\n", cmd);
367 		outp->wldp_result = WL_NOTSUPPORTED;
368 		err = EINVAL;
369 		break;
370 	}
371 
372 	freemsg(*mp);
373 	*mp = omp;
374 	return (err);
375 }
376 
377 static int
378 wifi_cfg_authmode(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
379 {
380 	mblk_t *omp;
381 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
382 	wldp_t *outp;
383 	wl_authmode_t *iw_auth = (wl_authmode_t *)inp->wldp_buf;
384 	wl_authmode_t *ow_auth;
385 	int err = 0;
386 
387 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_authmode_t))) == NULL)
388 		return (ENOMEM);
389 	outp = (wldp_t *)omp->b_rptr;
390 	ow_auth = (wl_authmode_t *)outp->wldp_buf;
391 
392 	switch (cmd) {
393 	case WLAN_GET_PARAM:
394 		wl_get_authmode(ic, ow_auth);
395 		break;
396 	case WLAN_SET_PARAM:
397 		err = wl_set_authmode(ic, iw_auth);
398 		break;
399 	default:
400 		ieee80211_err("wifi_cfg_authmode: unknown command %x\n", cmd);
401 		outp->wldp_result = WL_NOTSUPPORTED;
402 		err = EINVAL;
403 		break;
404 	}
405 
406 	freemsg(*mp);
407 	*mp = omp;
408 	return (err);
409 }
410 
411 static int
412 wifi_cfg_encrypt(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
413 {
414 	mblk_t *omp;
415 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
416 	wldp_t *outp;
417 	wl_encryption_t *iw_encryp = (wl_encryption_t *)inp->wldp_buf;
418 	wl_encryption_t *ow_encryp;
419 	int err = 0;
420 
421 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_encryption_t))) == NULL)
422 		return (ENOMEM);
423 	outp = (wldp_t *)omp->b_rptr;
424 	ow_encryp = (wl_encryption_t *)outp->wldp_buf;
425 
426 	switch (cmd) {
427 	case WLAN_GET_PARAM:
428 		wl_get_encrypt(ic, ow_encryp);
429 		break;
430 	case WLAN_SET_PARAM:
431 		err = wl_set_encrypt(ic, iw_encryp);
432 		break;
433 	default:
434 		ieee80211_err("wifi_cfg_encrypt: unknown command %x\n", cmd);
435 		outp->wldp_result = WL_NOTSUPPORTED;
436 		err = EINVAL;
437 		break;
438 	}
439 
440 	freemsg(*mp);
441 	*mp = omp;
442 	return (err);
443 }
444 
445 static int
446 wifi_cfg_bsstype(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
447 {
448 	mblk_t *omp;
449 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
450 	wldp_t *outp;
451 	wl_bss_type_t *iw_opmode = (wl_bss_type_t *)inp->wldp_buf;
452 	wl_bss_type_t *ow_opmode;
453 	int err = 0;
454 
455 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bss_type_t))) == NULL)
456 		return (ENOMEM);
457 	outp = (wldp_t *)omp->b_rptr;
458 	ow_opmode = (wl_bss_type_t *)outp->wldp_buf;
459 
460 	switch (cmd) {
461 	case WLAN_GET_PARAM:
462 		wl_get_bsstype(ic, ow_opmode);
463 		break;
464 	case  WLAN_SET_PARAM:
465 		if (*iw_opmode == ic->ic_opmode)
466 			break;
467 
468 		err = wl_set_bsstype(ic, iw_opmode);
469 		break;
470 	default:
471 		ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd);
472 		outp->wldp_result = WL_NOTSUPPORTED;
473 		err = EINVAL;
474 		break;
475 	}
476 
477 	freemsg(*mp);
478 	*mp = omp;
479 	return (err);
480 }
481 
482 static int
483 wifi_cfg_createibss(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
484 {
485 	mblk_t *omp;
486 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
487 	wldp_t *outp;
488 	wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)inp->wldp_buf;
489 	wl_create_ibss_t *ow_ibss;
490 	int err = 0;
491 
492 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_create_ibss_t))) == NULL)
493 		return (ENOMEM);
494 	outp = (wldp_t *)omp->b_rptr;
495 	ow_ibss = (wl_create_ibss_t *)outp->wldp_buf;
496 
497 	switch (cmd) {
498 	case WLAN_GET_PARAM:
499 		*ow_ibss = (ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0;
500 		break;
501 	case  WLAN_SET_PARAM:
502 		ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_createibss: "
503 		    "set createibss=%u\n", *iw_ibss);
504 		if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) {
505 			outp->wldp_result = WL_LACK_FEATURE;
506 			err = ENOTSUP;
507 			break;
508 		}
509 		if (*iw_ibss) { /* create ibss */
510 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
511 				ic->ic_flags |= IEEE80211_F_IBSSON;
512 				ic->ic_opmode = IEEE80211_M_IBSS;
513 				/*
514 				 * Yech, slot time may change depending on the
515 				 * operating mode so reset it to be sure
516 				 * everything is setup appropriately.
517 				 */
518 				ieee80211_reset_erp(ic);
519 				err = ENETRESET;
520 			}
521 		} else {
522 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
523 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
524 				err = ENETRESET;
525 			}
526 		}
527 		break;
528 	default:
529 		ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd);
530 		outp->wldp_result = WL_NOTSUPPORTED;
531 		err = EINVAL;
532 		break;
533 	}
534 
535 	freemsg(*mp);
536 	*mp = omp;
537 	return (err);
538 }
539 
540 static int
541 wifi_cfg_linkstatus(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
542 {
543 	mblk_t *omp;
544 	wldp_t *outp;
545 	wl_linkstatus_t *ow_linkstat;
546 	int err = 0;
547 
548 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_linkstatus_t))) == NULL)
549 		return (ENOMEM);
550 	outp = (wldp_t *)omp->b_rptr;
551 	ow_linkstat = (wl_linkstatus_t *)outp->wldp_buf;
552 
553 	switch (cmd) {
554 	case WLAN_GET_PARAM:
555 		wl_get_linkstatus(ic, ow_linkstat);
556 		break;
557 	case WLAN_SET_PARAM:
558 		outp->wldp_result = WL_READONLY;
559 		err = EINVAL;
560 		break;
561 	default:
562 		ieee80211_err("wifi_cfg_linkstatus: unknown command %x\n", cmd);
563 		outp->wldp_result = WL_NOTSUPPORTED;
564 		err = EINVAL;
565 		break;
566 	}
567 
568 	freemsg(*mp);
569 	*mp = omp;
570 	return (err);
571 }
572 
573 static int
574 wifi_cfg_suprates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
575 {
576 	mblk_t *omp;
577 	wldp_t *outp;
578 	wl_rates_t *ow_rates;
579 	int err, buflen;
580 
581 	err = 0;
582 	/* rate value (wl_rates_rates) is of type char */
583 	buflen = offsetof(wl_rates_t, wl_rates_rates) +
584 	    sizeof (char) * IEEE80211_MODE_MAX * IEEE80211_RATE_MAXSIZE;
585 	if ((omp = wifi_getoutmsg(*mp, cmd, buflen)) == NULL)
586 		return (ENOMEM);
587 	outp = (wldp_t *)omp->b_rptr;
588 	ow_rates = (wl_rates_t *)outp->wldp_buf;
589 
590 	switch (cmd) {
591 	case WLAN_GET_PARAM:
592 		(void) wl_get_suprates(ic, ow_rates);
593 		break;
594 	case WLAN_SET_PARAM:
595 		outp->wldp_result = WL_READONLY;
596 		err = EINVAL;
597 		break;
598 	default:
599 		ieee80211_err("wifi_cfg_suprates: unknown command %x\n", cmd);
600 		outp->wldp_result = WL_NOTSUPPORTED;
601 		err = EINVAL;
602 		break;
603 	}
604 
605 	freemsg(*mp);
606 	*mp = omp;
607 	return (err);
608 }
609 
610 static int
611 wifi_cfg_desrates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
612 {
613 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
614 	wl_rates_t *iw_rates = (wl_rates_t *)inp->wldp_buf;
615 	mblk_t *omp;
616 	wldp_t *outp;
617 	wl_rates_t *ow_rates;
618 	int err;
619 
620 	err = 0;
621 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rates_t))) == NULL)
622 		return (ENOMEM);
623 	outp = (wldp_t *)omp->b_rptr;
624 	ow_rates = (wl_rates_t *)outp->wldp_buf;
625 
626 	switch (cmd) {
627 	case  WLAN_GET_PARAM:
628 		wl_get_desrates(ic, ow_rates);
629 		break;
630 	case  WLAN_SET_PARAM:
631 		err = wl_set_desrates(ic, iw_rates);
632 		break;
633 	default:
634 		ieee80211_err("wifi_cfg_desrates: unknown command %x\n", cmd);
635 		outp->wldp_result = WL_NOTSUPPORTED;
636 		err = EINVAL;
637 		break;
638 	}
639 
640 	freemsg(*mp);
641 	*mp = omp;
642 	return (err);
643 }
644 
645 /*
646  * Rescale device's RSSI value to (0, 15) as required by WiFi
647  * driver IOCTLs (PSARC/2003/722)
648  */
649 static wl_rssi_t
650 wifi_getrssi(struct ieee80211_node *in)
651 {
652 	struct ieee80211com *ic = in->in_ic;
653 	wl_rssi_t rssi, max_rssi;
654 
655 	rssi = ic->ic_node_getrssi(in);
656 	max_rssi = (ic->ic_maxrssi == 0) ? IEEE80211_MAXRSSI : ic->ic_maxrssi;
657 	if (rssi == 0)
658 		rssi = 0;
659 	else if (rssi >= max_rssi)
660 		rssi = MAX_RSSI;
661 	else
662 		rssi = rssi * MAX_RSSI / max_rssi + 1;
663 
664 	return (rssi);
665 }
666 
667 static int
668 wifi_cfg_rssi(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
669 {
670 	mblk_t *omp;
671 	wldp_t *outp;
672 	wl_rssi_t *ow_rssi;
673 	int err = 0;
674 
675 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rssi_t))) == NULL)
676 		return (ENOMEM);
677 	outp = (wldp_t *)omp->b_rptr;
678 	ow_rssi = (wl_rssi_t *)outp->wldp_buf;
679 
680 	switch (cmd) {
681 	case  WLAN_GET_PARAM:
682 		*ow_rssi = wifi_getrssi(ic->ic_bss);
683 		break;
684 	case  WLAN_SET_PARAM:
685 		outp->wldp_result = WL_READONLY;
686 		err = EINVAL;
687 		break;
688 	default:
689 		ieee80211_err("wifi_cfg_rssi: unknown command %x\n", cmd);
690 		outp->wldp_result = WL_NOTSUPPORTED;
691 		return (EINVAL);
692 	}
693 
694 	freemsg(*mp);
695 	*mp = omp;
696 	return (err);
697 }
698 
699 /*
700  * maximum scan wait time in second.
701  * Time spent on scaning one channel is usually 100~200ms. The maximum
702  * number of channels defined in wifi_ioctl.h is 99 (MAX_CHANNEL_NUM).
703  * As a result the maximum total scan time is defined as below in ms.
704  */
705 #define	WAIT_SCAN_MAX	(200 * MAX_CHANNEL_NUM)
706 
707 static void
708 wifi_wait_scan(struct ieee80211com *ic)
709 {
710 	ieee80211_impl_t *im = ic->ic_private;
711 
712 	while ((ic->ic_flags & (IEEE80211_F_SCAN | IEEE80211_F_ASCAN)) != 0) {
713 		if (cv_timedwait_sig(&im->im_scan_cv, &ic->ic_genlock,
714 		    ddi_get_lbolt() + drv_usectohz(WAIT_SCAN_MAX * 1000)) !=
715 		    0) {
716 			break;
717 		}
718 	}
719 }
720 
721 #define	WIFI_HAVE_CAP(in, flag)	(((in)->in_capinfo & (flag)) ? 1 : 0)
722 #define	WIFI_HAVE_HTCAP(in)	(((in)->in_htcap != 0) ? 1 : 0)
723 
724 /*
725  * Callback function used by ieee80211_iterate_nodes() in
726  * wifi_cfg_esslist() to get info of each node in a node table
727  *    arg  output buffer, pointer to wl_ess_list_t
728  *    in   each node in the node table
729  */
730 static void
731 wifi_read_ap(void *arg, struct ieee80211_node *in)
732 {
733 	wl_ess_list_t *aps = arg;
734 	ieee80211com_t *ic = in->in_ic;
735 	struct ieee80211_channel *chan = in->in_chan;
736 	struct ieee80211_rateset *rates = &(in->in_rates);
737 	wl_ess_conf_t *conf;
738 	uint8_t *end;
739 	uint_t i, nrates;
740 
741 	end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN -
742 	    sizeof (wl_ess_list_t);
743 	conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num];
744 	if ((uint8_t *)conf > end)
745 		return;
746 
747 	conf->wl_ess_conf_length = sizeof (struct wl_ess_conf);
748 
749 	/* skip newly allocated NULL bss node */
750 	if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr))
751 		return;
752 
753 	conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen;
754 	bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid,
755 	    in->in_esslen);
756 	bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN);
757 	conf->wl_ess_conf_wepenabled =
758 	    (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ?
759 	    WL_ENC_WEP : WL_NOENCRYPTION);
760 	conf->wl_ess_conf_bsstype =
761 	    (in->in_capinfo & IEEE80211_CAPINFO_ESS ?
762 	    WL_BSS_BSS : WL_BSS_IBSS);
763 	conf->wl_ess_conf_sl = wifi_getrssi(in);
764 	conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1);
765 
766 	/* physical (FH, DS, ERP) parameters */
767 	if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) {
768 		wl_ofdm_t *ofdm =
769 		    (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf);
770 		ofdm->wl_ofdm_subtype = WL_OFDM;
771 		ofdm->wl_ofdm_frequency = chan->ich_freq;
772 		ofdm->wl_ofdm_ht_enabled = WIFI_HAVE_HTCAP(in);
773 	} else {
774 		switch (in->in_phytype) {
775 		case IEEE80211_T_FH: {
776 			wl_fhss_t *fhss = (wl_fhss_t *)
777 			    &((conf->wl_phy_conf).wl_phy_fhss_conf);
778 
779 			fhss->wl_fhss_subtype = WL_FHSS;
780 			fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan);
781 			fhss->wl_fhss_dwelltime = in->in_fhdwell;
782 			break;
783 		}
784 		case IEEE80211_T_DS: {
785 			wl_dsss_t *dsss = (wl_dsss_t *)
786 			    &((conf->wl_phy_conf).wl_phy_dsss_conf);
787 
788 			dsss->wl_dsss_subtype = WL_DSSS;
789 			dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan);
790 			dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in,
791 			    IEEE80211_CAPINFO_SHORT_PREAMBLE);
792 			dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in,
793 			    IEEE80211_CAPINFO_CHNL_AGILITY);
794 			dsss->wl_dsss_have_pbcc = dsss->wl_dsss_pbcc_enable =
795 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC);
796 			break;
797 		}
798 		case IEEE80211_T_OFDM: {
799 			wl_erp_t *erp = (wl_erp_t *)
800 			    &((conf->wl_phy_conf).wl_phy_erp_conf);
801 
802 			erp->wl_erp_subtype = WL_ERP;
803 			erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan);
804 			erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in,
805 			    IEEE80211_CAPINFO_SHORT_PREAMBLE);
806 			erp->wl_erp_have_agility = erp->wl_erp_agility_enabled =
807 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_CHNL_AGILITY);
808 			erp->wl_erp_have_pbcc = erp->wl_erp_pbcc_enabled =
809 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC);
810 			erp->wl_erp_dsss_ofdm_enabled =
811 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_DSSSOFDM);
812 			erp->wl_erp_sst_enabled = WIFI_HAVE_CAP(in,
813 			    IEEE80211_CAPINFO_SHORT_SLOTTIME);
814 			erp->wl_erp_ht_enabled = WIFI_HAVE_HTCAP(in);
815 			break;
816 		} /* case IEEE80211_T_OFDM */
817 		} /* switch in->in_phytype */
818 	}
819 
820 	/* supported rates */
821 	nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES);
822 	/*
823 	 * The number of supported rates might exceed
824 	 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates
825 	 * first so userland command could properly show
826 	 * maximum speed of AP
827 	 */
828 	for (i = 0; i < nrates; i++) {
829 		conf->wl_supported_rates[i] =
830 		    rates->ir_rates[rates->ir_nrates - i - 1];
831 	}
832 
833 	aps->wl_ess_list_num++;
834 }
835 
836 static int
837 wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
838 {
839 	mblk_t *omp;
840 	wldp_t *outp;
841 	wl_ess_list_t *ow_aps;
842 	int err = 0;
843 
844 	if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) ==
845 	    NULL) {
846 		return (ENOMEM);
847 	}
848 	outp = (wldp_t *)omp->b_rptr;
849 	ow_aps = (wl_ess_list_t *)outp->wldp_buf;
850 
851 	switch (cmd) {
852 	case WLAN_GET_PARAM:
853 		ow_aps->wl_ess_list_num = 0;
854 		ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps);
855 		outp->wldp_length = WIFI_BUF_OFFSET +
856 		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
857 		    ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t);
858 		omp->b_wptr = omp->b_rptr + outp->wldp_length;
859 		break;
860 	case WLAN_SET_PARAM:
861 		outp->wldp_result = WL_READONLY;
862 		err = EINVAL;
863 		break;
864 	default:
865 		ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd);
866 		outp->wldp_result = WL_NOTSUPPORTED;
867 		err = EINVAL;
868 		break;
869 	}
870 
871 	freemsg(*mp);
872 	*mp = omp;
873 	return (err);
874 }
875 
876 /*
877  * Scan the network for all available ESSs.
878  * IEEE80211_F_SCANONLY is set when current state is INIT. And
879  * with this flag, after scan the state will be changed back to
880  * INIT. The reason is at the end of SCAN stage, the STA will
881  * consequently connect to an AP. Then it looks unreasonable that
882  * for a disconnected device, A SCAN command causes it connected.
883  * So the state is changed back to INIT.
884  */
885 static int
886 wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp)
887 {
888 	int ostate = ic->ic_state;
889 
890 	/*
891 	 * Do not scan when current state is RUN. The reason is
892 	 * when connected, STA is on the same channel as AP. But
893 	 * to do scan, STA have to switch to each available channel,
894 	 * send probe request and wait certian time for probe
895 	 * response/beacon. Then when the STA switches to a channel
896 	 * different than AP's, as a result it cannot send/receive
897 	 * data packets to/from the connected WLAN. This eventually
898 	 * will cause data loss.
899 	 */
900 	if (ostate == IEEE80211_S_RUN)
901 		return (0);
902 
903 	IEEE80211_UNLOCK(ic);
904 
905 	ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
906 	IEEE80211_LOCK(ic);
907 	if (ostate == IEEE80211_S_INIT)
908 		ic->ic_flags |= IEEE80211_F_SCANONLY;
909 
910 	/* Don't wait on WPA mode */
911 	if ((ic->ic_flags & IEEE80211_F_WPA) == 0) {
912 		/* wait scan complete */
913 		wifi_wait_scan(ic);
914 	}
915 
916 	wifi_setupoutmsg(mp, 0);
917 	return (0);
918 }
919 
920 static void
921 wifi_loaddefdata(struct ieee80211com *ic)
922 {
923 	struct ieee80211_node *in = ic->ic_bss;
924 	int i;
925 
926 	ic->ic_des_esslen = 0;
927 	bzero(ic->ic_des_essid, IEEE80211_NWID_LEN);
928 	ic->ic_flags &= ~IEEE80211_F_DESBSSID;
929 	bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN);
930 	bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN);
931 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;
932 	ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
933 	bzero(ic->ic_nickname, IEEE80211_NWID_LEN);
934 	in->in_authmode = IEEE80211_AUTH_OPEN;
935 	ic->ic_flags &= ~IEEE80211_F_PRIVACY;
936 	ic->ic_flags &= ~IEEE80211_F_WPA;	/* mask WPA mode */
937 	ic->ic_evq_head = ic->ic_evq_tail = 0;	/* reset Queue */
938 	ic->ic_def_txkey = 0;
939 	for (i = 0; i < MAX_NWEPKEYS; i++) {
940 		ic->ic_nw_keys[i].wk_keylen = 0;
941 		bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE);
942 	}
943 	ic->ic_curmode = IEEE80211_MODE_AUTO;
944 	ic->ic_flags &= ~IEEE80211_F_IBSSON;
945 	ic->ic_opmode = IEEE80211_M_STA;
946 }
947 
948 static int
949 wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp)
950 {
951 	wifi_loaddefdata(ic);
952 	wifi_setupoutmsg(mp, 0);
953 	return (ENETRESET);
954 }
955 
956 static int
957 wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp)
958 {
959 	if (ic->ic_state != IEEE80211_S_INIT) {
960 		IEEE80211_UNLOCK(ic);
961 		(void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
962 		IEEE80211_LOCK(ic);
963 	}
964 	wifi_loaddefdata(ic);
965 	wifi_setupoutmsg(mp, 0);
966 	return (0);
967 }
968 
969 /*
970  * Get the capabilities of drivers.
971  */
972 static int
973 wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
974 {
975 	mblk_t *omp;
976 	wldp_t *outp;
977 	wl_capability_t *o_caps;
978 	int err = 0;
979 
980 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL)
981 		return (ENOMEM);
982 	outp = (wldp_t *)omp->b_rptr;
983 	o_caps = (wl_capability_t *)outp->wldp_buf;
984 
985 	switch (cmd) {
986 	case WLAN_GET_PARAM:
987 		wl_get_capability(ic, o_caps);
988 		break;
989 	case WLAN_SET_PARAM:
990 		outp->wldp_result = WL_READONLY;
991 		err = EINVAL;
992 		break;
993 	default:
994 		ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd);
995 		outp->wldp_result = WL_NOTSUPPORTED;
996 		err = EINVAL;
997 		break;
998 	}
999 
1000 	freemsg(*mp);
1001 	*mp = omp;
1002 	return (err);
1003 }
1004 
1005 /*
1006  * Operating on WPA mode.
1007  */
1008 static int
1009 wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1010 {
1011 	mblk_t *omp;
1012 	wldp_t *outp;
1013 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1014 	wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf;
1015 	wl_wpa_t *o_wpa;
1016 	int err = 0;
1017 
1018 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL)
1019 		return (ENOMEM);
1020 	outp = (wldp_t *)omp->b_rptr;
1021 	o_wpa = (wl_wpa_t *)outp->wldp_buf;
1022 
1023 	switch (cmd) {
1024 	case WLAN_GET_PARAM:
1025 		wl_get_wpa(ic, o_wpa);
1026 		break;
1027 	case WLAN_SET_PARAM:
1028 		err = wl_set_wpa(ic, wpa);
1029 		break;
1030 	default:
1031 		ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd);
1032 		outp->wldp_result = WL_NOTSUPPORTED;
1033 		err = EINVAL;
1034 		break;
1035 	}
1036 
1037 	freemsg(*mp);
1038 	*mp = omp;
1039 	return (err);
1040 }
1041 
1042 /*
1043  * WPA daemon set the WPA keys.
1044  * The WPA keys are negotiated with APs through wpa service.
1045  */
1046 static int
1047 wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1048 {
1049 	mblk_t *omp;
1050 	wldp_t *outp;
1051 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1052 	wl_key_t *ik = (wl_key_t *)(inp->wldp_buf);
1053 	int err = 0;
1054 
1055 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1056 		return (ENOMEM);
1057 	outp = (wldp_t *)omp->b_rptr;
1058 
1059 	switch (cmd) {
1060 	case WLAN_GET_PARAM:
1061 		outp->wldp_result = WL_WRITEONLY;
1062 		err = EINVAL;
1063 		break;
1064 	case WLAN_SET_PARAM:
1065 		err = wl_set_wpakey(ic, ik);
1066 		break;
1067 	default:
1068 		ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd);
1069 		outp->wldp_result = WL_NOTSUPPORTED;
1070 		err = EINVAL;
1071 		break;
1072 	}
1073 
1074 	freemsg(*mp);
1075 	*mp = omp;
1076 	return (err);
1077 }
1078 
1079 /*
1080  * Delete obsolete keys - keys are dynamically exchanged between APs
1081  * and wpa daemon.
1082  */
1083 static int
1084 wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1085 {
1086 	mblk_t *omp;
1087 	wldp_t *outp;
1088 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1089 	wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf;
1090 	int err = 0;
1091 
1092 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1093 		return (ENOMEM);
1094 	outp = (wldp_t *)omp->b_rptr;
1095 
1096 	switch (cmd) {
1097 	case WLAN_GET_PARAM:
1098 		outp->wldp_result = WL_WRITEONLY;
1099 		err = EINVAL;
1100 		break;
1101 	case WLAN_SET_PARAM:
1102 		err = wl_set_delkey(ic, dk);
1103 		break;
1104 	default:
1105 		ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd);
1106 		outp->wldp_result = WL_NOTSUPPORTED;
1107 		err = EINVAL;
1108 		break;
1109 	}
1110 
1111 	freemsg(*mp);
1112 	*mp = omp;
1113 	return (err);
1114 }
1115 
1116 /*
1117  * The OPTIE will be used in the association request.
1118  */
1119 static int
1120 wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1121 {
1122 	mblk_t *omp;
1123 	wldp_t *outp;
1124 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1125 	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf;
1126 	int err = 0;
1127 
1128 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1129 		return (ENOMEM);
1130 	outp = (wldp_t *)omp->b_rptr;
1131 
1132 	switch (cmd) {
1133 	case WLAN_GET_PARAM:
1134 		outp->wldp_result = WL_WRITEONLY;
1135 		err = EINVAL;
1136 		break;
1137 	case WLAN_SET_PARAM:
1138 		if ((err = wl_set_optie(ic, ie_in)) == EINVAL)
1139 			outp->wldp_result = WL_NOTSUPPORTED;
1140 		break;
1141 	default:
1142 		ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd);
1143 		outp->wldp_result = WL_NOTSUPPORTED;
1144 		err = EINVAL;
1145 		break;
1146 	}
1147 
1148 	freemsg(*mp);
1149 	*mp = omp;
1150 	return (err);
1151 }
1152 
1153 /*
1154  * To be compatible with drivers/tools of OpenSolaris.org,
1155  * we use a different ID to filter out those APs of WPA mode.
1156  */
1157 static int
1158 wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1159 {
1160 	mblk_t *omp;
1161 	wldp_t *outp;
1162 	wl_wpa_ess_t *sr;
1163 	ieee80211_node_t *in;
1164 	ieee80211_node_table_t *nt;
1165 	int len, ap_num = 0;
1166 	int err = 0;
1167 
1168 	if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) ==
1169 	    NULL) {
1170 		return (ENOMEM);
1171 	}
1172 	outp = (wldp_t *)omp->b_rptr;
1173 	sr = (wl_wpa_ess_t *)outp->wldp_buf;
1174 	sr->count = 0;
1175 
1176 	switch (cmd) {
1177 	case WLAN_GET_PARAM:
1178 		ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n");
1179 		nt = &ic->ic_scan;
1180 		IEEE80211_NODE_LOCK(nt);
1181 		in = list_head(&nt->nt_node);
1182 		while (in != NULL) {
1183 			/* filter out non-WPA APs */
1184 			if (in->in_wpa_ie == NULL) {
1185 				in = list_next(&nt->nt_node, in);
1186 				continue;
1187 			}
1188 			bcopy(in->in_bssid, sr->ess[ap_num].bssid,
1189 			    IEEE80211_ADDR_LEN);
1190 			sr->ess[ap_num].ssid_len = in->in_esslen;
1191 			bcopy(in->in_essid, sr->ess[ap_num].ssid,
1192 			    in->in_esslen);
1193 			sr->ess[ap_num].freq = in->in_chan->ich_freq;
1194 
1195 			len = in->in_wpa_ie[1] + 2;
1196 			bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len);
1197 			sr->ess[ap_num].wpa_ie_len = len;
1198 
1199 			ap_num ++;
1200 			in = list_next(&nt->nt_node, in);
1201 		}
1202 		IEEE80211_NODE_UNLOCK(nt);
1203 		sr->count = ap_num;
1204 		outp->wldp_length = WIFI_BUF_OFFSET +
1205 		    offsetof(wl_wpa_ess_t, ess) +
1206 		    sr->count * sizeof (struct wpa_ess);
1207 		omp->b_wptr = omp->b_rptr + outp->wldp_length;
1208 		break;
1209 	case WLAN_SET_PARAM:
1210 		outp->wldp_result = WL_READONLY;
1211 		err = EINVAL;
1212 		break;
1213 	default:
1214 		ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd);
1215 		outp->wldp_result = WL_NOTSUPPORTED;
1216 		err = EINVAL;
1217 		break;
1218 	}
1219 
1220 	freemsg(*mp);
1221 	*mp = omp;
1222 	return (err);
1223 }
1224 
1225 /*
1226  * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC
1227  */
1228 static int
1229 wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1230 {
1231 	mblk_t *omp;
1232 	wldp_t *outp;
1233 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1234 	wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf;
1235 	int err = 0;
1236 
1237 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1238 		return (ENOMEM);
1239 	outp = (wldp_t *)omp->b_rptr;
1240 
1241 	switch (cmd) {
1242 	case WLAN_GET_PARAM:
1243 		outp->wldp_result = WL_WRITEONLY;
1244 		err = EINVAL;
1245 		break;
1246 	case WLAN_SET_PARAM:
1247 		err = wl_set_mlme(ic, mlme);
1248 		break;
1249 	default:
1250 		ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd);
1251 		outp->wldp_result = WL_NOTSUPPORTED;
1252 		err = EINVAL;
1253 		break;
1254 	}
1255 
1256 	freemsg(*mp);
1257 	*mp = omp;
1258 	return (err);
1259 }
1260 
1261 static int
1262 wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd)
1263 {
1264 	mblk_t *mp1 = *mp;
1265 	wldp_t *wp = (wldp_t *)mp1->b_rptr;
1266 	int err = 0;
1267 
1268 	ASSERT(ic != NULL && mp1 != NULL);
1269 	IEEE80211_LOCK_ASSERT(ic);
1270 	if (MBLKL(mp1) < WIFI_BUF_OFFSET) {
1271 		ieee80211_err("wifi_cfg_getset: "
1272 		    "invalid input buffer, size=%d\n", MBLKL(mp1));
1273 		return (EINVAL);
1274 	}
1275 
1276 	switch (wp->wldp_id) {
1277 	/* Commands */
1278 	case WL_SCAN:
1279 		err = wifi_cmd_scan(ic, mp1);
1280 		break;
1281 	case WL_LOAD_DEFAULTS:
1282 		err = wifi_cmd_loaddefaults(ic, mp1);
1283 		break;
1284 	case WL_DISASSOCIATE:
1285 		err = wifi_cmd_disassoc(ic, mp1);
1286 		break;
1287 	/* Parameters */
1288 	case WL_ESSID:
1289 		err = wifi_cfg_essid(ic, cmd, mp);
1290 		break;
1291 	case WL_BSSID:
1292 		err = wifi_cfg_bssid(ic, cmd, mp);
1293 		break;
1294 	case WL_NODE_NAME:
1295 		err = wifi_cfg_nodename(ic, cmd, mp);
1296 		break;
1297 	case WL_PHY_CONFIG:
1298 		err = wifi_cfg_phy(ic, cmd, mp);
1299 		break;
1300 	case WL_WEP_KEY_TAB:
1301 		err = wifi_cfg_wepkey(ic, cmd, mp);
1302 		break;
1303 	case WL_WEP_KEY_ID:
1304 		err = wifi_cfg_keyid(ic, cmd, mp);
1305 		break;
1306 	case WL_AUTH_MODE:
1307 		err = wifi_cfg_authmode(ic, cmd, mp);
1308 		break;
1309 	case WL_ENCRYPTION:
1310 		err = wifi_cfg_encrypt(ic, cmd, mp);
1311 		break;
1312 	case WL_BSS_TYPE:
1313 		err = wifi_cfg_bsstype(ic, cmd, mp);
1314 		break;
1315 	case WL_CREATE_IBSS:
1316 		err = wifi_cfg_createibss(ic, cmd, mp);
1317 		break;
1318 	case WL_DESIRED_RATES:
1319 		err = wifi_cfg_desrates(ic, cmd, mp);
1320 		break;
1321 	case WL_LINKSTATUS:
1322 		err = wifi_cfg_linkstatus(ic, cmd, mp);
1323 		break;
1324 	case WL_ESS_LIST:
1325 		err = wifi_cfg_esslist(ic, cmd, mp);
1326 		break;
1327 	case WL_SUPPORTED_RATES:
1328 		err = wifi_cfg_suprates(ic, cmd, mp);
1329 		break;
1330 	case WL_RSSI:
1331 		err = wifi_cfg_rssi(ic, cmd, mp);
1332 		break;
1333 	/*
1334 	 * WPA IOCTLs
1335 	 */
1336 	case WL_CAPABILITY:
1337 		err = wifi_cfg_caps(ic, cmd, mp);
1338 		break;
1339 	case WL_WPA:
1340 		err = wifi_cfg_wpa(ic, cmd, mp);
1341 		break;
1342 	case WL_KEY:
1343 		err = wifi_cfg_wpakey(ic, cmd, mp);
1344 		break;
1345 	case WL_DELKEY:
1346 		err = wifi_cfg_delkey(ic, cmd, mp);
1347 		break;
1348 	case WL_SETOPTIE:
1349 		err = wifi_cfg_setoptie(ic, cmd, mp);
1350 		break;
1351 	case WL_SCANRESULTS:
1352 		err = wifi_cfg_scanresults(ic, cmd, mp);
1353 		break;
1354 	case WL_MLME:
1355 		err = wifi_cfg_setmlme(ic, cmd, mp);
1356 		break;
1357 	default:
1358 		wifi_setupoutmsg(mp1, 0);
1359 		wp->wldp_result = WL_LACK_FEATURE;
1360 		err = ENOTSUP;
1361 		break;
1362 	}
1363 
1364 	return (err);
1365 }
1366 
1367 /*
1368  * Typically invoked by drivers in response to requests for
1369  * information or to change settings from the userland.
1370  *
1371  * Return value should be checked by WiFi drivers. Return 0
1372  * on success. Otherwise, return non-zero value to indicate
1373  * the error. Driver should operate as below when the return
1374  * error is:
1375  * ENETRESET	Reset wireless network and re-start to join a
1376  *		WLAN. ENETRESET is returned when a configuration
1377  *		parameter has been changed.
1378  *		When acknowledge a M_IOCTL message, thie error
1379  *		is ignored.
1380  */
1381 int
1382 ieee80211_ioctl(struct ieee80211com *ic, queue_t *wq, mblk_t *mp)
1383 {
1384 	struct iocblk *iocp;
1385 	int32_t cmd, err, len;
1386 	boolean_t need_privilege;
1387 	mblk_t *mp1;
1388 
1389 	if (MBLKL(mp) < sizeof (struct iocblk)) {
1390 		ieee80211_err("ieee80211_ioctl: ioctl buffer too short, %u\n",
1391 		    MBLKL(mp));
1392 		miocnak(wq, mp, 0, EINVAL);
1393 		return (EINVAL);
1394 	}
1395 
1396 	/*
1397 	 * Validate the command
1398 	 */
1399 	iocp = (struct iocblk *)mp->b_rptr;
1400 	iocp->ioc_error = 0;
1401 	cmd = iocp->ioc_cmd;
1402 	need_privilege = B_TRUE;
1403 	switch (cmd) {
1404 	case WLAN_SET_PARAM:
1405 	case WLAN_COMMAND:
1406 		break;
1407 	case WLAN_GET_PARAM:
1408 		need_privilege = B_FALSE;
1409 		break;
1410 	default:
1411 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): "
1412 		    "unknown cmd 0x%x\n", cmd);
1413 		miocnak(wq, mp, 0, EINVAL);
1414 		return (EINVAL);
1415 	}
1416 
1417 	if (need_privilege && (err = secpolicy_dl_config(iocp->ioc_cr)) != 0) {
1418 		miocnak(wq, mp, 0, err);
1419 		return (err);
1420 	}
1421 
1422 	IEEE80211_LOCK(ic);
1423 
1424 	/* sanity check */
1425 	mp1 = mp->b_cont;
1426 	if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) ||
1427 	    mp1 == NULL) {
1428 		miocnak(wq, mp, 0, EINVAL);
1429 		IEEE80211_UNLOCK(ic);
1430 		return (EINVAL);
1431 	}
1432 
1433 	/* assuming single data block */
1434 	if (mp1->b_cont != NULL) {
1435 		freemsg(mp1->b_cont);
1436 		mp1->b_cont = NULL;
1437 	}
1438 
1439 	err = wifi_cfg_getset(ic, &mp1, cmd);
1440 	mp->b_cont = mp1;
1441 	IEEE80211_UNLOCK(ic);
1442 
1443 	len = msgdsize(mp1);
1444 	/* ignore ENETRESET when acknowledge the M_IOCTL message */
1445 	if (err == 0 || err == ENETRESET)
1446 		miocack(wq, mp, len, 0);
1447 	else
1448 		miocack(wq, mp, len, err);
1449 
1450 	return (err);
1451 }
1452 
1453 /*
1454  * The following routines are for brussels support
1455  */
1456 
1457 /*
1458  * MAC_PROP_WL_ESSID
1459  */
1460 static int
1461 wl_set_essid(struct ieee80211com *ic, const void *wldp_buf)
1462 {
1463 	int err = 0;
1464 	char *essid;
1465 	wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
1466 
1467 	if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN) {
1468 		ieee80211_err("wl_set_essid: "
1469 		    "essid too long, %u, max %u\n",
1470 		    iw_essid->wl_essid_length, IEEE80211_NWID_LEN);
1471 
1472 		err = EINVAL;
1473 		return (err);
1474 	}
1475 
1476 	essid = iw_essid->wl_essid_essid;
1477 	essid[IEEE80211_NWID_LEN] = 0;
1478 
1479 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_essid: "
1480 	    "set essid=%s length=%d\n",
1481 	    essid, iw_essid->wl_essid_length);
1482 
1483 	ic->ic_des_esslen = iw_essid->wl_essid_length;
1484 	if (ic->ic_des_esslen != 0)
1485 		bcopy(essid, ic->ic_des_essid, ic->ic_des_esslen);
1486 	if (ic->ic_des_esslen < IEEE80211_NWID_LEN)
1487 		ic->ic_des_essid[ic->ic_des_esslen] = 0;
1488 
1489 	err = ENETRESET;
1490 
1491 	return (err);
1492 }
1493 
1494 static void
1495 wl_get_essid(struct ieee80211com *ic, void *wldp_buf)
1496 {
1497 	char *essid;
1498 	wl_essid_t ow_essid;
1499 
1500 	essid = (char *)ic->ic_des_essid;
1501 	if (essid[0] == '\0')
1502 		essid = (char *)ic->ic_bss->in_essid;
1503 
1504 	bzero(&ow_essid, sizeof (wl_essid_t));
1505 	ow_essid.wl_essid_length = wifi_strnlen((const char *)essid,
1506 	    IEEE80211_NWID_LEN);
1507 	bcopy(essid, ow_essid.wl_essid_essid,
1508 	    ow_essid.wl_essid_length);
1509 	bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
1510 
1511 }
1512 
1513 /*
1514  * MAC_PROP_WL_BSSID
1515  */
1516 static int
1517 wl_set_bssid(struct ieee80211com *ic, const void* wldp_buf)
1518 {
1519 
1520 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bssid: "
1521 	    "set bssid=%s\n",
1522 	    ieee80211_macaddr_sprintf(wldp_buf));
1523 
1524 	bcopy(wldp_buf, ic->ic_des_bssid, sizeof (wl_bssid_t));
1525 	ic->ic_flags |= IEEE80211_F_DESBSSID;
1526 
1527 	return (ENETRESET);
1528 }
1529 
1530 static void
1531 wl_get_bssid(struct ieee80211com *ic, void *wldp_buf)
1532 {
1533 	uint8_t *bssid;
1534 
1535 	if (ic->ic_flags & IEEE80211_F_DESBSSID)
1536 		bssid = ic->ic_des_bssid;
1537 	else
1538 		bssid = ic->ic_bss->in_bssid;
1539 	bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
1540 
1541 }
1542 
1543 /*
1544  * MAC_PROP_WL_BSSTYP
1545  */
1546 static int
1547 wl_set_bsstype(struct ieee80211com *ic, const void *wldp_buf)
1548 {
1549 	int err = 0;
1550 	wl_bss_type_t *iw_opmode = (wl_bss_type_t *)wldp_buf;
1551 
1552 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bsstype: "
1553 	    "set bsstype=%u\n", *iw_opmode);
1554 
1555 	switch (*iw_opmode) {
1556 	case WL_BSS_BSS:
1557 		ic->ic_flags &= ~IEEE80211_F_IBSSON;
1558 		ic->ic_opmode = IEEE80211_M_STA;
1559 		err = ENETRESET;
1560 		break;
1561 	case WL_BSS_IBSS:
1562 		if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) {
1563 			err = ENOTSUP;
1564 			break;
1565 		}
1566 
1567 		ic->ic_opmode = IEEE80211_M_IBSS;
1568 		err = ENETRESET;
1569 		break;
1570 	default:
1571 		ieee80211_err("wl_set_bsstype: "
1572 		    "unknown opmode\n");
1573 		err = EINVAL;
1574 		break;
1575 	}
1576 	return (err);
1577 }
1578 
1579 static void
1580 wl_get_bsstype(struct ieee80211com *ic, void *wldp_buf)
1581 {
1582 	wl_bss_type_t ow_opmode;
1583 
1584 	switch (ic->ic_opmode) {
1585 	case IEEE80211_M_STA:
1586 		ow_opmode = WL_BSS_BSS;
1587 		break;
1588 	case IEEE80211_M_IBSS:
1589 		ow_opmode = WL_BSS_IBSS;
1590 		break;
1591 	default:
1592 		ow_opmode = WL_BSS_ANY;
1593 		break;
1594 	}
1595 
1596 	bcopy(&ow_opmode, wldp_buf, sizeof (wl_bss_type_t));
1597 }
1598 
1599 /*
1600  * MAC_PROP_WL_LINKSTATUS
1601  */
1602 static void
1603 wl_get_linkstatus(struct ieee80211com *ic, void *wldp_buf)
1604 {
1605 	wl_linkstatus_t ow_linkstat;
1606 
1607 	ow_linkstat = (ic->ic_state == IEEE80211_S_RUN) ?
1608 	    WL_CONNECTED : WL_NOTCONNECTED;
1609 	if ((ic->ic_flags & IEEE80211_F_WPA) &&
1610 	    (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA)) {
1611 		ow_linkstat = WL_NOTCONNECTED;
1612 	}
1613 
1614 	bcopy(&ow_linkstat, wldp_buf, sizeof (wl_linkstatus_t));
1615 }
1616 
1617 /*
1618  * MAC_PROP_WL_DESIRED_RATESa
1619  */
1620 static int
1621 wl_set_desrates(struct ieee80211com *ic, const void *wldp_buf)
1622 {
1623 	int err = 0;
1624 	int i, j;
1625 	uint8_t drate;
1626 	boolean_t isfound;
1627 	wl_rates_t *iw_rates = (wl_rates_t *)wldp_buf;
1628 	struct ieee80211_node *in = ic->ic_bss;
1629 	struct ieee80211_rateset *rs = &in->in_rates;
1630 
1631 	drate = iw_rates->wl_rates_rates[0];
1632 	if (ic->ic_fixed_rate == drate)
1633 		return (err);
1634 
1635 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_desrates: "
1636 	    "set desired rate=%u\n", drate);
1637 
1638 	if (drate == 0) {
1639 		ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
1640 		if (ic->ic_state == IEEE80211_S_RUN) {
1641 			IEEE80211_UNLOCK(ic);
1642 			ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0);
1643 			IEEE80211_LOCK(ic);
1644 		}
1645 		return (err);
1646 	}
1647 
1648 	/*
1649 	 * Set desired rate. The desired rate is for data transfer
1650 	 * and usally is checked and used when driver changes to
1651 	 * RUN state.
1652 	 * If the driver is in AUTH | ASSOC | RUN state, desired
1653 	 * rate is checked anainst rates supported by current ESS.
1654 	 * If it's supported and current state is AUTH|ASSOC, nothing
1655 	 * needs to be done by driver since the desired rate will
1656 	 * be enabled when the device changes to RUN state. And
1657 	 * when current state is RUN, Re-associate with the ESS to
1658 	 * enable the desired rate.
1659 	 */
1660 
1661 	if (ic->ic_state != IEEE80211_S_INIT &&
1662 	    ic->ic_state != IEEE80211_S_SCAN) {
1663 		for (i = 0; i < rs->ir_nrates; i++) {
1664 			if (drate == IEEE80211_RV(rs->ir_rates[i]))
1665 				break;
1666 		}
1667 		/* supported */
1668 		if (i < rs->ir_nrates) {
1669 			ic->ic_fixed_rate = drate;
1670 			if (ic->ic_state == IEEE80211_S_RUN) {
1671 				IEEE80211_UNLOCK(ic);
1672 				ieee80211_new_state(ic,
1673 				    IEEE80211_S_ASSOC, 0);
1674 				IEEE80211_LOCK(ic);
1675 			}
1676 			return (err);
1677 		}
1678 	}
1679 
1680 	/*
1681 	 * In INIT or SCAN state
1682 	 * check if the desired rate is supported by device
1683 	 */
1684 	isfound = B_FALSE;
1685 	for (i = 0; i < IEEE80211_MODE_MAX; i++) {
1686 		rs = &ic->ic_sup_rates[i];
1687 		for (j = 0; j < rs->ir_nrates; j++) {
1688 			if (drate ==  IEEE80211_RV(rs->ir_rates[j])) {
1689 				isfound = B_TRUE;
1690 				break;
1691 			}
1692 		}
1693 		if (isfound)
1694 			break;
1695 	}
1696 	if (!isfound) {
1697 		ieee80211_err("wl_set_desrates: "
1698 		    "invald rate %d\n", drate);
1699 		err = EINVAL;
1700 		return (err);
1701 	}
1702 	ic->ic_fixed_rate = drate;
1703 	if (ic->ic_state != IEEE80211_S_SCAN)
1704 		err = ENETRESET;
1705 
1706 	return (err);
1707 }
1708 
1709 static void
1710 wl_get_desrates(struct ieee80211com *ic, void *wldp_buf)
1711 {
1712 	uint8_t srate;
1713 	wl_rates_t ow_rates;
1714 	struct ieee80211_node *in = ic->ic_bss;
1715 	struct ieee80211_rateset *rs = &in->in_rates;
1716 
1717 	srate = rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL;
1718 	ow_rates.wl_rates_num = 1;
1719 	ow_rates.wl_rates_rates[0] =
1720 	    (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
1721 	    srate : ic->ic_fixed_rate;
1722 	bcopy(&ow_rates, wldp_buf, sizeof (wl_rates_t));
1723 
1724 }
1725 
1726 /*
1727  * MAC_PROP_AUTH_MODE
1728  */
1729 static int
1730 wl_set_authmode(struct ieee80211com *ic, const void *wldp_buf)
1731 {
1732 	int err = 0;
1733 	wl_authmode_t *iw_auth = (wl_authmode_t *)wldp_buf;
1734 
1735 	if (*iw_auth == ic->ic_bss->in_authmode)
1736 		return (err);
1737 
1738 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_authmode: "
1739 	    "set authmode=%u\n", *iw_auth);
1740 
1741 	switch (*iw_auth) {
1742 	case WL_OPENSYSTEM:
1743 	case WL_SHAREDKEY:
1744 		ic->ic_bss->in_authmode = *iw_auth;
1745 		err = ENETRESET;
1746 		break;
1747 	default:
1748 		ieee80211_err("wl_set_authmode: "
1749 		    "unknown authmode %u\n", *iw_auth);
1750 		err = EINVAL;
1751 		break;
1752 	}
1753 
1754 	return (err);
1755 }
1756 
1757 static void
1758 wl_get_authmode(struct ieee80211com *ic, void *wldp_buf)
1759 {
1760 	wl_authmode_t ow_auth;
1761 
1762 	ow_auth = ic->ic_bss->in_authmode;
1763 	bcopy(&ow_auth, wldp_buf, sizeof (wl_authmode_t));
1764 
1765 }
1766 
1767 /*
1768  * MAC_PROP_WL_ENCRYPTION
1769  */
1770 static int
1771 wl_set_encrypt(struct ieee80211com *ic, const void *wldp_buf)
1772 {
1773 	int err = 0;
1774 	uint32_t flags;
1775 	wl_encryption_t *iw_encryp = (wl_encryption_t *)wldp_buf;
1776 
1777 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_encrypt: "
1778 	    "set encryption=%u\n", *iw_encryp);
1779 
1780 	flags = ic->ic_flags;
1781 	if (*iw_encryp == WL_NOENCRYPTION)
1782 		flags &= ~IEEE80211_F_PRIVACY;
1783 	else
1784 		flags |= IEEE80211_F_PRIVACY;
1785 
1786 	if (ic->ic_flags != flags) {
1787 		ic->ic_flags = flags;
1788 		err = ENETRESET;
1789 	}
1790 
1791 	return (err);
1792 }
1793 
1794 static void
1795 wl_get_encrypt(struct ieee80211com *ic, void *wldp_buf)
1796 {
1797 	wl_encryption_t *ow_encryp;
1798 
1799 	ow_encryp = (wl_encryption_t *)wldp_buf;
1800 	*ow_encryp = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0;
1801 	if (ic->ic_flags & IEEE80211_F_WPA)
1802 		*ow_encryp = WL_ENC_WPA;
1803 
1804 }
1805 
1806 /*
1807  * MAC_PROP_WL_RSSI
1808  */
1809 static void
1810 wl_get_rssi(struct ieee80211com *ic, void *wldp_buf)
1811 {
1812 	wl_rssi_t *ow_rssi;
1813 
1814 	ow_rssi = (wl_rssi_t *)wldp_buf;
1815 	*ow_rssi = wifi_getrssi(ic->ic_bss);
1816 
1817 }
1818 
1819 /*
1820  * MAC_PROP_WL_PHY_CONFIG
1821  */
1822 
1823 static int
1824 wl_set_phy(struct ieee80211com *ic, const void* wldp_buf)
1825 {
1826 	int err = 0;
1827 	int16_t ch;
1828 	wl_dsss_t *dsss;
1829 	wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)wldp_buf;
1830 
1831 	dsss = (wl_dsss_t *)iw_phy;
1832 	ch = dsss->wl_dsss_channel;
1833 
1834 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_phy: "
1835 	    "set channel=%d\n", ch);
1836 
1837 	if (ch == 0 || ch == (int16_t)IEEE80211_CHAN_ANY) {
1838 		ic->ic_des_chan = IEEE80211_CHAN_ANYC;
1839 	} else if ((uint_t)ch > IEEE80211_CHAN_MAX ||
1840 	    ieee80211_isclr(ic->ic_chan_active, ch)) {
1841 		err = EINVAL;
1842 		return (err);
1843 	} else {
1844 		ic->ic_des_chan = ic->ic_ibss_chan =
1845 		    &ic->ic_sup_channels[ch];
1846 	}
1847 
1848 	switch (ic->ic_state) {
1849 	case IEEE80211_S_INIT:
1850 	case IEEE80211_S_SCAN:
1851 		err = ENETRESET;
1852 		break;
1853 	default:
1854 		/*
1855 		 * If hte desired channel has changed (to something
1856 		 * other than any) and we're not already scanning,
1857 		 * then kick the state machine.
1858 		 */
1859 		if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
1860 		    ic->ic_bss->in_chan != ic->ic_des_chan &&
1861 		    (ic->ic_flags & IEEE80211_F_SCAN) == 0)
1862 			err = ENETRESET;
1863 		break;
1864 	}
1865 
1866 	return (err);
1867 }
1868 
1869 #define	WIFI_HT_MODE(in)	(((in)->in_flags & IEEE80211_NODE_HT) ? 1 : 0)
1870 
1871 static int
1872 wl_get_phy(struct ieee80211com *ic, void *wldp_buf)
1873 {
1874 	int err = 0;
1875 	wl_phy_conf_t *ow_phy;
1876 	struct ieee80211_channel *ch = ic->ic_curchan;
1877 	struct ieee80211_node *in = ic->ic_bss;
1878 
1879 	ow_phy = (wl_phy_conf_t *)wldp_buf;
1880 	bzero(wldp_buf, sizeof (wl_phy_conf_t));
1881 
1882 	/* get current phy parameters: FH|DS|ERP */
1883 	if (IEEE80211_IS_CHAN_A(ch) || IEEE80211_IS_CHAN_T(ch)) {
1884 		wl_ofdm_t *ofdm = (wl_ofdm_t *)ow_phy;
1885 		ofdm->wl_ofdm_subtype = WL_OFDM;
1886 		ofdm->wl_ofdm_frequency = ch->ich_freq;
1887 		ofdm->wl_ofdm_ht_enabled = WIFI_HT_MODE(in);
1888 	} else {
1889 		switch (ic->ic_phytype) {
1890 		case IEEE80211_T_FH: {
1891 			wl_fhss_t *fhss = (wl_fhss_t *)ow_phy;
1892 			fhss->wl_fhss_subtype = WL_FHSS;
1893 			fhss->wl_fhss_channel =
1894 			    ieee80211_chan2ieee(ic, ch);
1895 			break;
1896 		}
1897 		case IEEE80211_T_DS: {
1898 			wl_dsss_t *dsss = (wl_dsss_t *)ow_phy;
1899 			dsss->wl_dsss_subtype = WL_DSSS;
1900 			dsss->wl_dsss_channel =
1901 			    ieee80211_chan2ieee(ic, ch);
1902 			break;
1903 		}
1904 		case IEEE80211_T_OFDM: {
1905 			wl_erp_t *erp = (wl_erp_t *)ow_phy;
1906 			erp->wl_erp_subtype = WL_ERP;
1907 			erp->wl_erp_channel =
1908 			    ieee80211_chan2ieee(ic, ch);
1909 			erp->wl_erp_ht_enabled = WIFI_HT_MODE(in);
1910 			break;
1911 		}
1912 		default:
1913 			ieee80211_err("wl_get_phy: "
1914 			    "unknown phy type, %x\n", ic->ic_phytype);
1915 			err = EIO;
1916 			break;
1917 		}
1918 	}
1919 
1920 	return (err);
1921 }
1922 
1923 /*
1924  * MAC_PROP_WL_CAPABILITY
1925  */
1926 static void
1927 wl_get_capability(struct ieee80211com *ic, void *wldp_buf)
1928 {
1929 	wl_capability_t ow_caps;
1930 
1931 	ow_caps.caps = ic->ic_caps;
1932 	bcopy(&ow_caps, wldp_buf, sizeof (wl_capability_t));
1933 
1934 }
1935 
1936 /*
1937  * MAC_PROP_WL_WPA
1938  */
1939 static int
1940 wl_set_wpa(struct ieee80211com *ic, const void *wldp_buf)
1941 {
1942 	int err = 0;
1943 	wl_wpa_t *wpa = (wl_wpa_t *)wldp_buf;
1944 
1945 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpa: "
1946 	    "set wpa=%u\n", wpa->wpa_flag);
1947 
1948 	if (wpa->wpa_flag > 0) {
1949 		/* enable wpa mode */
1950 		ic->ic_flags |= IEEE80211_F_PRIVACY;
1951 		ic->ic_flags |= IEEE80211_F_WPA;
1952 	} else {
1953 		ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1954 		ic->ic_flags &= ~IEEE80211_F_WPA;
1955 	}
1956 
1957 	return (err);
1958 }
1959 
1960 static void
1961 wl_get_wpa(struct ieee80211com *ic, void *wldp_buf)
1962 {
1963 	wl_wpa_t *wpa;
1964 
1965 	wpa = (wl_wpa_t *)wldp_buf;
1966 	wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA) ? 1 : 0);
1967 
1968 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_get_wpa: "
1969 	    "get wpa=%u\n", wpa->wpa_flag);
1970 
1971 }
1972 
1973 /*
1974  * MAC_PROP_WL_SCANRESULTS
1975  */
1976 
1977 static void
1978 wl_get_scanresults(struct ieee80211com *ic, void *wldp_buf)
1979 {
1980 	wl_wpa_ess_t *sr;
1981 	ieee80211_node_t *in;
1982 	ieee80211_node_table_t *nt;
1983 	int ap_num;
1984 	int len;
1985 
1986 	sr = (wl_wpa_ess_t *)wldp_buf;
1987 	sr->count = 0;
1988 	ap_num = 0;
1989 
1990 	ieee80211_dbg(IEEE80211_MSG_WPA, "wl_get_scanrelults\n");
1991 
1992 	nt = &ic->ic_scan;
1993 	IEEE80211_NODE_LOCK(nt);
1994 	in = list_head(&nt->nt_node);
1995 
1996 	while (in != NULL) {
1997 		/* filter out non-wpa APs */
1998 		if (in->in_wpa_ie == NULL) {
1999 			in = list_next(&nt->nt_node, in);
2000 			continue;
2001 		}
2002 		bcopy(in->in_bssid, sr->ess[ap_num].bssid,
2003 		    IEEE80211_ADDR_LEN);
2004 		sr->ess[ap_num].ssid_len = in->in_esslen;
2005 		bcopy(in->in_essid, sr->ess[ap_num].ssid,
2006 		    in->in_esslen);
2007 		sr->ess[ap_num].freq = in->in_chan->ich_freq;
2008 
2009 		len = in->in_wpa_ie[1] + 2;
2010 		bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len);
2011 		sr->ess[ap_num].wpa_ie_len = len;
2012 
2013 		ap_num++;
2014 		in = list_next(&nt->nt_node, in);
2015 	}
2016 	IEEE80211_NODE_UNLOCK(nt);
2017 	sr->count = ap_num;
2018 
2019 }
2020 
2021 /*
2022  * MAC_PROP_WL_ESS_LIST
2023  */
2024 static void
2025 wl_get_esslist(struct ieee80211com *ic, void *wldp_buf)
2026 {
2027 	wl_ess_list_t *ess_list;
2028 
2029 	ess_list = (wl_ess_list_t *)wldp_buf;
2030 
2031 	ess_list->wl_ess_list_num = 0;
2032 	ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ess_list);
2033 
2034 }
2035 
2036 /*
2037  * MAC_PROP_WL_WEP_KEY
2038  */
2039 static int
2040 wl_set_wepkey(struct ieee80211com *ic, const void *wldp_buf)
2041 {
2042 	int	 err = 0;
2043 	uint16_t i;
2044 	uint32_t klen;
2045 	struct ieee80211_key *key;
2046 	wl_wep_key_t *wepkey = (wl_wep_key_t *)wldp_buf;
2047 
2048 	/* set all valid keys */
2049 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2050 		if (wepkey[i].wl_wep_operation != WL_ADD)
2051 			continue;
2052 		klen = wepkey[i].wl_wep_length;
2053 		if (klen > IEEE80211_KEYBUF_SIZE) {
2054 			ieee80211_err("wl_set_wepkey: "
2055 			    "invalid wepkey length, %u\n", klen);
2056 			err = EINVAL;
2057 			continue;  /* continue to set other keys */
2058 		}
2059 		if (klen == 0)
2060 			continue;
2061 
2062 		/*
2063 		 *  Set key contents. Only WEP is supported
2064 		 */
2065 		ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_wepkey: "
2066 		    "set key %u, len=%u\n", i, klen);
2067 		key = &ic->ic_nw_keys[i];
2068 		if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
2069 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key) == 0) {
2070 			ieee80211_err("wl_set_wepkey: "
2071 			    "abort, create key failed. id=%u\n", i);
2072 			err = EIO;
2073 			continue;
2074 		}
2075 
2076 		key->wk_keyix = i;
2077 		key->wk_keylen = (uint8_t)klen;
2078 		key->wk_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
2079 		bzero(key->wk_key, IEEE80211_KEYBUF_SIZE);
2080 		bcopy(wepkey[i].wl_wep_key, key->wk_key, klen);
2081 		if (ieee80211_crypto_setkey(ic, key, ic->ic_macaddr)
2082 		    == 0) {
2083 			ieee80211_err("wl_set_wepkey: "
2084 			    "set key failed len=%u\n", klen);
2085 			err = EIO;
2086 		}
2087 	}
2088 	if (err == 0)
2089 		err = ENETRESET;
2090 
2091 	return (err);
2092 }
2093 
2094 /*
2095  * MAC_PROP_WL_SETOPTIE
2096  */
2097 static int
2098 wl_set_optie(struct ieee80211com *ic, const void *wldp_buf)
2099 {
2100 	int err = 0;
2101 	char *ie;
2102 	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)wldp_buf;
2103 
2104 	if (ic->ic_opmode != IEEE80211_M_STA) {
2105 		ieee80211_err("wl_set_optie: opmode err\n");
2106 		err = EINVAL;
2107 		return (err);
2108 	}
2109 	if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) {
2110 
2111 		ieee80211_err("wl_set_optie: optie is too long\n");
2112 
2113 		err = EINVAL;
2114 		return (err);
2115 	}
2116 
2117 	ie = ieee80211_malloc(ie_in->wpa_ie_len);
2118 	(void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len);
2119 	if (ic->ic_opt_ie != NULL) {
2120 		ieee80211_dbg(IEEE80211_MSG_BRUSSELS,
2121 		    "wl_set_optie:ic_opt_ie!=NULL\n");
2122 		ieee80211_free(ic->ic_opt_ie);
2123 	}
2124 	ic->ic_opt_ie = ie;
2125 	ic->ic_opt_ie_len = ie_in->wpa_ie_len;
2126 
2127 	return (err);
2128 }
2129 
2130 /*
2131  * MAC_PROP_WL_DELKEY
2132  */
2133 static int
2134 wl_set_delkey(struct ieee80211com *ic, const void *wldp_buf)
2135 {
2136 	int err = 0;
2137 	int kid;
2138 	wl_del_key_t *dk = (wl_del_key_t *)wldp_buf;
2139 
2140 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_delkey(): "
2141 	    "keyix=%d\n", dk->idk_keyix);
2142 
2143 	kid = dk->idk_keyix;
2144 
2145 	if (kid == IEEE80211_KEYIX_NONE ||
2146 	    kid >= IEEE80211_WEP_NKID) {
2147 		ieee80211_err("wl_set_delkey: incorrect keyix\n");
2148 		err = EINVAL;
2149 		return (err);
2150 	} else {
2151 		(void) ieee80211_crypto_delkey(ic,
2152 		    &ic->ic_nw_keys[kid]);
2153 		ieee80211_mac_update(ic);
2154 	}
2155 
2156 	return (err);
2157 }
2158 
2159 /*
2160  * MAC_PROP_WL_MLME
2161  */
2162 
2163 static int
2164 wl_set_mlme(struct ieee80211com *ic, const void *wldp_buf)
2165 {
2166 	int err = 0;
2167 	uint32_t flags;
2168 	ieee80211_node_t *in;
2169 	wl_mlme_t *mlme = (wl_mlme_t *)wldp_buf;
2170 
2171 	ieee80211_dbg(IEEE80211_MSG_WPA, "wl_set_mlme: "
2172 	    "op=%d\n", mlme->im_op);
2173 
2174 	switch (mlme->im_op) {
2175 	case IEEE80211_MLME_DISASSOC:
2176 	case IEEE80211_MLME_DEAUTH:
2177 		if (ic->ic_opmode == IEEE80211_M_STA) {
2178 			/*
2179 			 * Mask ic_flags of IEEE80211_F_WPA to disable
2180 			 * ieee80211_notify temporarily.
2181 			 */
2182 			flags = ic->ic_flags;
2183 			ic->ic_flags &= ~IEEE80211_F_WPA;
2184 
2185 			IEEE80211_UNLOCK(ic);
2186 			ieee80211_new_state(ic, IEEE80211_S_INIT,
2187 			    mlme->im_reason);
2188 			IEEE80211_LOCK(ic);
2189 
2190 			ic->ic_flags = flags;
2191 		}
2192 		break;
2193 	case IEEE80211_MLME_ASSOC:
2194 		if (ic->ic_opmode != IEEE80211_M_STA) {
2195 			ieee80211_err("wifi_cfg_setmlme: opmode err\n");
2196 			err = EINVAL;
2197 			break;
2198 		}
2199 		if (ic->ic_des_esslen != 0) {
2200 		/*
2201 		 * Desired ssid specified; must match both bssid and
2202 		 * ssid to distinguish ap advertising multiple ssid's.
2203 		 */
2204 			in = ieee80211_find_node_with_ssid(&ic->ic_scan,
2205 			    mlme->im_macaddr,
2206 			    ic->ic_des_esslen,
2207 			    ic->ic_des_essid);
2208 		} else {
2209 		/*
2210 		 * Normal case; just match bssid.
2211 		 */
2212 			in = ieee80211_find_node(&ic->ic_scan,
2213 			    mlme->im_macaddr);
2214 		}
2215 		if (in == NULL) {
2216 			ieee80211_err("wifi_cfg_setmlme: "
2217 			    "no matched node\n");
2218 			err = EINVAL;
2219 			break;
2220 		}
2221 		IEEE80211_UNLOCK(ic);
2222 		ieee80211_sta_join(ic, in);
2223 		IEEE80211_LOCK(ic);
2224 		break;
2225 	default:
2226 		err = EINVAL;
2227 		break;
2228 	}
2229 
2230 	return (err);
2231 }
2232 
2233 /*
2234  * MAC_PROP_WL_WPA_KEY
2235  */
2236 static int
2237 wl_set_wpakey(struct ieee80211com *ic, const void *wldp_buf)
2238 {
2239 	int err = 0;
2240 	uint16_t kid;
2241 	struct ieee80211_node *in;
2242 	struct ieee80211_key *wk;
2243 	wl_key_t ik;
2244 
2245 	bcopy(wldp_buf, &ik, sizeof (wl_key_t));
2246 
2247 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpakey: "
2248 	    "idx=%d\n", ik.ik_keyix);
2249 
2250 	/*
2251 	 * cipher support is verified by ieee80211_crypt_newkey
2252 	 * this also checks ik.ik_keylen > sizeof(wk->wk_key)
2253 	 */
2254 	if (ik.ik_keylen > sizeof (ik.ik_keydata)) {
2255 		ieee80211_err("wl_set_wpakey: key is too long\n");
2256 		err = EINVAL;
2257 		return (err);
2258 	}
2259 	kid = ik.ik_keyix;
2260 	if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) {
2261 		ieee80211_err("wl_set_wpakey: incorrect keyix\n");
2262 		err = EINVAL;
2263 		return (err);
2264 	} else {
2265 		wk = &ic->ic_nw_keys[kid];
2266 		/*
2267 		 * Globle slots start off w/o any assigned key index.
2268 		 * Force one here for consistency with WEPKEY.
2269 		 */
2270 		if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
2271 			wk->wk_keyix = kid;
2272 		in = NULL;
2273 	}
2274 
2275 	KEY_UPDATE_BEGIN(ic);
2276 	if (ieee80211_crypto_newkey(ic, ik.ik_type,
2277 	    ik.ik_flags, wk)) {
2278 		wk->wk_keylen = ik.ik_keylen;
2279 		/* MIC presence is implied by cipher type */
2280 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
2281 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
2282 		wk->wk_keyrsc = ik.ik_keyrsc;
2283 		wk->wk_keytsc = 0;
2284 		wk->wk_flags |= ik.ik_flags &
2285 		    (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
2286 		(void) memset(wk->wk_key, 0, sizeof (wk->wk_key));
2287 		(void) memcpy(wk->wk_key, ik.ik_keydata,
2288 		    ik.ik_keylen);
2289 		if (!ieee80211_crypto_setkey(ic, wk,
2290 		    in != NULL ? in->in_macaddr : ik.ik_macaddr)) {
2291 			err = EIO;
2292 		} else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT)) {
2293 			ic->ic_def_txkey = kid;
2294 			ieee80211_mac_update(ic);
2295 		}
2296 	} else {
2297 		err = EIO;
2298 	}
2299 	KEY_UPDATE_END(ic);
2300 
2301 	return (err);
2302 }
2303 
2304 /*
2305  * MAC_PROP_WL_SUP_RATE
2306  */
2307 static void
2308 wl_get_suprates(struct ieee80211com *ic, void *wldp_buf)
2309 {
2310 	int i, j, k, l;
2311 	uint8_t srates;
2312 	uint8_t *drates;
2313 	wl_rates_t *wl_rates;
2314 	const struct ieee80211_rateset *srs;
2315 
2316 	wl_rates = (wl_rates_t *)wldp_buf;
2317 
2318 	wl_rates->wl_rates_num = 0;
2319 	drates = (uint8_t *)wl_rates->wl_rates_rates;
2320 	for (i = 0; i < IEEE80211_MODE_MAX; i++) {
2321 		srs = &ic->ic_sup_rates[i];
2322 		if (srs->ir_nrates == 0)
2323 			continue;
2324 		for (j = 0; j < srs->ir_nrates; j++) {
2325 			srates = IEEE80211_RV(srs->ir_rates[j]);
2326 			/* sort & skip duplicated rates */
2327 			for (k = 0; k < wl_rates->wl_rates_num; k++) {
2328 				if (srates <= drates[k])
2329 					break;
2330 			}
2331 			if (srates == drates[k])
2332 				/* skip duplicated rates */
2333 				continue;
2334 			/* sort */
2335 			for (l = wl_rates->wl_rates_num; l > k; l--)
2336 				drates[l] = drates[l-1];
2337 			drates[k] = srates;
2338 			wl_rates->wl_rates_num++;
2339 		}
2340 	}
2341 
2342 }
2343 
2344 /*
2345  * Typically invoked by drivers in response to request for
2346  * information or to change settings from the userland.
2347  *
2348  * Return value should be checked by WiFI drivers. Return 0
2349  * on success. Otherwise, return non-zero value to indicate
2350  * the error. Driver should operate as below when the return
2351  * error is:
2352  * ENETRESET	Reset wireless network and re-start to join a
2353  * 		WLAN, ENETRESET is returned when a configuration
2354  * 		parameter has been changed.
2355  * 		When acknowledge a M_IOCTL message, this error
2356  * 		is ignored
2357  */
2358 /* ARGSUSED */
2359 int
2360 ieee80211_setprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2361     uint_t wldp_length, const void *wldp_buf)
2362 {
2363 	int err = 0;
2364 	struct ieee80211com *ic = ic_arg;
2365 
2366 	ASSERT(ic != NULL);
2367 	IEEE80211_LOCK(ic);
2368 
2369 	switch (wldp_pr_num) {
2370 	/* mac_prop_id */
2371 	case MAC_PROP_WL_ESSID:
2372 		err = wl_set_essid(ic, wldp_buf);
2373 		break;
2374 	case MAC_PROP_WL_BSSID:
2375 		err = wl_set_bssid(ic, wldp_buf);
2376 		break;
2377 	case MAC_PROP_WL_PHY_CONFIG:
2378 		err = wl_set_phy(ic, wldp_buf);
2379 		break;
2380 	case MAC_PROP_WL_KEY_TAB:
2381 		err = wl_set_wepkey(ic, wldp_buf);
2382 		break;
2383 	case MAC_PROP_WL_AUTH_MODE:
2384 		err = wl_set_authmode(ic, wldp_buf);
2385 		break;
2386 	case MAC_PROP_WL_ENCRYPTION:
2387 		err = wl_set_encrypt(ic, wldp_buf);
2388 		break;
2389 	case MAC_PROP_WL_BSSTYPE:
2390 		err = wl_set_bsstype(ic, wldp_buf);
2391 		break;
2392 	case MAC_PROP_WL_DESIRED_RATES:
2393 		err = wl_set_desrates(ic, wldp_buf);
2394 		break;
2395 	case MAC_PROP_WL_WPA:
2396 		err = wl_set_wpa(ic, wldp_buf);
2397 		break;
2398 	case MAC_PROP_WL_KEY:
2399 		err = wl_set_wpakey(ic, wldp_buf);
2400 		break;
2401 	case MAC_PROP_WL_DELKEY:
2402 		err = wl_set_delkey(ic, wldp_buf);
2403 		break;
2404 	case MAC_PROP_WL_SETOPTIE:
2405 		err = wl_set_optie(ic, wldp_buf);
2406 		break;
2407 	case MAC_PROP_WL_MLME:
2408 		err = wl_set_mlme(ic, wldp_buf);
2409 		break;
2410 	case MAC_PROP_WL_LINKSTATUS:
2411 	case MAC_PROP_WL_ESS_LIST:
2412 	case MAC_PROP_WL_SUPPORTED_RATES:
2413 	case MAC_PROP_WL_RSSI:
2414 	case MAC_PROP_WL_CAPABILITY:
2415 	case MAC_PROP_WL_SCANRESULTS:
2416 		ieee80211_err("ieee80211_setprop: opmode err\n");
2417 		err = EINVAL;
2418 		break;
2419 	default:
2420 		ieee80211_err("ieee80211_setprop: opmode not support\n");
2421 		err = ENOTSUP;
2422 		break;
2423 	}
2424 
2425 	IEEE80211_UNLOCK(ic);
2426 
2427 	return (err);
2428 }
2429 
2430 /* ARGSUSED */
2431 int
2432 ieee80211_getprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2433     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
2434 {
2435 	int err = 0;
2436 	struct ieee80211com *ic = ic_arg;
2437 
2438 	if (wldp_length == 0) {
2439 		err = EINVAL;
2440 		return (err);
2441 	}
2442 	bzero(wldp_buf, wldp_length);
2443 
2444 	ASSERT(ic != NULL);
2445 	IEEE80211_LOCK(ic);
2446 
2447 	*perm = MAC_PROP_PERM_RW;
2448 
2449 	switch (wldp_pr_num) {
2450 	/* mac_prop_id */
2451 	case MAC_PROP_WL_ESSID:
2452 		wl_get_essid(ic, wldp_buf);
2453 		break;
2454 	case MAC_PROP_WL_BSSID:
2455 		wl_get_bssid(ic, wldp_buf);
2456 		break;
2457 	case MAC_PROP_WL_PHY_CONFIG:
2458 		err = wl_get_phy(ic, wldp_buf);
2459 		break;
2460 	case MAC_PROP_WL_AUTH_MODE:
2461 		wl_get_authmode(ic, wldp_buf);
2462 		break;
2463 	case MAC_PROP_WL_ENCRYPTION:
2464 		wl_get_encrypt(ic, wldp_buf);
2465 		break;
2466 	case MAC_PROP_WL_BSSTYPE:
2467 		wl_get_bsstype(ic, wldp_buf);
2468 		break;
2469 	case MAC_PROP_WL_DESIRED_RATES:
2470 		wl_get_desrates(ic, wldp_buf);
2471 		break;
2472 	case MAC_PROP_WL_LINKSTATUS:
2473 		*perm = MAC_PROP_PERM_READ;
2474 		wl_get_linkstatus(ic, wldp_buf);
2475 		break;
2476 	case MAC_PROP_WL_ESS_LIST:
2477 		*perm = MAC_PROP_PERM_READ;
2478 		wl_get_esslist(ic, wldp_buf);
2479 		break;
2480 	case MAC_PROP_WL_SUPPORTED_RATES:
2481 		*perm = MAC_PROP_PERM_READ;
2482 		wl_get_suprates(ic, wldp_buf);
2483 		break;
2484 	case MAC_PROP_WL_RSSI:
2485 		*perm = MAC_PROP_PERM_READ;
2486 		wl_get_rssi(ic, wldp_buf);
2487 		break;
2488 	case MAC_PROP_WL_CAPABILITY:
2489 		*perm = MAC_PROP_PERM_READ;
2490 		wl_get_capability(ic, wldp_buf);
2491 		break;
2492 	case MAC_PROP_WL_WPA:
2493 		wl_get_wpa(ic, wldp_buf);
2494 		break;
2495 	case MAC_PROP_WL_SCANRESULTS:
2496 		*perm = MAC_PROP_PERM_READ;
2497 		wl_get_scanresults(ic, wldp_buf);
2498 		break;
2499 	case MAC_PROP_WL_KEY_TAB:
2500 	case MAC_PROP_WL_KEY:
2501 	case MAC_PROP_WL_DELKEY:
2502 	case MAC_PROP_WL_SETOPTIE:
2503 	case MAC_PROP_WL_MLME:
2504 		ieee80211_err("ieee80211_setprop: opmode err\n");
2505 		err = EINVAL;
2506 		break;
2507 	default:
2508 		ieee80211_err("ieee80211_setprop: opmode not support\n");
2509 		err = ENOTSUP;
2510 		break;
2511 	}
2512 
2513 	IEEE80211_UNLOCK(ic);
2514 
2515 	return (err);
2516 }
2517