10ba2cbe9Sxc /*
2*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
30ba2cbe9Sxc  * Use is subject to license terms.
40ba2cbe9Sxc  */
50ba2cbe9Sxc 
60ba2cbe9Sxc /*
70ba2cbe9Sxc  * Redistribution and use in source and binary forms, with or without
80ba2cbe9Sxc  * modification, are permitted provided that the following conditions
90ba2cbe9Sxc  * are met:
100ba2cbe9Sxc  * 1. Redistributions of source code must retain the above copyright
110ba2cbe9Sxc  *    notice, this list of conditions and the following disclaimer.
120ba2cbe9Sxc  * 2. Redistributions in binary form must reproduce the above copyright
130ba2cbe9Sxc  *    notice, this list of conditions and the following disclaimer in the
140ba2cbe9Sxc  *    documentation and/or other materials provided with the distribution.
150ba2cbe9Sxc  * 3. The name of the author may not be used to endorse or promote products
160ba2cbe9Sxc  *    derived from this software without specific prior written permission.
170ba2cbe9Sxc  *
180ba2cbe9Sxc  * Alternatively, this software may be distributed under the terms of the
190ba2cbe9Sxc  * GNU General Public License ("GPL") version 2 as published by the Free
200ba2cbe9Sxc  * Software Foundation.
210ba2cbe9Sxc  *
220ba2cbe9Sxc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
230ba2cbe9Sxc  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
240ba2cbe9Sxc  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
250ba2cbe9Sxc  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
260ba2cbe9Sxc  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
270ba2cbe9Sxc  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
280ba2cbe9Sxc  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
290ba2cbe9Sxc  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
300ba2cbe9Sxc  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
310ba2cbe9Sxc  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
320ba2cbe9Sxc  */
330ba2cbe9Sxc 
34bcb5c89dSSowmini Varadhan 
350ba2cbe9Sxc #include <sys/param.h>
360ba2cbe9Sxc #include <sys/types.h>
370ba2cbe9Sxc #include <sys/errno.h>
380ba2cbe9Sxc #include <sys/strsun.h>
390ba2cbe9Sxc #include <sys/policy.h>
400ba2cbe9Sxc #include <inet/common.h>
410ba2cbe9Sxc #include <inet/nd.h>
420ba2cbe9Sxc #include <inet/mi.h>
430ba2cbe9Sxc #include <sys/note.h>
44da14cebeSEric Cheng #include <sys/mac_provider.h>
450ba2cbe9Sxc #include <inet/wifi_ioctl.h>
460ba2cbe9Sxc #include "net80211_impl.h"
470ba2cbe9Sxc 
48bcb5c89dSSowmini Varadhan static int wl_set_essid(struct ieee80211com *, const void *);
49bcb5c89dSSowmini Varadhan static void wl_get_essid(struct ieee80211com *, void *);
50bcb5c89dSSowmini Varadhan static int wl_set_bssid(struct ieee80211com *, const void *);
51bcb5c89dSSowmini Varadhan static void wl_get_bssid(struct ieee80211com *, void *);
52bcb5c89dSSowmini Varadhan static int wl_set_bsstype(struct ieee80211com *, const void *);
53bcb5c89dSSowmini Varadhan static void wl_get_bsstype(struct ieee80211com *, void *);
54bcb5c89dSSowmini Varadhan static void wl_get_linkstatus(struct ieee80211com *, void *);
55bcb5c89dSSowmini Varadhan static int wl_set_desrates(struct ieee80211com *, const void *);
56bcb5c89dSSowmini Varadhan static void wl_get_desrates(struct ieee80211com *, void *);
57bcb5c89dSSowmini Varadhan static int wl_set_authmode(struct ieee80211com *, const void *);
58bcb5c89dSSowmini Varadhan static void wl_get_authmode(struct ieee80211com *, void *);
59bcb5c89dSSowmini Varadhan static int wl_set_encrypt(struct ieee80211com *, const void *);
60bcb5c89dSSowmini Varadhan static void wl_get_encrypt(struct ieee80211com *, void *);
61bcb5c89dSSowmini Varadhan static void wl_get_rssi(struct ieee80211com *, void *);
62bcb5c89dSSowmini Varadhan static int wl_set_phy(struct ieee80211com *, const void *);
63bcb5c89dSSowmini Varadhan static int wl_get_phy(struct ieee80211com *, void *);
64bcb5c89dSSowmini Varadhan static void wl_get_capability(struct ieee80211com *, void *);
65bcb5c89dSSowmini Varadhan static int wl_set_wpa(struct ieee80211com *, const void *);
66bcb5c89dSSowmini Varadhan static void wl_get_wpa(struct ieee80211com *, void *);
67bcb5c89dSSowmini Varadhan static void wl_get_scanresults(struct ieee80211com *, void *);
68bcb5c89dSSowmini Varadhan static void wl_get_esslist(struct ieee80211com *, void *);
69bcb5c89dSSowmini Varadhan static int wl_set_wepkey(struct ieee80211com *, const void *);
70bcb5c89dSSowmini Varadhan static int wl_set_optie(struct ieee80211com *, const void *);
71bcb5c89dSSowmini Varadhan static int wl_set_delkey(struct ieee80211com *, const void *);
72bcb5c89dSSowmini Varadhan static int wl_set_mlme(struct ieee80211com *, const void *);
73bcb5c89dSSowmini Varadhan static int wl_set_wpakey(struct ieee80211com *, const void *);
74bcb5c89dSSowmini Varadhan static void wl_get_suprates(struct ieee80211com *, void *);
75127ac1c2Sfei feng - Sun Microsystems - Beijing China static int wl_set_createibss(struct ieee80211com *, const void *);
76127ac1c2Sfei feng - Sun Microsystems - Beijing China static void wl_get_createibss(struct ieee80211com *, void *);
77bcb5c89dSSowmini Varadhan 
780ba2cbe9Sxc static size_t
wifi_strnlen(const char * s,size_t n)790ba2cbe9Sxc wifi_strnlen(const char *s, size_t n)
800ba2cbe9Sxc {
810ba2cbe9Sxc 	size_t i;
820ba2cbe9Sxc 
830ba2cbe9Sxc 	for (i = 0; i < n && s[i] != '\0'; i++)
840ba2cbe9Sxc 		/* noop */;
850ba2cbe9Sxc 	return (i);
860ba2cbe9Sxc }
870ba2cbe9Sxc 
880ba2cbe9Sxc /*
890ba2cbe9Sxc  * Initialize an output message block by copying from an
900ba2cbe9Sxc  * input message block. The message is of type wldp_t.
910ba2cbe9Sxc  *    mp     input message block
920ba2cbe9Sxc  *    buflen length of wldp_buf
930ba2cbe9Sxc  */
940ba2cbe9Sxc static void
wifi_setupoutmsg(mblk_t * mp,int buflen)950ba2cbe9Sxc wifi_setupoutmsg(mblk_t *mp, int buflen)
960ba2cbe9Sxc {
970ba2cbe9Sxc 	wldp_t *wp;
980ba2cbe9Sxc 
990ba2cbe9Sxc 	wp = (wldp_t *)mp->b_rptr;
1000ba2cbe9Sxc 	wp->wldp_length = WIFI_BUF_OFFSET + buflen;
1010ba2cbe9Sxc 	wp->wldp_result = WL_SUCCESS;
1020ba2cbe9Sxc 	mp->b_wptr = mp->b_rptr + wp->wldp_length;
1030ba2cbe9Sxc }
1040ba2cbe9Sxc 
1050ba2cbe9Sxc /*
1060ba2cbe9Sxc  * Allocate and initialize an output message.
1070ba2cbe9Sxc  */
1080ba2cbe9Sxc static mblk_t *
wifi_getoutmsg(mblk_t * mp,uint32_t cmd,int buflen)1090ba2cbe9Sxc wifi_getoutmsg(mblk_t *mp, uint32_t cmd, int buflen)
1100ba2cbe9Sxc {
1110ba2cbe9Sxc 	mblk_t *mp1;
1120ba2cbe9Sxc 	int size;
1130ba2cbe9Sxc 
1140ba2cbe9Sxc 	size = WIFI_BUF_OFFSET;
1150ba2cbe9Sxc 	if (cmd == WLAN_GET_PARAM)
1160ba2cbe9Sxc 		size += buflen;	/* to hold output parameters */
1170ba2cbe9Sxc 	mp1 = allocb(size, BPRI_HI);
1180ba2cbe9Sxc 	if (mp1 == NULL) {
1190ba2cbe9Sxc 		ieee80211_err("wifi_getoutbuf: allocb %d bytes failed!\n",
1200ba2cbe9Sxc 		    size);
1210ba2cbe9Sxc 		return (NULL);
1220ba2cbe9Sxc 	}
1230ba2cbe9Sxc 
1240ba2cbe9Sxc 	bzero(mp1->b_rptr, size);
1250ba2cbe9Sxc 	bcopy(mp->b_rptr, mp1->b_rptr, WIFI_BUF_OFFSET);
1260ba2cbe9Sxc 	wifi_setupoutmsg(mp1, size - WIFI_BUF_OFFSET);
1270ba2cbe9Sxc 
1280ba2cbe9Sxc 	return (mp1);
1290ba2cbe9Sxc }
1300ba2cbe9Sxc 
1310ba2cbe9Sxc static int
wifi_cfg_essid(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1320ba2cbe9Sxc wifi_cfg_essid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1330ba2cbe9Sxc {
1340ba2cbe9Sxc 	mblk_t *omp;
1350ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1360ba2cbe9Sxc 	wldp_t *outp;
1370ba2cbe9Sxc 	wl_essid_t *iw_essid = (wl_essid_t *)inp->wldp_buf;
1380ba2cbe9Sxc 	wl_essid_t *ow_essid;
1390ba2cbe9Sxc 	int err = 0;
1400ba2cbe9Sxc 
1410ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_essid_t))) == NULL)
1420ba2cbe9Sxc 		return (ENOMEM);
1430ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
1440ba2cbe9Sxc 	ow_essid = (wl_essid_t *)outp->wldp_buf;
1450ba2cbe9Sxc 
1460ba2cbe9Sxc 	switch (cmd) {
1470ba2cbe9Sxc 	case WLAN_GET_PARAM:
148bcb5c89dSSowmini Varadhan 		wl_get_essid(ic, ow_essid);
1490ba2cbe9Sxc 		break;
1500ba2cbe9Sxc 	case WLAN_SET_PARAM:
151bcb5c89dSSowmini Varadhan 		err = wl_set_essid(ic, iw_essid);
1520ba2cbe9Sxc 		break;
1530ba2cbe9Sxc 	default:
1540ba2cbe9Sxc 		ieee80211_err("wifi_cfg_essid: unknown command %x\n", cmd);
1550ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
1560ba2cbe9Sxc 		err = EINVAL;
1570ba2cbe9Sxc 		break;
1580ba2cbe9Sxc 	}
1590ba2cbe9Sxc 
1600ba2cbe9Sxc 	freemsg(*mp);
1610ba2cbe9Sxc 	*mp = omp;
1620ba2cbe9Sxc 	return (err);
1630ba2cbe9Sxc }
1640ba2cbe9Sxc 
1650ba2cbe9Sxc static int
wifi_cfg_bssid(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1660ba2cbe9Sxc wifi_cfg_bssid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1670ba2cbe9Sxc {
1680ba2cbe9Sxc 	mblk_t *omp;
1690ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1700ba2cbe9Sxc 	wldp_t *outp;
1710ba2cbe9Sxc 	int err = 0;
1720ba2cbe9Sxc 
1730ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bssid_t))) == NULL)
1740ba2cbe9Sxc 		return (ENOMEM);
1750ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
1760ba2cbe9Sxc 
1770ba2cbe9Sxc 	switch (cmd) {
1780ba2cbe9Sxc 	case  WLAN_GET_PARAM:
179bcb5c89dSSowmini Varadhan 		wl_get_bssid(ic, outp->wldp_buf);
1800ba2cbe9Sxc 		break;
1810ba2cbe9Sxc 	case WLAN_SET_PARAM:
182bcb5c89dSSowmini Varadhan 		err = wl_set_bssid(ic, inp->wldp_buf);
1830ba2cbe9Sxc 		ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_bssid: "
1840ba2cbe9Sxc 		    "set bssid=%s\n",
1850ba2cbe9Sxc 		    ieee80211_macaddr_sprintf(inp->wldp_buf));
1860ba2cbe9Sxc 		break;
1870ba2cbe9Sxc 	default:
1880ba2cbe9Sxc 		ieee80211_err("wifi_cfg_bssid: unknown command %x\n", cmd);
1890ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
1900ba2cbe9Sxc 		err = EINVAL;
1910ba2cbe9Sxc 		break;
1920ba2cbe9Sxc 	}
1930ba2cbe9Sxc 
1940ba2cbe9Sxc 	freemsg(*mp);
1950ba2cbe9Sxc 	*mp = omp;
1960ba2cbe9Sxc 	return (err);
1970ba2cbe9Sxc }
1980ba2cbe9Sxc 
1990ba2cbe9Sxc static int
wifi_cfg_nodename(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)2000ba2cbe9Sxc wifi_cfg_nodename(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
2010ba2cbe9Sxc {
2020ba2cbe9Sxc 	mblk_t *omp;
2030ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
2040ba2cbe9Sxc 	wldp_t *outp;
2050ba2cbe9Sxc 	wl_nodename_t *iw_name = (wl_nodename_t *)inp->wldp_buf;
2060ba2cbe9Sxc 	wl_nodename_t *ow_name;
2070ba2cbe9Sxc 	char *nodename;
2080ba2cbe9Sxc 	int len, err;
2090ba2cbe9Sxc 
2100ba2cbe9Sxc 	err = 0;
2110ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_nodename_t))) == NULL)
2120ba2cbe9Sxc 		return (ENOMEM);
2130ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
2140ba2cbe9Sxc 	ow_name = (wl_nodename_t *)outp->wldp_buf;
2150ba2cbe9Sxc 
2160ba2cbe9Sxc 	switch (cmd) {
2170ba2cbe9Sxc 	case WLAN_GET_PARAM:
2180ba2cbe9Sxc 		len = wifi_strnlen((const char *)ic->ic_nickname,
2190ba2cbe9Sxc 		    IEEE80211_NWID_LEN);
2200ba2cbe9Sxc 		ow_name->wl_nodename_length = len;
2210ba2cbe9Sxc 		bcopy(ic->ic_nickname, ow_name->wl_nodename_name, len);
2220ba2cbe9Sxc 		break;
2230ba2cbe9Sxc 	case WLAN_SET_PARAM:
2240ba2cbe9Sxc 		if (iw_name->wl_nodename_length > IEEE80211_NWID_LEN) {
2250ba2cbe9Sxc 			ieee80211_err("wifi_cfg_nodename: "
2260ba2cbe9Sxc 			    "node name too long, %u\n",
2270ba2cbe9Sxc 			    iw_name->wl_nodename_length);
2280ba2cbe9Sxc 			outp->wldp_result = WL_NOTSUPPORTED;
2290ba2cbe9Sxc 			err = EINVAL;
2300ba2cbe9Sxc 			break;
2310ba2cbe9Sxc 		}
2320ba2cbe9Sxc 		nodename = iw_name->wl_nodename_name;
2330ba2cbe9Sxc 		nodename[IEEE80211_NWID_LEN] = 0;
2340ba2cbe9Sxc 		ieee80211_dbg(IEEE80211_MSG_CONFIG,
2350ba2cbe9Sxc 		    "wifi_cfg_nodename: set nodename %s, len=%d\n",
2360ba2cbe9Sxc 		    nodename, iw_name->wl_nodename_length);
2370ba2cbe9Sxc 
2380ba2cbe9Sxc 		len = iw_name->wl_nodename_length;
2390ba2cbe9Sxc 		if (len > 0)
2400ba2cbe9Sxc 			bcopy(nodename, ic->ic_nickname, len);
2410ba2cbe9Sxc 		if (len < IEEE80211_NWID_LEN)
2420ba2cbe9Sxc 			ic->ic_nickname[len] = 0;
2430ba2cbe9Sxc 		break;
2440ba2cbe9Sxc 	default:
2450ba2cbe9Sxc 		ieee80211_err("wifi_cfg_nodename: unknown command %x\n", cmd);
2460ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
2470ba2cbe9Sxc 		err = EINVAL;
2480ba2cbe9Sxc 		break;
2490ba2cbe9Sxc 	}
2500ba2cbe9Sxc 
2510ba2cbe9Sxc 	freemsg(*mp);
2520ba2cbe9Sxc 	*mp = omp;
2530ba2cbe9Sxc 	return (err);
2540ba2cbe9Sxc }
2550ba2cbe9Sxc 
2560ba2cbe9Sxc static int
wifi_cfg_phy(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)2570ba2cbe9Sxc wifi_cfg_phy(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
2580ba2cbe9Sxc {
2590ba2cbe9Sxc 	mblk_t *omp;
2600ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
2610ba2cbe9Sxc 	wldp_t *outp;
2620ba2cbe9Sxc 	wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)inp->wldp_buf;
2630ba2cbe9Sxc 	wl_phy_conf_t *ow_phy;
2640ba2cbe9Sxc 	int err = 0;
2650ba2cbe9Sxc 
2660ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_phy_conf_t))) == NULL)
2670ba2cbe9Sxc 		return (ENOMEM);
2680ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
2690ba2cbe9Sxc 	ow_phy = (wl_phy_conf_t *)outp->wldp_buf;
2700ba2cbe9Sxc 
2710ba2cbe9Sxc 	switch (cmd) {
272bcb5c89dSSowmini Varadhan 	case WLAN_GET_PARAM:
273bcb5c89dSSowmini Varadhan 		err = wl_get_phy(ic, ow_phy);
2740ba2cbe9Sxc 		break;
2750ba2cbe9Sxc 
276bcb5c89dSSowmini Varadhan 	case WLAN_SET_PARAM:
277bcb5c89dSSowmini Varadhan 		err = wl_set_phy(ic, iw_phy);
2780ba2cbe9Sxc 		break;
2790ba2cbe9Sxc 
2800ba2cbe9Sxc 	default:
2810ba2cbe9Sxc 		ieee80211_err("wifi_cfg_phy: unknown command %x\n", cmd);
2820ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
2830ba2cbe9Sxc 		err = EINVAL;
2840ba2cbe9Sxc 		break;
2850ba2cbe9Sxc 	} /* switch (cmd) */
2860ba2cbe9Sxc 
2870ba2cbe9Sxc 	freemsg(*mp);
2880ba2cbe9Sxc 	*mp = omp;
2890ba2cbe9Sxc 	return (err);
2900ba2cbe9Sxc }
2910ba2cbe9Sxc 
2920ba2cbe9Sxc static int
wifi_cfg_wepkey(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)2930ba2cbe9Sxc wifi_cfg_wepkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
2940ba2cbe9Sxc {
2950ba2cbe9Sxc 	mblk_t *omp;
2960ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
2970ba2cbe9Sxc 	wldp_t *outp;
2980ba2cbe9Sxc 	wl_wep_key_t *iw_wepkey = (wl_wep_key_t *)inp->wldp_buf;
2990ba2cbe9Sxc 	int err = 0;
3000ba2cbe9Sxc 
3010ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
3020ba2cbe9Sxc 		return (ENOMEM);
3030ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
3040ba2cbe9Sxc 
3050ba2cbe9Sxc 	switch (cmd) {
3060ba2cbe9Sxc 	case WLAN_GET_PARAM:
3070ba2cbe9Sxc 		outp->wldp_result = WL_WRITEONLY;
3080ba2cbe9Sxc 		err = EINVAL;
3090ba2cbe9Sxc 		break;
3100ba2cbe9Sxc 	case WLAN_SET_PARAM:
3110ba2cbe9Sxc 		if (inp->wldp_length < sizeof (wl_wep_key_tab_t)) {
3120ba2cbe9Sxc 			ieee80211_err("wifi_cfg_wepkey: "
3130ba2cbe9Sxc 			    "parameter too short, %d, expected %d\n",
3140ba2cbe9Sxc 			    inp->wldp_length, sizeof (wl_wep_key_tab_t));
3150ba2cbe9Sxc 			outp->wldp_result = WL_NOTSUPPORTED;
3160ba2cbe9Sxc 			err = EINVAL;
3170ba2cbe9Sxc 			break;
3180ba2cbe9Sxc 		}
3190ba2cbe9Sxc 
320bcb5c89dSSowmini Varadhan 		err = wl_set_wepkey(ic, iw_wepkey);
3210ba2cbe9Sxc 		break;
3220ba2cbe9Sxc 	default:
3230ba2cbe9Sxc 		ieee80211_err("wifi_cfg_wepkey: unknown command %x\n", cmd);
3240ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
3250ba2cbe9Sxc 		err = EINVAL;
3260ba2cbe9Sxc 		break;
3270ba2cbe9Sxc 	}
3280ba2cbe9Sxc 
3290ba2cbe9Sxc 	freemsg(*mp);
3300ba2cbe9Sxc 	*mp = omp;
3310ba2cbe9Sxc 	return (err);
3320ba2cbe9Sxc }
3330ba2cbe9Sxc 
3340ba2cbe9Sxc static int
wifi_cfg_keyid(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)3350ba2cbe9Sxc wifi_cfg_keyid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
3360ba2cbe9Sxc {
3370ba2cbe9Sxc 	mblk_t *omp;
3380ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
3390ba2cbe9Sxc 	wldp_t *outp;
3400ba2cbe9Sxc 	wl_wep_key_id_t *iw_kid = (wl_wep_key_id_t *)inp->wldp_buf;
3410ba2cbe9Sxc 	wl_wep_key_id_t *ow_kid;
3420ba2cbe9Sxc 	int err = 0;
3430ba2cbe9Sxc 
3440ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wep_key_id_t))) == NULL)
3450ba2cbe9Sxc 		return (ENOMEM);
3460ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
3470ba2cbe9Sxc 	ow_kid = (wl_wep_key_id_t *)outp->wldp_buf;
3480ba2cbe9Sxc 
3490ba2cbe9Sxc 	switch (cmd) {
3500ba2cbe9Sxc 	case WLAN_GET_PARAM:
3510ba2cbe9Sxc 		*ow_kid = (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) ?
3523a1a8936Szf 		    0 : ic->ic_def_txkey;
3530ba2cbe9Sxc 		break;
3540ba2cbe9Sxc 	case  WLAN_SET_PARAM:
3550ba2cbe9Sxc 		if (*iw_kid >= MAX_NWEPKEYS) {
3560ba2cbe9Sxc 			ieee80211_err("wifi_cfg_keyid: "
3570ba2cbe9Sxc 			    "keyid too large, %u\n", *iw_kid);
3580ba2cbe9Sxc 			outp->wldp_result = WL_NOTSUPPORTED;
3590ba2cbe9Sxc 			err = EINVAL;
3600ba2cbe9Sxc 		} else {
3610ba2cbe9Sxc 			ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_keyid: "
3620ba2cbe9Sxc 			    "set keyid=%u\n", *iw_kid);
3630ba2cbe9Sxc 			ic->ic_def_txkey = *iw_kid;
3640ba2cbe9Sxc 			err = ENETRESET;
3650ba2cbe9Sxc 		}
3660ba2cbe9Sxc 		break;
3670ba2cbe9Sxc 	default:
3680ba2cbe9Sxc 		ieee80211_err("wifi_cfg_keyid: unknown command %x\n", cmd);
3690ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
3700ba2cbe9Sxc 		err = EINVAL;
3710ba2cbe9Sxc 		break;
3720ba2cbe9Sxc 	}
3730ba2cbe9Sxc 
3740ba2cbe9Sxc 	freemsg(*mp);
3750ba2cbe9Sxc 	*mp = omp;
3760ba2cbe9Sxc 	return (err);
3770ba2cbe9Sxc }
3780ba2cbe9Sxc 
3790ba2cbe9Sxc static int
wifi_cfg_authmode(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)3800ba2cbe9Sxc wifi_cfg_authmode(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
3810ba2cbe9Sxc {
3820ba2cbe9Sxc 	mblk_t *omp;
3830ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
3840ba2cbe9Sxc 	wldp_t *outp;
3850ba2cbe9Sxc 	wl_authmode_t *iw_auth = (wl_authmode_t *)inp->wldp_buf;
3860ba2cbe9Sxc 	wl_authmode_t *ow_auth;
3870ba2cbe9Sxc 	int err = 0;
3880ba2cbe9Sxc 
3890ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_authmode_t))) == NULL)
3900ba2cbe9Sxc 		return (ENOMEM);
3910ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
3920ba2cbe9Sxc 	ow_auth = (wl_authmode_t *)outp->wldp_buf;
3930ba2cbe9Sxc 
3940ba2cbe9Sxc 	switch (cmd) {
3950ba2cbe9Sxc 	case WLAN_GET_PARAM:
396bcb5c89dSSowmini Varadhan 		wl_get_authmode(ic, ow_auth);
3970ba2cbe9Sxc 		break;
3980ba2cbe9Sxc 	case WLAN_SET_PARAM:
399bcb5c89dSSowmini Varadhan 		err = wl_set_authmode(ic, iw_auth);
4000ba2cbe9Sxc 		break;
4010ba2cbe9Sxc 	default:
4020ba2cbe9Sxc 		ieee80211_err("wifi_cfg_authmode: unknown command %x\n", cmd);
4030ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
4040ba2cbe9Sxc 		err = EINVAL;
4050ba2cbe9Sxc 		break;
4060ba2cbe9Sxc 	}
4070ba2cbe9Sxc 
4080ba2cbe9Sxc 	freemsg(*mp);
4090ba2cbe9Sxc 	*mp = omp;
4100ba2cbe9Sxc 	return (err);
4110ba2cbe9Sxc }
4120ba2cbe9Sxc 
4130ba2cbe9Sxc static int
wifi_cfg_encrypt(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)4140ba2cbe9Sxc wifi_cfg_encrypt(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
4150ba2cbe9Sxc {
4160ba2cbe9Sxc 	mblk_t *omp;
4170ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
4180ba2cbe9Sxc 	wldp_t *outp;
4190ba2cbe9Sxc 	wl_encryption_t *iw_encryp = (wl_encryption_t *)inp->wldp_buf;
4200ba2cbe9Sxc 	wl_encryption_t *ow_encryp;
4210ba2cbe9Sxc 	int err = 0;
4220ba2cbe9Sxc 
4230ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_encryption_t))) == NULL)
4240ba2cbe9Sxc 		return (ENOMEM);
4250ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
4260ba2cbe9Sxc 	ow_encryp = (wl_encryption_t *)outp->wldp_buf;
4270ba2cbe9Sxc 
4280ba2cbe9Sxc 	switch (cmd) {
4290ba2cbe9Sxc 	case WLAN_GET_PARAM:
430bcb5c89dSSowmini Varadhan 		wl_get_encrypt(ic, ow_encryp);
4310ba2cbe9Sxc 		break;
4320ba2cbe9Sxc 	case WLAN_SET_PARAM:
433bcb5c89dSSowmini Varadhan 		err = wl_set_encrypt(ic, iw_encryp);
4340ba2cbe9Sxc 		break;
4350ba2cbe9Sxc 	default:
4360ba2cbe9Sxc 		ieee80211_err("wifi_cfg_encrypt: unknown command %x\n", cmd);
4370ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
4380ba2cbe9Sxc 		err = EINVAL;
4390ba2cbe9Sxc 		break;
4400ba2cbe9Sxc 	}
4410ba2cbe9Sxc 
4420ba2cbe9Sxc 	freemsg(*mp);
4430ba2cbe9Sxc 	*mp = omp;
4440ba2cbe9Sxc 	return (err);
4450ba2cbe9Sxc }
4460ba2cbe9Sxc 
4470ba2cbe9Sxc static int
wifi_cfg_bsstype(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)4480ba2cbe9Sxc wifi_cfg_bsstype(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
4490ba2cbe9Sxc {
4500ba2cbe9Sxc 	mblk_t *omp;
4510ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
4520ba2cbe9Sxc 	wldp_t *outp;
4530ba2cbe9Sxc 	wl_bss_type_t *iw_opmode = (wl_bss_type_t *)inp->wldp_buf;
4540ba2cbe9Sxc 	wl_bss_type_t *ow_opmode;
4550ba2cbe9Sxc 	int err = 0;
4560ba2cbe9Sxc 
4570ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bss_type_t))) == NULL)
4580ba2cbe9Sxc 		return (ENOMEM);
4590ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
4600ba2cbe9Sxc 	ow_opmode = (wl_bss_type_t *)outp->wldp_buf;
4610ba2cbe9Sxc 
4620ba2cbe9Sxc 	switch (cmd) {
4630ba2cbe9Sxc 	case WLAN_GET_PARAM:
464bcb5c89dSSowmini Varadhan 		wl_get_bsstype(ic, ow_opmode);
4650ba2cbe9Sxc 		break;
4660ba2cbe9Sxc 	case  WLAN_SET_PARAM:
46719d332feSfei feng - Sun Microsystems - Beijing China 		if (*iw_opmode == ic->ic_opmode)
46819d332feSfei feng - Sun Microsystems - Beijing China 			break;
46919d332feSfei feng - Sun Microsystems - Beijing China 
470bcb5c89dSSowmini Varadhan 		err = wl_set_bsstype(ic, iw_opmode);
4710ba2cbe9Sxc 		break;
4720ba2cbe9Sxc 	default:
4730ba2cbe9Sxc 		ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd);
4740ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
4750ba2cbe9Sxc 		err = EINVAL;
4760ba2cbe9Sxc 		break;
4770ba2cbe9Sxc 	}
4780ba2cbe9Sxc 
4790ba2cbe9Sxc 	freemsg(*mp);
4800ba2cbe9Sxc 	*mp = omp;
4810ba2cbe9Sxc 	return (err);
4820ba2cbe9Sxc }
4830ba2cbe9Sxc 
48419d332feSfei feng - Sun Microsystems - Beijing China static int
wifi_cfg_createibss(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)48519d332feSfei feng - Sun Microsystems - Beijing China wifi_cfg_createibss(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
48619d332feSfei feng - Sun Microsystems - Beijing China {
48719d332feSfei feng - Sun Microsystems - Beijing China 	mblk_t *omp;
48819d332feSfei feng - Sun Microsystems - Beijing China 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
48919d332feSfei feng - Sun Microsystems - Beijing China 	wldp_t *outp;
49019d332feSfei feng - Sun Microsystems - Beijing China 	wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)inp->wldp_buf;
49119d332feSfei feng - Sun Microsystems - Beijing China 	wl_create_ibss_t *ow_ibss;
49219d332feSfei feng - Sun Microsystems - Beijing China 	int err = 0;
49319d332feSfei feng - Sun Microsystems - Beijing China 
49419d332feSfei feng - Sun Microsystems - Beijing China 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_create_ibss_t))) == NULL)
49519d332feSfei feng - Sun Microsystems - Beijing China 		return (ENOMEM);
49619d332feSfei feng - Sun Microsystems - Beijing China 	outp = (wldp_t *)omp->b_rptr;
49719d332feSfei feng - Sun Microsystems - Beijing China 	ow_ibss = (wl_create_ibss_t *)outp->wldp_buf;
49819d332feSfei feng - Sun Microsystems - Beijing China 
49919d332feSfei feng - Sun Microsystems - Beijing China 	switch (cmd) {
50019d332feSfei feng - Sun Microsystems - Beijing China 	case WLAN_GET_PARAM:
501127ac1c2Sfei feng - Sun Microsystems - Beijing China 		wl_get_createibss(ic, ow_ibss);
50219d332feSfei feng - Sun Microsystems - Beijing China 		break;
50319d332feSfei feng - Sun Microsystems - Beijing China 	case  WLAN_SET_PARAM:
504127ac1c2Sfei feng - Sun Microsystems - Beijing China 		err = wl_set_createibss(ic, iw_ibss);
50519d332feSfei feng - Sun Microsystems - Beijing China 		break;
50619d332feSfei feng - Sun Microsystems - Beijing China 	default:
50719d332feSfei feng - Sun Microsystems - Beijing China 		ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd);
50819d332feSfei feng - Sun Microsystems - Beijing China 		outp->wldp_result = WL_NOTSUPPORTED;
50919d332feSfei feng - Sun Microsystems - Beijing China 		err = EINVAL;
51019d332feSfei feng - Sun Microsystems - Beijing China 		break;
51119d332feSfei feng - Sun Microsystems - Beijing China 	}
51219d332feSfei feng - Sun Microsystems - Beijing China 
51319d332feSfei feng - Sun Microsystems - Beijing China 	freemsg(*mp);
51419d332feSfei feng - Sun Microsystems - Beijing China 	*mp = omp;
51519d332feSfei feng - Sun Microsystems - Beijing China 	return (err);
51619d332feSfei feng - Sun Microsystems - Beijing China }
51719d332feSfei feng - Sun Microsystems - Beijing China 
5180ba2cbe9Sxc static int
wifi_cfg_linkstatus(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)5190ba2cbe9Sxc wifi_cfg_linkstatus(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
5200ba2cbe9Sxc {
5210ba2cbe9Sxc 	mblk_t *omp;
5220ba2cbe9Sxc 	wldp_t *outp;
5230ba2cbe9Sxc 	wl_linkstatus_t *ow_linkstat;
5240ba2cbe9Sxc 	int err = 0;
5250ba2cbe9Sxc 
5260ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_linkstatus_t))) == NULL)
5270ba2cbe9Sxc 		return (ENOMEM);
5280ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
5290ba2cbe9Sxc 	ow_linkstat = (wl_linkstatus_t *)outp->wldp_buf;
5300ba2cbe9Sxc 
5310ba2cbe9Sxc 	switch (cmd) {
5320ba2cbe9Sxc 	case WLAN_GET_PARAM:
533bcb5c89dSSowmini Varadhan 		wl_get_linkstatus(ic, ow_linkstat);
5340ba2cbe9Sxc 		break;
5350ba2cbe9Sxc 	case WLAN_SET_PARAM:
5360ba2cbe9Sxc 		outp->wldp_result = WL_READONLY;
5370ba2cbe9Sxc 		err = EINVAL;
5380ba2cbe9Sxc 		break;
5390ba2cbe9Sxc 	default:
5400ba2cbe9Sxc 		ieee80211_err("wifi_cfg_linkstatus: unknown command %x\n", cmd);
5410ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
5420ba2cbe9Sxc 		err = EINVAL;
5430ba2cbe9Sxc 		break;
5440ba2cbe9Sxc 	}
5450ba2cbe9Sxc 
5460ba2cbe9Sxc 	freemsg(*mp);
5470ba2cbe9Sxc 	*mp = omp;
5480ba2cbe9Sxc 	return (err);
5490ba2cbe9Sxc }
5500ba2cbe9Sxc 
5510ba2cbe9Sxc static int
wifi_cfg_suprates(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)5520ba2cbe9Sxc wifi_cfg_suprates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
5530ba2cbe9Sxc {
5540ba2cbe9Sxc 	mblk_t *omp;
5550ba2cbe9Sxc 	wldp_t *outp;
5560ba2cbe9Sxc 	wl_rates_t *ow_rates;
557bcb5c89dSSowmini Varadhan 	int err, buflen;
5580ba2cbe9Sxc 
5590ba2cbe9Sxc 	err = 0;
5600ba2cbe9Sxc 	/* rate value (wl_rates_rates) is of type char */
5610ba2cbe9Sxc 	buflen = offsetof(wl_rates_t, wl_rates_rates) +
5623a1a8936Szf 	    sizeof (char) * IEEE80211_MODE_MAX * IEEE80211_RATE_MAXSIZE;
5630ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, buflen)) == NULL)
5640ba2cbe9Sxc 		return (ENOMEM);
5650ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
5660ba2cbe9Sxc 	ow_rates = (wl_rates_t *)outp->wldp_buf;
5670ba2cbe9Sxc 
5680ba2cbe9Sxc 	switch (cmd) {
5690ba2cbe9Sxc 	case WLAN_GET_PARAM:
570bcb5c89dSSowmini Varadhan 		(void) wl_get_suprates(ic, ow_rates);
5710ba2cbe9Sxc 		break;
5720ba2cbe9Sxc 	case WLAN_SET_PARAM:
5730ba2cbe9Sxc 		outp->wldp_result = WL_READONLY;
5740ba2cbe9Sxc 		err = EINVAL;
5750ba2cbe9Sxc 		break;
5760ba2cbe9Sxc 	default:
5770ba2cbe9Sxc 		ieee80211_err("wifi_cfg_suprates: unknown command %x\n", cmd);
5780ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
5790ba2cbe9Sxc 		err = EINVAL;
5800ba2cbe9Sxc 		break;
5810ba2cbe9Sxc 	}
5820ba2cbe9Sxc 
5830ba2cbe9Sxc 	freemsg(*mp);
5840ba2cbe9Sxc 	*mp = omp;
5850ba2cbe9Sxc 	return (err);
5860ba2cbe9Sxc }
5870ba2cbe9Sxc 
5880ba2cbe9Sxc static int
wifi_cfg_desrates(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)5890ba2cbe9Sxc wifi_cfg_desrates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
5900ba2cbe9Sxc {
5910ba2cbe9Sxc 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
5920ba2cbe9Sxc 	wl_rates_t *iw_rates = (wl_rates_t *)inp->wldp_buf;
5930ba2cbe9Sxc 	mblk_t *omp;
5940ba2cbe9Sxc 	wldp_t *outp;
5950ba2cbe9Sxc 	wl_rates_t *ow_rates;
596bcb5c89dSSowmini Varadhan 	int err;
5970ba2cbe9Sxc 
5980ba2cbe9Sxc 	err = 0;
5990ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rates_t))) == NULL)
6000ba2cbe9Sxc 		return (ENOMEM);
6010ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
6020ba2cbe9Sxc 	ow_rates = (wl_rates_t *)outp->wldp_buf;
6030ba2cbe9Sxc 
6040ba2cbe9Sxc 	switch (cmd) {
6050ba2cbe9Sxc 	case  WLAN_GET_PARAM:
606bcb5c89dSSowmini Varadhan 		wl_get_desrates(ic, ow_rates);
6070ba2cbe9Sxc 		break;
6080ba2cbe9Sxc 	case  WLAN_SET_PARAM:
609bcb5c89dSSowmini Varadhan 		err = wl_set_desrates(ic, iw_rates);
6100ba2cbe9Sxc 		break;
6110ba2cbe9Sxc 	default:
6120ba2cbe9Sxc 		ieee80211_err("wifi_cfg_desrates: unknown command %x\n", cmd);
6130ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
6140ba2cbe9Sxc 		err = EINVAL;
6150ba2cbe9Sxc 		break;
6160ba2cbe9Sxc 	}
6170ba2cbe9Sxc 
6180ba2cbe9Sxc 	freemsg(*mp);
6190ba2cbe9Sxc 	*mp = omp;
6200ba2cbe9Sxc 	return (err);
6210ba2cbe9Sxc }
6220ba2cbe9Sxc 
6230ba2cbe9Sxc /*
6240ba2cbe9Sxc  * Rescale device's RSSI value to (0, 15) as required by WiFi
6250ba2cbe9Sxc  * driver IOCTLs (PSARC/2003/722)
6260ba2cbe9Sxc  */
6270ba2cbe9Sxc static wl_rssi_t
wifi_getrssi(struct ieee80211_node * in)6280ba2cbe9Sxc wifi_getrssi(struct ieee80211_node *in)
6290ba2cbe9Sxc {
6300ba2cbe9Sxc 	struct ieee80211com *ic = in->in_ic;
6310ba2cbe9Sxc 	wl_rssi_t rssi, max_rssi;
6320ba2cbe9Sxc 
6330ba2cbe9Sxc 	rssi = ic->ic_node_getrssi(in);
6340ba2cbe9Sxc 	max_rssi = (ic->ic_maxrssi == 0) ? IEEE80211_MAXRSSI : ic->ic_maxrssi;
6350ba2cbe9Sxc 	if (rssi == 0)
6360ba2cbe9Sxc 		rssi = 0;
6370ba2cbe9Sxc 	else if (rssi >= max_rssi)
6380ba2cbe9Sxc 		rssi = MAX_RSSI;
6390ba2cbe9Sxc 	else
6400ba2cbe9Sxc 		rssi = rssi * MAX_RSSI / max_rssi + 1;
6410ba2cbe9Sxc 
6420ba2cbe9Sxc 	return (rssi);
6430ba2cbe9Sxc }
6440ba2cbe9Sxc 
6450ba2cbe9Sxc static int
wifi_cfg_rssi(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)6460ba2cbe9Sxc wifi_cfg_rssi(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
6470ba2cbe9Sxc {
6480ba2cbe9Sxc 	mblk_t *omp;
6490ba2cbe9Sxc 	wldp_t *outp;
6500ba2cbe9Sxc 	wl_rssi_t *ow_rssi;
6510ba2cbe9Sxc 	int err = 0;
6520ba2cbe9Sxc 
6530ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rssi_t))) == NULL)
6540ba2cbe9Sxc 		return (ENOMEM);
6550ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
6560ba2cbe9Sxc 	ow_rssi = (wl_rssi_t *)outp->wldp_buf;
6570ba2cbe9Sxc 
6580ba2cbe9Sxc 	switch (cmd) {
6590ba2cbe9Sxc 	case  WLAN_GET_PARAM:
6600ba2cbe9Sxc 		*ow_rssi = wifi_getrssi(ic->ic_bss);
6610ba2cbe9Sxc 		break;
6620ba2cbe9Sxc 	case  WLAN_SET_PARAM:
6630ba2cbe9Sxc 		outp->wldp_result = WL_READONLY;
6640ba2cbe9Sxc 		err = EINVAL;
6650ba2cbe9Sxc 		break;
6660ba2cbe9Sxc 	default:
6670ba2cbe9Sxc 		ieee80211_err("wifi_cfg_rssi: unknown command %x\n", cmd);
6680ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
6690ba2cbe9Sxc 		return (EINVAL);
6700ba2cbe9Sxc 	}
6710ba2cbe9Sxc 
6720ba2cbe9Sxc 	freemsg(*mp);
6730ba2cbe9Sxc 	*mp = omp;
6740ba2cbe9Sxc 	return (err);
6750ba2cbe9Sxc }
6760ba2cbe9Sxc 
6770ba2cbe9Sxc /*
6780ba2cbe9Sxc  * maximum scan wait time in second.
6790ba2cbe9Sxc  * Time spent on scaning one channel is usually 100~200ms. The maximum
6800ba2cbe9Sxc  * number of channels defined in wifi_ioctl.h is 99 (MAX_CHANNEL_NUM).
6810ba2cbe9Sxc  * As a result the maximum total scan time is defined as below in ms.
6820ba2cbe9Sxc  */
6830ba2cbe9Sxc #define	WAIT_SCAN_MAX	(200 * MAX_CHANNEL_NUM)
6840ba2cbe9Sxc 
6850ba2cbe9Sxc static void
wifi_wait_scan(struct ieee80211com * ic)6860ba2cbe9Sxc wifi_wait_scan(struct ieee80211com *ic)
6870ba2cbe9Sxc {
6880ba2cbe9Sxc 	ieee80211_impl_t *im = ic->ic_private;
689d3d50737SRafael Vanoni 	clock_t delta = drv_usectohz(WAIT_SCAN_MAX * 1000);
6900ba2cbe9Sxc 
6910ba2cbe9Sxc 	while ((ic->ic_flags & (IEEE80211_F_SCAN | IEEE80211_F_ASCAN)) != 0) {
692d3d50737SRafael Vanoni 		if (cv_reltimedwait_sig(&im->im_scan_cv, &ic->ic_genlock,
693d3d50737SRafael Vanoni 		    delta, TR_CLOCK_TICK) != 0) {
6940ba2cbe9Sxc 			break;
6950ba2cbe9Sxc 		}
6960ba2cbe9Sxc 	}
6970ba2cbe9Sxc }
6980ba2cbe9Sxc 
6990ba2cbe9Sxc #define	WIFI_HAVE_CAP(in, flag)	(((in)->in_capinfo & (flag)) ? 1 : 0)
700e2cf88acSQuaker Fang #define	WIFI_HAVE_HTCAP(in)	(((in)->in_htcap != 0) ? 1 : 0)
7010ba2cbe9Sxc 
7020ba2cbe9Sxc /*
7030ba2cbe9Sxc  * Callback function used by ieee80211_iterate_nodes() in
7040ba2cbe9Sxc  * wifi_cfg_esslist() to get info of each node in a node table
7050ba2cbe9Sxc  *    arg  output buffer, pointer to wl_ess_list_t
7060ba2cbe9Sxc  *    in   each node in the node table
7070ba2cbe9Sxc  */
7080ba2cbe9Sxc static void
wifi_read_ap(void * arg,struct ieee80211_node * in)7090ba2cbe9Sxc wifi_read_ap(void *arg, struct ieee80211_node *in)
7100ba2cbe9Sxc {
7110ba2cbe9Sxc 	wl_ess_list_t *aps = arg;
7120ba2cbe9Sxc 	ieee80211com_t *ic = in->in_ic;
7130ba2cbe9Sxc 	struct ieee80211_channel *chan = in->in_chan;
7140ba2cbe9Sxc 	struct ieee80211_rateset *rates = &(in->in_rates);
7150ba2cbe9Sxc 	wl_ess_conf_t *conf;
7160ba2cbe9Sxc 	uint8_t *end;
7170ba2cbe9Sxc 	uint_t i, nrates;
7180ba2cbe9Sxc 
7190ba2cbe9Sxc 	end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN -
7203a1a8936Szf 	    sizeof (wl_ess_list_t);
7210ba2cbe9Sxc 	conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num];
7220ba2cbe9Sxc 	if ((uint8_t *)conf > end)
7230ba2cbe9Sxc 		return;
7240ba2cbe9Sxc 
72519d332feSfei feng - Sun Microsystems - Beijing China 	conf->wl_ess_conf_length = sizeof (struct wl_ess_conf);
72619d332feSfei feng - Sun Microsystems - Beijing China 
7270ba2cbe9Sxc 	/* skip newly allocated NULL bss node */
7280ba2cbe9Sxc 	if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr))
7290ba2cbe9Sxc 		return;
7300ba2cbe9Sxc 
7310ba2cbe9Sxc 	conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen;
7320ba2cbe9Sxc 	bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid,
7330ba2cbe9Sxc 	    in->in_esslen);
7340ba2cbe9Sxc 	bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN);
7350ba2cbe9Sxc 	conf->wl_ess_conf_wepenabled =
7360ba2cbe9Sxc 	    (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ?
7370ba2cbe9Sxc 	    WL_ENC_WEP : WL_NOENCRYPTION);
7380ba2cbe9Sxc 	conf->wl_ess_conf_bsstype =
7390ba2cbe9Sxc 	    (in->in_capinfo & IEEE80211_CAPINFO_ESS ?
7400ba2cbe9Sxc 	    WL_BSS_BSS : WL_BSS_IBSS);
7410ba2cbe9Sxc 	conf->wl_ess_conf_sl = wifi_getrssi(in);
742a399b765Szf 	conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1);
7430ba2cbe9Sxc 
7440ba2cbe9Sxc 	/* physical (FH, DS, ERP) parameters */
7450ba2cbe9Sxc 	if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) {
7460ba2cbe9Sxc 		wl_ofdm_t *ofdm =
7470ba2cbe9Sxc 		    (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf);
7480ba2cbe9Sxc 		ofdm->wl_ofdm_subtype = WL_OFDM;
7490ba2cbe9Sxc 		ofdm->wl_ofdm_frequency = chan->ich_freq;
750e2cf88acSQuaker Fang 		ofdm->wl_ofdm_ht_enabled = WIFI_HAVE_HTCAP(in);
7510ba2cbe9Sxc 	} else {
7520ba2cbe9Sxc 		switch (in->in_phytype) {
7530ba2cbe9Sxc 		case IEEE80211_T_FH: {
7540ba2cbe9Sxc 			wl_fhss_t *fhss = (wl_fhss_t *)
7550ba2cbe9Sxc 			    &((conf->wl_phy_conf).wl_phy_fhss_conf);
7560ba2cbe9Sxc 
7570ba2cbe9Sxc 			fhss->wl_fhss_subtype = WL_FHSS;
7580ba2cbe9Sxc 			fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan);
7590ba2cbe9Sxc 			fhss->wl_fhss_dwelltime = in->in_fhdwell;
7600ba2cbe9Sxc 			break;
7610ba2cbe9Sxc 		}
7620ba2cbe9Sxc 		case IEEE80211_T_DS: {
7630ba2cbe9Sxc 			wl_dsss_t *dsss = (wl_dsss_t *)
7640ba2cbe9Sxc 			    &((conf->wl_phy_conf).wl_phy_dsss_conf);
7650ba2cbe9Sxc 
7660ba2cbe9Sxc 			dsss->wl_dsss_subtype = WL_DSSS;
7670ba2cbe9Sxc 			dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan);
7680ba2cbe9Sxc 			dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in,
7690ba2cbe9Sxc 			    IEEE80211_CAPINFO_SHORT_PREAMBLE);
7700ba2cbe9Sxc 			dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in,
7710ba2cbe9Sxc 			    IEEE80211_CAPINFO_CHNL_AGILITY);
7720ba2cbe9Sxc 			dsss->wl_dsss_have_pbcc = dsss->wl_dsss_pbcc_enable =
7730ba2cbe9Sxc 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC);
7740ba2cbe9Sxc 			break;
7750ba2cbe9Sxc 		}
7760ba2cbe9Sxc 		case IEEE80211_T_OFDM: {
7770ba2cbe9Sxc 			wl_erp_t *erp = (wl_erp_t *)
7780ba2cbe9Sxc 			    &((conf->wl_phy_conf).wl_phy_erp_conf);
7790ba2cbe9Sxc 
7800ba2cbe9Sxc 			erp->wl_erp_subtype = WL_ERP;
7810ba2cbe9Sxc 			erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan);
7820ba2cbe9Sxc 			erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in,
7830ba2cbe9Sxc 			    IEEE80211_CAPINFO_SHORT_PREAMBLE);
7840ba2cbe9Sxc 			erp->wl_erp_have_agility = erp->wl_erp_agility_enabled =
7850ba2cbe9Sxc 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_CHNL_AGILITY);
7860ba2cbe9Sxc 			erp->wl_erp_have_pbcc = erp->wl_erp_pbcc_enabled =
7870ba2cbe9Sxc 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_PBCC);
7880ba2cbe9Sxc 			erp->wl_erp_dsss_ofdm_enabled =
7890ba2cbe9Sxc 			    WIFI_HAVE_CAP(in, IEEE80211_CAPINFO_DSSSOFDM);
7900ba2cbe9Sxc 			erp->wl_erp_sst_enabled = WIFI_HAVE_CAP(in,
7910ba2cbe9Sxc 			    IEEE80211_CAPINFO_SHORT_SLOTTIME);
792e2cf88acSQuaker Fang 			erp->wl_erp_ht_enabled = WIFI_HAVE_HTCAP(in);
7930ba2cbe9Sxc 			break;
7940ba2cbe9Sxc 		} /* case IEEE80211_T_OFDM */
7950ba2cbe9Sxc 		} /* switch in->in_phytype */
7960ba2cbe9Sxc 	}
7970ba2cbe9Sxc 
7980ba2cbe9Sxc 	/* supported rates */
7990ba2cbe9Sxc 	nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES);
8000ba2cbe9Sxc 	/*
8010ba2cbe9Sxc 	 * The number of supported rates might exceed
8020ba2cbe9Sxc 	 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates
8030ba2cbe9Sxc 	 * first so userland command could properly show
8040ba2cbe9Sxc 	 * maximum speed of AP
8050ba2cbe9Sxc 	 */
8060ba2cbe9Sxc 	for (i = 0; i < nrates; i++) {
8070ba2cbe9Sxc 		conf->wl_supported_rates[i] =
8080ba2cbe9Sxc 		    rates->ir_rates[rates->ir_nrates - i - 1];
8090ba2cbe9Sxc 	}
8100ba2cbe9Sxc 
8110ba2cbe9Sxc 	aps->wl_ess_list_num++;
8120ba2cbe9Sxc }
8130ba2cbe9Sxc 
8140ba2cbe9Sxc static int
wifi_cfg_esslist(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)8150ba2cbe9Sxc wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
8160ba2cbe9Sxc {
8170ba2cbe9Sxc 	mblk_t *omp;
8180ba2cbe9Sxc 	wldp_t *outp;
8190ba2cbe9Sxc 	wl_ess_list_t *ow_aps;
8200ba2cbe9Sxc 	int err = 0;
8210ba2cbe9Sxc 
8220ba2cbe9Sxc 	if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) ==
8230ba2cbe9Sxc 	    NULL) {
8240ba2cbe9Sxc 		return (ENOMEM);
8250ba2cbe9Sxc 	}
8260ba2cbe9Sxc 	outp = (wldp_t *)omp->b_rptr;
8270ba2cbe9Sxc 	ow_aps = (wl_ess_list_t *)outp->wldp_buf;
8280ba2cbe9Sxc 
8290ba2cbe9Sxc 	switch (cmd) {
8300ba2cbe9Sxc 	case WLAN_GET_PARAM:
8310ba2cbe9Sxc 		ow_aps->wl_ess_list_num = 0;
8320ba2cbe9Sxc 		ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps);
8330ba2cbe9Sxc 		outp->wldp_length = WIFI_BUF_OFFSET +
8340ba2cbe9Sxc 		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
8350ba2cbe9Sxc 		    ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t);
8360ba2cbe9Sxc 		omp->b_wptr = omp->b_rptr + outp->wldp_length;
8370ba2cbe9Sxc 		break;
8380ba2cbe9Sxc 	case WLAN_SET_PARAM:
8390ba2cbe9Sxc 		outp->wldp_result = WL_READONLY;
8400ba2cbe9Sxc 		err = EINVAL;
8410ba2cbe9Sxc 		break;
8420ba2cbe9Sxc 	default:
8430ba2cbe9Sxc 		ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd);
8440ba2cbe9Sxc 		outp->wldp_result = WL_NOTSUPPORTED;
8450ba2cbe9Sxc 		err = EINVAL;
8460ba2cbe9Sxc 		break;
8470ba2cbe9Sxc 	}
8480ba2cbe9Sxc 
8490ba2cbe9Sxc 	freemsg(*mp);
8500ba2cbe9Sxc 	*mp = omp;
8510ba2cbe9Sxc 	return (err);
8520ba2cbe9Sxc }
8530ba2cbe9Sxc 
8540ba2cbe9Sxc /*
8550ba2cbe9Sxc  * Scan the network for all available ESSs.
8560ba2cbe9Sxc  * IEEE80211_F_SCANONLY is set when current state is INIT. And
8570ba2cbe9Sxc  * with this flag, after scan the state will be changed back to
8580ba2cbe9Sxc  * INIT. The reason is at the end of SCAN stage, the STA will
8590ba2cbe9Sxc  * consequently connect to an AP. Then it looks unreasonable that
8600ba2cbe9Sxc  * for a disconnected device, A SCAN command causes it connected.
8610ba2cbe9Sxc  * So the state is changed back to INIT.
8620ba2cbe9Sxc  */
8630ba2cbe9Sxc static int
wifi_cmd_scan(struct ieee80211com * ic,mblk_t * mp)8640ba2cbe9Sxc wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp)
8650ba2cbe9Sxc {
8660ba2cbe9Sxc 	int ostate = ic->ic_state;
8670ba2cbe9Sxc 
8680ba2cbe9Sxc 	/*
8690ba2cbe9Sxc 	 * Do not scan when current state is RUN. The reason is
8700ba2cbe9Sxc 	 * when connected, STA is on the same channel as AP. But
8710ba2cbe9Sxc 	 * to do scan, STA have to switch to each available channel,
8720ba2cbe9Sxc 	 * send probe request and wait certian time for probe
8730ba2cbe9Sxc 	 * response/beacon. Then when the STA switches to a channel
8740ba2cbe9Sxc 	 * different than AP's, as a result it cannot send/receive
8750ba2cbe9Sxc 	 * data packets to/from the connected WLAN. This eventually
8760ba2cbe9Sxc 	 * will cause data loss.
8770ba2cbe9Sxc 	 */
8780ba2cbe9Sxc 	if (ostate == IEEE80211_S_RUN)
8790ba2cbe9Sxc 		return (0);
8800ba2cbe9Sxc 
8810ba2cbe9Sxc 	IEEE80211_UNLOCK(ic);
882a399b765Szf 
8830ba2cbe9Sxc 	ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
8840ba2cbe9Sxc 	IEEE80211_LOCK(ic);
8850ba2cbe9Sxc 	if (ostate == IEEE80211_S_INIT)
8860ba2cbe9Sxc 		ic->ic_flags |= IEEE80211_F_SCANONLY;
8870ba2cbe9Sxc 
888a399b765Szf 	/* Don't wait on WPA mode */
889a399b765Szf 	if ((ic->ic_flags & IEEE80211_F_WPA) == 0) {
890a399b765Szf 		/* wait scan complete */
891a399b765Szf 		wifi_wait_scan(ic);
892a399b765Szf 	}
8930ba2cbe9Sxc 
8940ba2cbe9Sxc 	wifi_setupoutmsg(mp, 0);
8950ba2cbe9Sxc 	return (0);
8960ba2cbe9Sxc }
8970ba2cbe9Sxc 
8980ba2cbe9Sxc static void
wifi_loaddefdata(struct ieee80211com * ic)8990ba2cbe9Sxc wifi_loaddefdata(struct ieee80211com *ic)
9000ba2cbe9Sxc {
9010ba2cbe9Sxc 	struct ieee80211_node *in = ic->ic_bss;
9020ba2cbe9Sxc 	int i;
9030ba2cbe9Sxc 
9040ba2cbe9Sxc 	ic->ic_des_esslen = 0;
9050ba2cbe9Sxc 	bzero(ic->ic_des_essid, IEEE80211_NWID_LEN);
9060ba2cbe9Sxc 	ic->ic_flags &= ~IEEE80211_F_DESBSSID;
9070ba2cbe9Sxc 	bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN);
9080ba2cbe9Sxc 	bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN);
9090ba2cbe9Sxc 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;
9100ba2cbe9Sxc 	ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
9110ba2cbe9Sxc 	bzero(ic->ic_nickname, IEEE80211_NWID_LEN);
9120ba2cbe9Sxc 	in->in_authmode = IEEE80211_AUTH_OPEN;
9130ba2cbe9Sxc 	ic->ic_flags &= ~IEEE80211_F_PRIVACY;
914a399b765Szf 	ic->ic_flags &= ~IEEE80211_F_WPA;	/* mask WPA mode */
915a399b765Szf 	ic->ic_evq_head = ic->ic_evq_tail = 0;	/* reset Queue */
9160ba2cbe9Sxc 	ic->ic_def_txkey = 0;
9170ba2cbe9Sxc 	for (i = 0; i < MAX_NWEPKEYS; i++) {
9180ba2cbe9Sxc 		ic->ic_nw_keys[i].wk_keylen = 0;
9190ba2cbe9Sxc 		bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE);
9200ba2cbe9Sxc 	}
9210ba2cbe9Sxc 	ic->ic_curmode = IEEE80211_MODE_AUTO;
92219d332feSfei feng - Sun Microsystems - Beijing China 	ic->ic_flags &= ~IEEE80211_F_IBSSON;
92319d332feSfei feng - Sun Microsystems - Beijing China 	ic->ic_opmode = IEEE80211_M_STA;
9240ba2cbe9Sxc }
9250ba2cbe9Sxc 
9260ba2cbe9Sxc static int
wifi_cmd_loaddefaults(struct ieee80211com * ic,mblk_t * mp)9270ba2cbe9Sxc wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp)
9280ba2cbe9Sxc {
9290ba2cbe9Sxc 	wifi_loaddefdata(ic);
9300ba2cbe9Sxc 	wifi_setupoutmsg(mp, 0);
9310ba2cbe9Sxc 	return (ENETRESET);
9320ba2cbe9Sxc }
9330ba2cbe9Sxc 
9340ba2cbe9Sxc static int
wifi_cmd_disassoc(struct ieee80211com * ic,mblk_t * mp)9350ba2cbe9Sxc wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp)
9360ba2cbe9Sxc {
9370ba2cbe9Sxc 	if (ic->ic_state != IEEE80211_S_INIT) {
9380ba2cbe9Sxc 		IEEE80211_UNLOCK(ic);
9390ba2cbe9Sxc 		(void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
9400ba2cbe9Sxc 		IEEE80211_LOCK(ic);
9410ba2cbe9Sxc 	}
9420ba2cbe9Sxc 	wifi_loaddefdata(ic);
9430ba2cbe9Sxc 	wifi_setupoutmsg(mp, 0);
9440ba2cbe9Sxc 	return (0);
9450ba2cbe9Sxc }
9460ba2cbe9Sxc 
947a399b765Szf /*
948a399b765Szf  * Get the capabilities of drivers.
949a399b765Szf  */
950a399b765Szf static int
wifi_cfg_caps(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)951a399b765Szf wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
952a399b765Szf {
953a399b765Szf 	mblk_t *omp;
954a399b765Szf 	wldp_t *outp;
955a399b765Szf 	wl_capability_t *o_caps;
956a399b765Szf 	int err = 0;
957a399b765Szf 
958a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL)
959a399b765Szf 		return (ENOMEM);
960a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
961a399b765Szf 	o_caps = (wl_capability_t *)outp->wldp_buf;
962a399b765Szf 
963a399b765Szf 	switch (cmd) {
964a399b765Szf 	case WLAN_GET_PARAM:
965bcb5c89dSSowmini Varadhan 		wl_get_capability(ic, o_caps);
966a399b765Szf 		break;
967a399b765Szf 	case WLAN_SET_PARAM:
968a399b765Szf 		outp->wldp_result = WL_READONLY;
969a399b765Szf 		err = EINVAL;
970a399b765Szf 		break;
971a399b765Szf 	default:
972a399b765Szf 		ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd);
973a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
974a399b765Szf 		err = EINVAL;
975a399b765Szf 		break;
976a399b765Szf 	}
977a399b765Szf 
978a399b765Szf 	freemsg(*mp);
979a399b765Szf 	*mp = omp;
980a399b765Szf 	return (err);
981a399b765Szf }
982a399b765Szf 
983a399b765Szf /*
984a399b765Szf  * Operating on WPA mode.
985a399b765Szf  */
986a399b765Szf static int
wifi_cfg_wpa(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)987a399b765Szf wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
988a399b765Szf {
989a399b765Szf 	mblk_t *omp;
990a399b765Szf 	wldp_t *outp;
991a399b765Szf 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
992a399b765Szf 	wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf;
993a399b765Szf 	wl_wpa_t *o_wpa;
994a399b765Szf 	int err = 0;
995a399b765Szf 
996a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL)
997a399b765Szf 		return (ENOMEM);
998a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
999a399b765Szf 	o_wpa = (wl_wpa_t *)outp->wldp_buf;
1000a399b765Szf 
1001a399b765Szf 	switch (cmd) {
1002a399b765Szf 	case WLAN_GET_PARAM:
1003bcb5c89dSSowmini Varadhan 		wl_get_wpa(ic, o_wpa);
1004a399b765Szf 		break;
1005a399b765Szf 	case WLAN_SET_PARAM:
1006bcb5c89dSSowmini Varadhan 		err = wl_set_wpa(ic, wpa);
1007a399b765Szf 		break;
1008a399b765Szf 	default:
1009a399b765Szf 		ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd);
1010a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
1011a399b765Szf 		err = EINVAL;
1012a399b765Szf 		break;
1013a399b765Szf 	}
1014a399b765Szf 
1015a399b765Szf 	freemsg(*mp);
1016a399b765Szf 	*mp = omp;
1017a399b765Szf 	return (err);
1018a399b765Szf }
1019a399b765Szf 
1020a399b765Szf /*
1021a399b765Szf  * WPA daemon set the WPA keys.
1022a399b765Szf  * The WPA keys are negotiated with APs through wpa service.
1023a399b765Szf  */
1024a399b765Szf static int
wifi_cfg_wpakey(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1025a399b765Szf wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1026a399b765Szf {
1027a399b765Szf 	mblk_t *omp;
1028a399b765Szf 	wldp_t *outp;
1029a399b765Szf 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1030a399b765Szf 	wl_key_t *ik = (wl_key_t *)(inp->wldp_buf);
1031a399b765Szf 	int err = 0;
1032a399b765Szf 
1033a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1034a399b765Szf 		return (ENOMEM);
1035a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
1036a399b765Szf 
1037a399b765Szf 	switch (cmd) {
1038a399b765Szf 	case WLAN_GET_PARAM:
1039a399b765Szf 		outp->wldp_result = WL_WRITEONLY;
1040a399b765Szf 		err = EINVAL;
1041a399b765Szf 		break;
1042a399b765Szf 	case WLAN_SET_PARAM:
1043bcb5c89dSSowmini Varadhan 		err = wl_set_wpakey(ic, ik);
1044a399b765Szf 		break;
1045a399b765Szf 	default:
1046a399b765Szf 		ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd);
1047a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
1048a399b765Szf 		err = EINVAL;
1049a399b765Szf 		break;
1050a399b765Szf 	}
1051a399b765Szf 
1052a399b765Szf 	freemsg(*mp);
1053a399b765Szf 	*mp = omp;
1054a399b765Szf 	return (err);
1055a399b765Szf }
1056a399b765Szf 
1057a399b765Szf /*
1058a399b765Szf  * Delete obsolete keys - keys are dynamically exchanged between APs
1059a399b765Szf  * and wpa daemon.
1060a399b765Szf  */
1061a399b765Szf static int
wifi_cfg_delkey(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1062a399b765Szf wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1063a399b765Szf {
1064a399b765Szf 	mblk_t *omp;
1065a399b765Szf 	wldp_t *outp;
1066a399b765Szf 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1067a399b765Szf 	wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf;
1068a399b765Szf 	int err = 0;
1069a399b765Szf 
1070a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1071a399b765Szf 		return (ENOMEM);
1072a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
1073a399b765Szf 
1074a399b765Szf 	switch (cmd) {
1075a399b765Szf 	case WLAN_GET_PARAM:
1076a399b765Szf 		outp->wldp_result = WL_WRITEONLY;
1077a399b765Szf 		err = EINVAL;
1078a399b765Szf 		break;
1079a399b765Szf 	case WLAN_SET_PARAM:
1080bcb5c89dSSowmini Varadhan 		err = wl_set_delkey(ic, dk);
1081a399b765Szf 		break;
1082a399b765Szf 	default:
1083a399b765Szf 		ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd);
1084a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
1085a399b765Szf 		err = EINVAL;
1086a399b765Szf 		break;
1087a399b765Szf 	}
1088a399b765Szf 
1089a399b765Szf 	freemsg(*mp);
1090a399b765Szf 	*mp = omp;
1091a399b765Szf 	return (err);
1092a399b765Szf }
1093a399b765Szf 
1094a399b765Szf /*
1095a399b765Szf  * The OPTIE will be used in the association request.
1096a399b765Szf  */
1097a399b765Szf static int
wifi_cfg_setoptie(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1098a399b765Szf wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1099a399b765Szf {
1100a399b765Szf 	mblk_t *omp;
1101a399b765Szf 	wldp_t *outp;
1102a399b765Szf 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1103a399b765Szf 	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf;
1104a399b765Szf 	int err = 0;
1105a399b765Szf 
1106a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1107a399b765Szf 		return (ENOMEM);
1108a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
1109a399b765Szf 
1110a399b765Szf 	switch (cmd) {
1111a399b765Szf 	case WLAN_GET_PARAM:
1112a399b765Szf 		outp->wldp_result = WL_WRITEONLY;
1113a399b765Szf 		err = EINVAL;
1114a399b765Szf 		break;
1115a399b765Szf 	case WLAN_SET_PARAM:
1116bcb5c89dSSowmini Varadhan 		if ((err = wl_set_optie(ic, ie_in)) == EINVAL)
1117a399b765Szf 			outp->wldp_result = WL_NOTSUPPORTED;
1118a399b765Szf 		break;
1119a399b765Szf 	default:
1120a399b765Szf 		ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd);
1121a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
1122a399b765Szf 		err = EINVAL;
1123a399b765Szf 		break;
1124a399b765Szf 	}
1125a399b765Szf 
1126a399b765Szf 	freemsg(*mp);
1127a399b765Szf 	*mp = omp;
1128a399b765Szf 	return (err);
1129a399b765Szf }
1130a399b765Szf 
1131a399b765Szf /*
1132a399b765Szf  * To be compatible with drivers/tools of OpenSolaris.org,
1133a399b765Szf  * we use a different ID to filter out those APs of WPA mode.
1134a399b765Szf  */
1135a399b765Szf static int
wifi_cfg_scanresults(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1136a399b765Szf wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1137a399b765Szf {
1138a399b765Szf 	mblk_t *omp;
1139a399b765Szf 	wldp_t *outp;
1140a399b765Szf 	wl_wpa_ess_t *sr;
1141a399b765Szf 	ieee80211_node_t *in;
1142a399b765Szf 	ieee80211_node_table_t *nt;
1143a399b765Szf 	int len, ap_num = 0;
1144a399b765Szf 	int err = 0;
1145a399b765Szf 
1146a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) ==
1147a399b765Szf 	    NULL) {
1148a399b765Szf 		return (ENOMEM);
1149a399b765Szf 	}
1150a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
1151a399b765Szf 	sr = (wl_wpa_ess_t *)outp->wldp_buf;
1152a399b765Szf 	sr->count = 0;
1153a399b765Szf 
1154a399b765Szf 	switch (cmd) {
1155a399b765Szf 	case WLAN_GET_PARAM:
1156a399b765Szf 		ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n");
1157a399b765Szf 		nt = &ic->ic_scan;
1158a399b765Szf 		IEEE80211_NODE_LOCK(nt);
1159a399b765Szf 		in = list_head(&nt->nt_node);
1160a399b765Szf 		while (in != NULL) {
1161a399b765Szf 			/* filter out non-WPA APs */
1162a399b765Szf 			if (in->in_wpa_ie == NULL) {
1163a399b765Szf 				in = list_next(&nt->nt_node, in);
1164a399b765Szf 				continue;
1165a399b765Szf 			}
1166a399b765Szf 			bcopy(in->in_bssid, sr->ess[ap_num].bssid,
1167a399b765Szf 			    IEEE80211_ADDR_LEN);
1168a399b765Szf 			sr->ess[ap_num].ssid_len = in->in_esslen;
1169a399b765Szf 			bcopy(in->in_essid, sr->ess[ap_num].ssid,
1170a399b765Szf 			    in->in_esslen);
1171a399b765Szf 			sr->ess[ap_num].freq = in->in_chan->ich_freq;
1172a399b765Szf 
1173a399b765Szf 			len = in->in_wpa_ie[1] + 2;
1174a399b765Szf 			bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len);
1175a399b765Szf 			sr->ess[ap_num].wpa_ie_len = len;
1176a399b765Szf 
1177a399b765Szf 			ap_num ++;
1178a399b765Szf 			in = list_next(&nt->nt_node, in);
1179a399b765Szf 		}
1180a399b765Szf 		IEEE80211_NODE_UNLOCK(nt);
1181a399b765Szf 		sr->count = ap_num;
1182a399b765Szf 		outp->wldp_length = WIFI_BUF_OFFSET +
1183a399b765Szf 		    offsetof(wl_wpa_ess_t, ess) +
1184a399b765Szf 		    sr->count * sizeof (struct wpa_ess);
1185a399b765Szf 		omp->b_wptr = omp->b_rptr + outp->wldp_length;
1186a399b765Szf 		break;
1187a399b765Szf 	case WLAN_SET_PARAM:
1188a399b765Szf 		outp->wldp_result = WL_READONLY;
1189a399b765Szf 		err = EINVAL;
1190a399b765Szf 		break;
1191a399b765Szf 	default:
1192a399b765Szf 		ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd);
1193a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
1194a399b765Szf 		err = EINVAL;
1195a399b765Szf 		break;
1196a399b765Szf 	}
1197a399b765Szf 
1198a399b765Szf 	freemsg(*mp);
1199a399b765Szf 	*mp = omp;
1200a399b765Szf 	return (err);
1201a399b765Szf }
1202a399b765Szf 
1203a399b765Szf /*
1204a399b765Szf  * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC
1205a399b765Szf  */
1206a399b765Szf static int
wifi_cfg_setmlme(struct ieee80211com * ic,uint32_t cmd,mblk_t ** mp)1207a399b765Szf wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
1208a399b765Szf {
1209a399b765Szf 	mblk_t *omp;
1210a399b765Szf 	wldp_t *outp;
1211a399b765Szf 	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
1212a399b765Szf 	wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf;
1213a399b765Szf 	int err = 0;
1214a399b765Szf 
1215a399b765Szf 	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
1216a399b765Szf 		return (ENOMEM);
1217a399b765Szf 	outp = (wldp_t *)omp->b_rptr;
1218a399b765Szf 
1219a399b765Szf 	switch (cmd) {
1220a399b765Szf 	case WLAN_GET_PARAM:
1221a399b765Szf 		outp->wldp_result = WL_WRITEONLY;
1222a399b765Szf 		err = EINVAL;
1223a399b765Szf 		break;
1224a399b765Szf 	case WLAN_SET_PARAM:
1225bcb5c89dSSowmini Varadhan 		err = wl_set_mlme(ic, mlme);
1226a399b765Szf 		break;
1227a399b765Szf 	default:
1228a399b765Szf 		ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd);
1229a399b765Szf 		outp->wldp_result = WL_NOTSUPPORTED;
1230a399b765Szf 		err = EINVAL;
1231a399b765Szf 		break;
1232a399b765Szf 	}
1233a399b765Szf 
1234a399b765Szf 	freemsg(*mp);
1235a399b765Szf 	*mp = omp;
1236a399b765Szf 	return (err);
1237a399b765Szf }
1238a399b765Szf 
12390ba2cbe9Sxc static int
wifi_cfg_getset(struct ieee80211com * ic,mblk_t ** mp,uint32_t cmd)12400ba2cbe9Sxc wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd)
12410ba2cbe9Sxc {
12420ba2cbe9Sxc 	mblk_t *mp1 = *mp;
12430ba2cbe9Sxc 	wldp_t *wp = (wldp_t *)mp1->b_rptr;
12440ba2cbe9Sxc 	int err = 0;
12450ba2cbe9Sxc 
12460ba2cbe9Sxc 	ASSERT(ic != NULL && mp1 != NULL);
12470ba2cbe9Sxc 	IEEE80211_LOCK_ASSERT(ic);
12480ba2cbe9Sxc 	if (MBLKL(mp1) < WIFI_BUF_OFFSET) {
12490ba2cbe9Sxc 		ieee80211_err("wifi_cfg_getset: "
12500ba2cbe9Sxc 		    "invalid input buffer, size=%d\n", MBLKL(mp1));
12510ba2cbe9Sxc 		return (EINVAL);
12520ba2cbe9Sxc 	}
12530ba2cbe9Sxc 
12540ba2cbe9Sxc 	switch (wp->wldp_id) {
12550ba2cbe9Sxc 	/* Commands */
12560ba2cbe9Sxc 	case WL_SCAN:
12570ba2cbe9Sxc 		err = wifi_cmd_scan(ic, mp1);
12580ba2cbe9Sxc 		break;
12590ba2cbe9Sxc 	case WL_LOAD_DEFAULTS:
12600ba2cbe9Sxc 		err = wifi_cmd_loaddefaults(ic, mp1);
12610ba2cbe9Sxc 		break;
12620ba2cbe9Sxc 	case WL_DISASSOCIATE:
12630ba2cbe9Sxc 		err = wifi_cmd_disassoc(ic, mp1);
12640ba2cbe9Sxc 		break;
12650ba2cbe9Sxc 	/* Parameters */
12660ba2cbe9Sxc 	case WL_ESSID:
12670ba2cbe9Sxc 		err = wifi_cfg_essid(ic, cmd, mp);
12680ba2cbe9Sxc 		break;
12690ba2cbe9Sxc 	case WL_BSSID:
12700ba2cbe9Sxc 		err = wifi_cfg_bssid(ic, cmd, mp);
12710ba2cbe9Sxc 		break;
12720ba2cbe9Sxc 	case WL_NODE_NAME:
12730ba2cbe9Sxc 		err = wifi_cfg_nodename(ic, cmd, mp);
12740ba2cbe9Sxc 		break;
12750ba2cbe9Sxc 	case WL_PHY_CONFIG:
12760ba2cbe9Sxc 		err = wifi_cfg_phy(ic, cmd, mp);
12770ba2cbe9Sxc 		break;
12780ba2cbe9Sxc 	case WL_WEP_KEY_TAB:
12790ba2cbe9Sxc 		err = wifi_cfg_wepkey(ic, cmd, mp);
12800ba2cbe9Sxc 		break;
12810ba2cbe9Sxc 	case WL_WEP_KEY_ID:
12820ba2cbe9Sxc 		err = wifi_cfg_keyid(ic, cmd, mp);
12830ba2cbe9Sxc 		break;
12840ba2cbe9Sxc 	case WL_AUTH_MODE:
12850ba2cbe9Sxc 		err = wifi_cfg_authmode(ic, cmd, mp);
12860ba2cbe9Sxc 		break;
12870ba2cbe9Sxc 	case WL_ENCRYPTION:
12880ba2cbe9Sxc 		err = wifi_cfg_encrypt(ic, cmd, mp);
12890ba2cbe9Sxc 		break;
12900ba2cbe9Sxc 	case WL_BSS_TYPE:
12910ba2cbe9Sxc 		err = wifi_cfg_bsstype(ic, cmd, mp);
12920ba2cbe9Sxc 		break;
129319d332feSfei feng - Sun Microsystems - Beijing China 	case WL_CREATE_IBSS:
129419d332feSfei feng - Sun Microsystems - Beijing China 		err = wifi_cfg_createibss(ic, cmd, mp);
129519d332feSfei feng - Sun Microsystems - Beijing China 		break;
12960ba2cbe9Sxc 	case WL_DESIRED_RATES:
12970ba2cbe9Sxc 		err = wifi_cfg_desrates(ic, cmd, mp);
12980ba2cbe9Sxc 		break;
12990ba2cbe9Sxc 	case WL_LINKSTATUS:
13000ba2cbe9Sxc 		err = wifi_cfg_linkstatus(ic, cmd, mp);
13010ba2cbe9Sxc 		break;
13020ba2cbe9Sxc 	case WL_ESS_LIST:
13030ba2cbe9Sxc 		err = wifi_cfg_esslist(ic, cmd, mp);
13040ba2cbe9Sxc 		break;
13050ba2cbe9Sxc 	case WL_SUPPORTED_RATES:
13060ba2cbe9Sxc 		err = wifi_cfg_suprates(ic, cmd, mp);
13070ba2cbe9Sxc 		break;
13080ba2cbe9Sxc 	case WL_RSSI:
13090ba2cbe9Sxc 		err = wifi_cfg_rssi(ic, cmd, mp);
13100ba2cbe9Sxc 		break;
1311a399b765Szf 	/*
1312a399b765Szf 	 * WPA IOCTLs
1313a399b765Szf 	 */
1314a399b765Szf 	case WL_CAPABILITY:
1315a399b765Szf 		err = wifi_cfg_caps(ic, cmd, mp);
1316a399b765Szf 		break;
1317a399b765Szf 	case WL_WPA:
1318a399b765Szf 		err = wifi_cfg_wpa(ic, cmd, mp);
1319a399b765Szf 		break;
1320a399b765Szf 	case WL_KEY:
1321a399b765Szf 		err = wifi_cfg_wpakey(ic, cmd, mp);
1322a399b765Szf 		break;
1323a399b765Szf 	case WL_DELKEY:
1324a399b765Szf 		err = wifi_cfg_delkey(ic, cmd, mp);
1325a399b765Szf 		break;
1326a399b765Szf 	case WL_SETOPTIE:
1327a399b765Szf 		err = wifi_cfg_setoptie(ic, cmd, mp);
1328a399b765Szf 		break;
1329a399b765Szf 	case WL_SCANRESULTS:
1330a399b765Szf 		err = wifi_cfg_scanresults(ic, cmd, mp);
1331a399b765Szf 		break;
1332a399b765Szf 	case WL_MLME:
1333a399b765Szf 		err = wifi_cfg_setmlme(ic, cmd, mp);
1334a399b765Szf 		break;
13350ba2cbe9Sxc 	default:
13360ba2cbe9Sxc 		wifi_setupoutmsg(mp1, 0);
13370ba2cbe9Sxc 		wp->wldp_result = WL_LACK_FEATURE;
13380ba2cbe9Sxc 		err = ENOTSUP;
13390ba2cbe9Sxc 		break;
13400ba2cbe9Sxc 	}
13410ba2cbe9Sxc 
13420ba2cbe9Sxc 	return (err);
13430ba2cbe9Sxc }
13440ba2cbe9Sxc 
13450ba2cbe9Sxc /*
13460ba2cbe9Sxc  * Typically invoked by drivers in response to requests for
13470ba2cbe9Sxc  * information or to change settings from the userland.
13480ba2cbe9Sxc  *
13490ba2cbe9Sxc  * Return value should be checked by WiFi drivers. Return 0
13500ba2cbe9Sxc  * on success. Otherwise, return non-zero value to indicate
13510ba2cbe9Sxc  * the error. Driver should operate as below when the return
13520ba2cbe9Sxc  * error is:
13530ba2cbe9Sxc  * ENETRESET	Reset wireless network and re-start to join a
13540ba2cbe9Sxc  *		WLAN. ENETRESET is returned when a configuration
13550ba2cbe9Sxc  *		parameter has been changed.
13560ba2cbe9Sxc  *		When acknowledge a M_IOCTL message, thie error
13570ba2cbe9Sxc  *		is ignored.
13580ba2cbe9Sxc  */
13590ba2cbe9Sxc int
ieee80211_ioctl(struct ieee80211com * ic,queue_t * wq,mblk_t * mp)13600ba2cbe9Sxc ieee80211_ioctl(struct ieee80211com *ic, queue_t *wq, mblk_t *mp)
13610ba2cbe9Sxc {
13620ba2cbe9Sxc 	struct iocblk *iocp;
13630ba2cbe9Sxc 	int32_t cmd, err, len;
13640ba2cbe9Sxc 	boolean_t need_privilege;
13650ba2cbe9Sxc 	mblk_t *mp1;
13660ba2cbe9Sxc 
13670ba2cbe9Sxc 	if (MBLKL(mp) < sizeof (struct iocblk)) {
13680ba2cbe9Sxc 		ieee80211_err("ieee80211_ioctl: ioctl buffer too short, %u\n",
13690ba2cbe9Sxc 		    MBLKL(mp));
13700ba2cbe9Sxc 		miocnak(wq, mp, 0, EINVAL);
13710ba2cbe9Sxc 		return (EINVAL);
13720ba2cbe9Sxc 	}
13730ba2cbe9Sxc 
13740ba2cbe9Sxc 	/*
13750ba2cbe9Sxc 	 * Validate the command
13760ba2cbe9Sxc 	 */
13770ba2cbe9Sxc 	iocp = (struct iocblk *)mp->b_rptr;
13780ba2cbe9Sxc 	iocp->ioc_error = 0;
13790ba2cbe9Sxc 	cmd = iocp->ioc_cmd;
13800ba2cbe9Sxc 	need_privilege = B_TRUE;
13810ba2cbe9Sxc 	switch (cmd) {
13820ba2cbe9Sxc 	case WLAN_SET_PARAM:
13830ba2cbe9Sxc 	case WLAN_COMMAND:
13840ba2cbe9Sxc 		break;
13850ba2cbe9Sxc 	case WLAN_GET_PARAM:
13860ba2cbe9Sxc 		need_privilege = B_FALSE;
13870ba2cbe9Sxc 		break;
13880ba2cbe9Sxc 	default:
13890ba2cbe9Sxc 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): "
13900ba2cbe9Sxc 		    "unknown cmd 0x%x\n", cmd);
13910ba2cbe9Sxc 		miocnak(wq, mp, 0, EINVAL);
13920ba2cbe9Sxc 		return (EINVAL);
13930ba2cbe9Sxc 	}
13940ba2cbe9Sxc 
1395eae72b5bSSebastien Roy 	if (need_privilege && (err = secpolicy_dl_config(iocp->ioc_cr)) != 0) {
1396eae72b5bSSebastien Roy 		miocnak(wq, mp, 0, err);
1397eae72b5bSSebastien Roy 		return (err);
13980ba2cbe9Sxc 	}
13990ba2cbe9Sxc 
14000ba2cbe9Sxc 	IEEE80211_LOCK(ic);
14010ba2cbe9Sxc 
14020ba2cbe9Sxc 	/* sanity check */
14030ba2cbe9Sxc 	mp1 = mp->b_cont;
14040ba2cbe9Sxc 	if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) ||
14050ba2cbe9Sxc 	    mp1 == NULL) {
14060ba2cbe9Sxc 		miocnak(wq, mp, 0, EINVAL);
14070ba2cbe9Sxc 		IEEE80211_UNLOCK(ic);
14080ba2cbe9Sxc 		return (EINVAL);
14090ba2cbe9Sxc 	}
14100ba2cbe9Sxc 
14110ba2cbe9Sxc 	/* assuming single data block */
14120ba2cbe9Sxc 	if (mp1->b_cont != NULL) {
14130ba2cbe9Sxc 		freemsg(mp1->b_cont);
14140ba2cbe9Sxc 		mp1->b_cont = NULL;
14150ba2cbe9Sxc 	}
14160ba2cbe9Sxc 
14170ba2cbe9Sxc 	err = wifi_cfg_getset(ic, &mp1, cmd);
14180ba2cbe9Sxc 	mp->b_cont = mp1;
14190ba2cbe9Sxc 	IEEE80211_UNLOCK(ic);
14200ba2cbe9Sxc 
14210ba2cbe9Sxc 	len = msgdsize(mp1);
14220ba2cbe9Sxc 	/* ignore ENETRESET when acknowledge the M_IOCTL message */
14230ba2cbe9Sxc 	if (err == 0 || err == ENETRESET)
14240ba2cbe9Sxc 		miocack(wq, mp, len, 0);
14250ba2cbe9Sxc 	else
14260ba2cbe9Sxc 		miocack(wq, mp, len, err);
14270ba2cbe9Sxc 
14280ba2cbe9Sxc 	return (err);
14290ba2cbe9Sxc }
1430bcb5c89dSSowmini Varadhan 
1431bcb5c89dSSowmini Varadhan /*
1432bcb5c89dSSowmini Varadhan  * The following routines are for brussels support
1433bcb5c89dSSowmini Varadhan  */
1434bcb5c89dSSowmini Varadhan 
1435bcb5c89dSSowmini Varadhan /*
1436bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_ESSID
1437bcb5c89dSSowmini Varadhan  */
1438bcb5c89dSSowmini Varadhan static int
wl_set_essid(struct ieee80211com * ic,const void * wldp_buf)1439bcb5c89dSSowmini Varadhan wl_set_essid(struct ieee80211com *ic, const void *wldp_buf)
1440bcb5c89dSSowmini Varadhan {
1441bcb5c89dSSowmini Varadhan 	int err = 0;
1442bcb5c89dSSowmini Varadhan 	char *essid;
1443bcb5c89dSSowmini Varadhan 	wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
1444bcb5c89dSSowmini Varadhan 
1445bcb5c89dSSowmini Varadhan 	if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN) {
1446bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_essid: "
1447bcb5c89dSSowmini Varadhan 		    "essid too long, %u, max %u\n",
1448bcb5c89dSSowmini Varadhan 		    iw_essid->wl_essid_length, IEEE80211_NWID_LEN);
1449bcb5c89dSSowmini Varadhan 
1450bcb5c89dSSowmini Varadhan 		err = EINVAL;
1451bcb5c89dSSowmini Varadhan 		return (err);
1452bcb5c89dSSowmini Varadhan 	}
1453bcb5c89dSSowmini Varadhan 
1454bcb5c89dSSowmini Varadhan 	essid = iw_essid->wl_essid_essid;
1455bcb5c89dSSowmini Varadhan 	essid[IEEE80211_NWID_LEN] = 0;
1456bcb5c89dSSowmini Varadhan 
1457bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_essid: "
1458bcb5c89dSSowmini Varadhan 	    "set essid=%s length=%d\n",
1459bcb5c89dSSowmini Varadhan 	    essid, iw_essid->wl_essid_length);
1460bcb5c89dSSowmini Varadhan 
1461bcb5c89dSSowmini Varadhan 	ic->ic_des_esslen = iw_essid->wl_essid_length;
1462bcb5c89dSSowmini Varadhan 	if (ic->ic_des_esslen != 0)
1463bcb5c89dSSowmini Varadhan 		bcopy(essid, ic->ic_des_essid, ic->ic_des_esslen);
1464bcb5c89dSSowmini Varadhan 	if (ic->ic_des_esslen < IEEE80211_NWID_LEN)
1465bcb5c89dSSowmini Varadhan 		ic->ic_des_essid[ic->ic_des_esslen] = 0;
1466bcb5c89dSSowmini Varadhan 
1467bcb5c89dSSowmini Varadhan 	err = ENETRESET;
1468bcb5c89dSSowmini Varadhan 
1469bcb5c89dSSowmini Varadhan 	return (err);
1470bcb5c89dSSowmini Varadhan }
1471bcb5c89dSSowmini Varadhan 
1472bcb5c89dSSowmini Varadhan static void
wl_get_essid(struct ieee80211com * ic,void * wldp_buf)1473bcb5c89dSSowmini Varadhan wl_get_essid(struct ieee80211com *ic, void *wldp_buf)
1474bcb5c89dSSowmini Varadhan {
1475bcb5c89dSSowmini Varadhan 	char *essid;
1476bcb5c89dSSowmini Varadhan 	wl_essid_t ow_essid;
1477bcb5c89dSSowmini Varadhan 
1478bcb5c89dSSowmini Varadhan 	essid = (char *)ic->ic_des_essid;
1479bcb5c89dSSowmini Varadhan 	if (essid[0] == '\0')
1480bcb5c89dSSowmini Varadhan 		essid = (char *)ic->ic_bss->in_essid;
1481bcb5c89dSSowmini Varadhan 
1482bcb5c89dSSowmini Varadhan 	bzero(&ow_essid, sizeof (wl_essid_t));
1483bcb5c89dSSowmini Varadhan 	ow_essid.wl_essid_length = wifi_strnlen((const char *)essid,
1484bcb5c89dSSowmini Varadhan 	    IEEE80211_NWID_LEN);
1485bcb5c89dSSowmini Varadhan 	bcopy(essid, ow_essid.wl_essid_essid,
1486bcb5c89dSSowmini Varadhan 	    ow_essid.wl_essid_length);
1487bcb5c89dSSowmini Varadhan 	bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
1488bcb5c89dSSowmini Varadhan 
1489bcb5c89dSSowmini Varadhan }
1490bcb5c89dSSowmini Varadhan 
1491bcb5c89dSSowmini Varadhan /*
1492bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_BSSID
1493bcb5c89dSSowmini Varadhan  */
1494bcb5c89dSSowmini Varadhan static int
wl_set_bssid(struct ieee80211com * ic,const void * wldp_buf)1495bcb5c89dSSowmini Varadhan wl_set_bssid(struct ieee80211com *ic, const void* wldp_buf)
1496bcb5c89dSSowmini Varadhan {
1497bcb5c89dSSowmini Varadhan 
1498bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bssid: "
1499bcb5c89dSSowmini Varadhan 	    "set bssid=%s\n",
1500bcb5c89dSSowmini Varadhan 	    ieee80211_macaddr_sprintf(wldp_buf));
1501bcb5c89dSSowmini Varadhan 
1502bcb5c89dSSowmini Varadhan 	bcopy(wldp_buf, ic->ic_des_bssid, sizeof (wl_bssid_t));
1503bcb5c89dSSowmini Varadhan 	ic->ic_flags |= IEEE80211_F_DESBSSID;
1504bcb5c89dSSowmini Varadhan 
1505bcb5c89dSSowmini Varadhan 	return (ENETRESET);
1506bcb5c89dSSowmini Varadhan }
1507bcb5c89dSSowmini Varadhan 
1508bcb5c89dSSowmini Varadhan static void
wl_get_bssid(struct ieee80211com * ic,void * wldp_buf)1509bcb5c89dSSowmini Varadhan wl_get_bssid(struct ieee80211com *ic, void *wldp_buf)
1510bcb5c89dSSowmini Varadhan {
1511bcb5c89dSSowmini Varadhan 	uint8_t *bssid;
1512bcb5c89dSSowmini Varadhan 
1513bcb5c89dSSowmini Varadhan 	if (ic->ic_flags & IEEE80211_F_DESBSSID)
1514bcb5c89dSSowmini Varadhan 		bssid = ic->ic_des_bssid;
1515bcb5c89dSSowmini Varadhan 	else
1516bcb5c89dSSowmini Varadhan 		bssid = ic->ic_bss->in_bssid;
1517bcb5c89dSSowmini Varadhan 	bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
1518bcb5c89dSSowmini Varadhan 
1519bcb5c89dSSowmini Varadhan }
1520bcb5c89dSSowmini Varadhan 
1521bcb5c89dSSowmini Varadhan /*
1522bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_BSSTYP
1523bcb5c89dSSowmini Varadhan  */
1524bcb5c89dSSowmini Varadhan static int
wl_set_bsstype(struct ieee80211com * ic,const void * wldp_buf)1525bcb5c89dSSowmini Varadhan wl_set_bsstype(struct ieee80211com *ic, const void *wldp_buf)
1526bcb5c89dSSowmini Varadhan {
1527bcb5c89dSSowmini Varadhan 	int err = 0;
1528bcb5c89dSSowmini Varadhan 	wl_bss_type_t *iw_opmode = (wl_bss_type_t *)wldp_buf;
1529bcb5c89dSSowmini Varadhan 
1530bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bsstype: "
1531bcb5c89dSSowmini Varadhan 	    "set bsstype=%u\n", *iw_opmode);
1532bcb5c89dSSowmini Varadhan 
1533bcb5c89dSSowmini Varadhan 	switch (*iw_opmode) {
1534bcb5c89dSSowmini Varadhan 	case WL_BSS_BSS:
1535bcb5c89dSSowmini Varadhan 		ic->ic_flags &= ~IEEE80211_F_IBSSON;
1536bcb5c89dSSowmini Varadhan 		ic->ic_opmode = IEEE80211_M_STA;
1537bcb5c89dSSowmini Varadhan 		err = ENETRESET;
1538bcb5c89dSSowmini Varadhan 		break;
1539bcb5c89dSSowmini Varadhan 	case WL_BSS_IBSS:
1540bcb5c89dSSowmini Varadhan 		if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) {
1541bcb5c89dSSowmini Varadhan 			err = ENOTSUP;
1542bcb5c89dSSowmini Varadhan 			break;
1543bcb5c89dSSowmini Varadhan 		}
154419d332feSfei feng - Sun Microsystems - Beijing China 
154519d332feSfei feng - Sun Microsystems - Beijing China 		ic->ic_opmode = IEEE80211_M_IBSS;
154619d332feSfei feng - Sun Microsystems - Beijing China 		err = ENETRESET;
1547bcb5c89dSSowmini Varadhan 		break;
1548bcb5c89dSSowmini Varadhan 	default:
1549bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_bsstype: "
1550bcb5c89dSSowmini Varadhan 		    "unknown opmode\n");
1551bcb5c89dSSowmini Varadhan 		err = EINVAL;
1552bcb5c89dSSowmini Varadhan 		break;
1553bcb5c89dSSowmini Varadhan 	}
1554bcb5c89dSSowmini Varadhan 	return (err);
1555bcb5c89dSSowmini Varadhan }
1556bcb5c89dSSowmini Varadhan 
1557bcb5c89dSSowmini Varadhan static void
wl_get_bsstype(struct ieee80211com * ic,void * wldp_buf)1558bcb5c89dSSowmini Varadhan wl_get_bsstype(struct ieee80211com *ic, void *wldp_buf)
1559bcb5c89dSSowmini Varadhan {
1560bcb5c89dSSowmini Varadhan 	wl_bss_type_t ow_opmode;
1561bcb5c89dSSowmini Varadhan 
1562bcb5c89dSSowmini Varadhan 	switch (ic->ic_opmode) {
1563bcb5c89dSSowmini Varadhan 	case IEEE80211_M_STA:
1564bcb5c89dSSowmini Varadhan 		ow_opmode = WL_BSS_BSS;
1565bcb5c89dSSowmini Varadhan 		break;
1566bcb5c89dSSowmini Varadhan 	case IEEE80211_M_IBSS:
1567bcb5c89dSSowmini Varadhan 		ow_opmode = WL_BSS_IBSS;
1568bcb5c89dSSowmini Varadhan 		break;
1569bcb5c89dSSowmini Varadhan 	default:
1570bcb5c89dSSowmini Varadhan 		ow_opmode = WL_BSS_ANY;
1571bcb5c89dSSowmini Varadhan 		break;
1572bcb5c89dSSowmini Varadhan 	}
1573bcb5c89dSSowmini Varadhan 
1574bcb5c89dSSowmini Varadhan 	bcopy(&ow_opmode, wldp_buf, sizeof (wl_bss_type_t));
1575bcb5c89dSSowmini Varadhan }
1576bcb5c89dSSowmini Varadhan 
1577bcb5c89dSSowmini Varadhan /*
1578bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_LINKSTATUS
1579bcb5c89dSSowmini Varadhan  */
1580bcb5c89dSSowmini Varadhan static void
wl_get_linkstatus(struct ieee80211com * ic,void * wldp_buf)1581bcb5c89dSSowmini Varadhan wl_get_linkstatus(struct ieee80211com *ic, void *wldp_buf)
1582bcb5c89dSSowmini Varadhan {
1583bcb5c89dSSowmini Varadhan 	wl_linkstatus_t ow_linkstat;
1584bcb5c89dSSowmini Varadhan 
1585bcb5c89dSSowmini Varadhan 	ow_linkstat = (ic->ic_state == IEEE80211_S_RUN) ?
1586bcb5c89dSSowmini Varadhan 	    WL_CONNECTED : WL_NOTCONNECTED;
1587bcb5c89dSSowmini Varadhan 	if ((ic->ic_flags & IEEE80211_F_WPA) &&
1588bcb5c89dSSowmini Varadhan 	    (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA)) {
1589bcb5c89dSSowmini Varadhan 		ow_linkstat = WL_NOTCONNECTED;
1590bcb5c89dSSowmini Varadhan 	}
1591bcb5c89dSSowmini Varadhan 
1592bcb5c89dSSowmini Varadhan 	bcopy(&ow_linkstat, wldp_buf, sizeof (wl_linkstatus_t));
1593bcb5c89dSSowmini Varadhan }
1594bcb5c89dSSowmini Varadhan 
1595bcb5c89dSSowmini Varadhan /*
1596bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_DESIRED_RATESa
1597bcb5c89dSSowmini Varadhan  */
1598bcb5c89dSSowmini Varadhan static int
wl_set_desrates(struct ieee80211com * ic,const void * wldp_buf)1599bcb5c89dSSowmini Varadhan wl_set_desrates(struct ieee80211com *ic, const void *wldp_buf)
1600bcb5c89dSSowmini Varadhan {
1601bcb5c89dSSowmini Varadhan 	int err = 0;
1602bcb5c89dSSowmini Varadhan 	int i, j;
1603bcb5c89dSSowmini Varadhan 	uint8_t drate;
1604bcb5c89dSSowmini Varadhan 	boolean_t isfound;
1605bcb5c89dSSowmini Varadhan 	wl_rates_t *iw_rates = (wl_rates_t *)wldp_buf;
1606bcb5c89dSSowmini Varadhan 	struct ieee80211_node *in = ic->ic_bss;
1607bcb5c89dSSowmini Varadhan 	struct ieee80211_rateset *rs = &in->in_rates;
1608bcb5c89dSSowmini Varadhan 
1609bcb5c89dSSowmini Varadhan 	drate = iw_rates->wl_rates_rates[0];
1610bcb5c89dSSowmini Varadhan 	if (ic->ic_fixed_rate == drate)
1611bcb5c89dSSowmini Varadhan 		return (err);
1612bcb5c89dSSowmini Varadhan 
1613bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_desrates: "
1614bcb5c89dSSowmini Varadhan 	    "set desired rate=%u\n", drate);
1615bcb5c89dSSowmini Varadhan 
1616bcb5c89dSSowmini Varadhan 	if (drate == 0) {
1617bcb5c89dSSowmini Varadhan 		ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
1618bcb5c89dSSowmini Varadhan 		if (ic->ic_state == IEEE80211_S_RUN) {
1619bcb5c89dSSowmini Varadhan 			IEEE80211_UNLOCK(ic);
1620bcb5c89dSSowmini Varadhan 			ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0);
1621bcb5c89dSSowmini Varadhan 			IEEE80211_LOCK(ic);
1622bcb5c89dSSowmini Varadhan 		}
1623bcb5c89dSSowmini Varadhan 		return (err);
1624bcb5c89dSSowmini Varadhan 	}
1625bcb5c89dSSowmini Varadhan 
1626bcb5c89dSSowmini Varadhan 	/*
1627bcb5c89dSSowmini Varadhan 	 * Set desired rate. The desired rate is for data transfer
1628bcb5c89dSSowmini Varadhan 	 * and usally is checked and used when driver changes to
1629bcb5c89dSSowmini Varadhan 	 * RUN state.
1630bcb5c89dSSowmini Varadhan 	 * If the driver is in AUTH | ASSOC | RUN state, desired
1631bcb5c89dSSowmini Varadhan 	 * rate is checked anainst rates supported by current ESS.
1632bcb5c89dSSowmini Varadhan 	 * If it's supported and current state is AUTH|ASSOC, nothing
1633bcb5c89dSSowmini Varadhan 	 * needs to be done by driver since the desired rate will
1634bcb5c89dSSowmini Varadhan 	 * be enabled when the device changes to RUN state. And
1635bcb5c89dSSowmini Varadhan 	 * when current state is RUN, Re-associate with the ESS to
1636bcb5c89dSSowmini Varadhan 	 * enable the desired rate.
1637bcb5c89dSSowmini Varadhan 	 */
1638bcb5c89dSSowmini Varadhan 
1639bcb5c89dSSowmini Varadhan 	if (ic->ic_state != IEEE80211_S_INIT &&
1640bcb5c89dSSowmini Varadhan 	    ic->ic_state != IEEE80211_S_SCAN) {
1641bcb5c89dSSowmini Varadhan 		for (i = 0; i < rs->ir_nrates; i++) {
1642bcb5c89dSSowmini Varadhan 			if (drate == IEEE80211_RV(rs->ir_rates[i]))
1643bcb5c89dSSowmini Varadhan 				break;
1644bcb5c89dSSowmini Varadhan 		}
1645bcb5c89dSSowmini Varadhan 		/* supported */
1646bcb5c89dSSowmini Varadhan 		if (i < rs->ir_nrates) {
1647bcb5c89dSSowmini Varadhan 			ic->ic_fixed_rate = drate;
1648bcb5c89dSSowmini Varadhan 			if (ic->ic_state == IEEE80211_S_RUN) {
1649bcb5c89dSSowmini Varadhan 				IEEE80211_UNLOCK(ic);
1650bcb5c89dSSowmini Varadhan 				ieee80211_new_state(ic,
1651bcb5c89dSSowmini Varadhan 				    IEEE80211_S_ASSOC, 0);
1652bcb5c89dSSowmini Varadhan 				IEEE80211_LOCK(ic);
1653bcb5c89dSSowmini Varadhan 			}
1654bcb5c89dSSowmini Varadhan 			return (err);
1655bcb5c89dSSowmini Varadhan 		}
1656bcb5c89dSSowmini Varadhan 	}
1657bcb5c89dSSowmini Varadhan 
1658bcb5c89dSSowmini Varadhan 	/*
1659bcb5c89dSSowmini Varadhan 	 * In INIT or SCAN state
1660bcb5c89dSSowmini Varadhan 	 * check if the desired rate is supported by device
1661bcb5c89dSSowmini Varadhan 	 */
1662bcb5c89dSSowmini Varadhan 	isfound = B_FALSE;
1663bcb5c89dSSowmini Varadhan 	for (i = 0; i < IEEE80211_MODE_MAX; i++) {
1664bcb5c89dSSowmini Varadhan 		rs = &ic->ic_sup_rates[i];
1665bcb5c89dSSowmini Varadhan 		for (j = 0; j < rs->ir_nrates; j++) {
1666bcb5c89dSSowmini Varadhan 			if (drate ==  IEEE80211_RV(rs->ir_rates[j])) {
1667bcb5c89dSSowmini Varadhan 				isfound = B_TRUE;
1668bcb5c89dSSowmini Varadhan 				break;
1669bcb5c89dSSowmini Varadhan 			}
1670bcb5c89dSSowmini Varadhan 		}
1671bcb5c89dSSowmini Varadhan 		if (isfound)
1672bcb5c89dSSowmini Varadhan 			break;
1673bcb5c89dSSowmini Varadhan 	}
1674bcb5c89dSSowmini Varadhan 	if (!isfound) {
1675bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_desrates: "
1676bcb5c89dSSowmini Varadhan 		    "invald rate %d\n", drate);
1677bcb5c89dSSowmini Varadhan 		err = EINVAL;
1678bcb5c89dSSowmini Varadhan 		return (err);
1679bcb5c89dSSowmini Varadhan 	}
1680bcb5c89dSSowmini Varadhan 	ic->ic_fixed_rate = drate;
1681bcb5c89dSSowmini Varadhan 	if (ic->ic_state != IEEE80211_S_SCAN)
1682bcb5c89dSSowmini Varadhan 		err = ENETRESET;
1683bcb5c89dSSowmini Varadhan 
1684bcb5c89dSSowmini Varadhan 	return (err);
1685bcb5c89dSSowmini Varadhan }
1686bcb5c89dSSowmini Varadhan 
1687bcb5c89dSSowmini Varadhan static void
wl_get_desrates(struct ieee80211com * ic,void * wldp_buf)1688bcb5c89dSSowmini Varadhan wl_get_desrates(struct ieee80211com *ic, void *wldp_buf)
1689bcb5c89dSSowmini Varadhan {
1690bcb5c89dSSowmini Varadhan 	uint8_t srate;
1691bcb5c89dSSowmini Varadhan 	wl_rates_t ow_rates;
1692bcb5c89dSSowmini Varadhan 	struct ieee80211_node *in = ic->ic_bss;
1693bcb5c89dSSowmini Varadhan 	struct ieee80211_rateset *rs = &in->in_rates;
1694bcb5c89dSSowmini Varadhan 
1695bcb5c89dSSowmini Varadhan 	srate = rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL;
1696bcb5c89dSSowmini Varadhan 	ow_rates.wl_rates_num = 1;
1697bcb5c89dSSowmini Varadhan 	ow_rates.wl_rates_rates[0] =
1698bcb5c89dSSowmini Varadhan 	    (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
1699bcb5c89dSSowmini Varadhan 	    srate : ic->ic_fixed_rate;
1700bcb5c89dSSowmini Varadhan 	bcopy(&ow_rates, wldp_buf, sizeof (wl_rates_t));
1701bcb5c89dSSowmini Varadhan 
1702bcb5c89dSSowmini Varadhan }
1703bcb5c89dSSowmini Varadhan 
1704bcb5c89dSSowmini Varadhan /*
1705bcb5c89dSSowmini Varadhan  * MAC_PROP_AUTH_MODE
1706bcb5c89dSSowmini Varadhan  */
1707bcb5c89dSSowmini Varadhan static int
wl_set_authmode(struct ieee80211com * ic,const void * wldp_buf)1708bcb5c89dSSowmini Varadhan wl_set_authmode(struct ieee80211com *ic, const void *wldp_buf)
1709bcb5c89dSSowmini Varadhan {
1710bcb5c89dSSowmini Varadhan 	int err = 0;
1711bcb5c89dSSowmini Varadhan 	wl_authmode_t *iw_auth = (wl_authmode_t *)wldp_buf;
1712bcb5c89dSSowmini Varadhan 
1713bcb5c89dSSowmini Varadhan 	if (*iw_auth == ic->ic_bss->in_authmode)
1714bcb5c89dSSowmini Varadhan 		return (err);
1715bcb5c89dSSowmini Varadhan 
1716bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_authmode: "
1717bcb5c89dSSowmini Varadhan 	    "set authmode=%u\n", *iw_auth);
1718bcb5c89dSSowmini Varadhan 
1719bcb5c89dSSowmini Varadhan 	switch (*iw_auth) {
1720bcb5c89dSSowmini Varadhan 	case WL_OPENSYSTEM:
1721bcb5c89dSSowmini Varadhan 	case WL_SHAREDKEY:
1722bcb5c89dSSowmini Varadhan 		ic->ic_bss->in_authmode = *iw_auth;
1723bcb5c89dSSowmini Varadhan 		err = ENETRESET;
1724bcb5c89dSSowmini Varadhan 		break;
1725bcb5c89dSSowmini Varadhan 	default:
1726bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_authmode: "
1727bcb5c89dSSowmini Varadhan 		    "unknown authmode %u\n", *iw_auth);
1728bcb5c89dSSowmini Varadhan 		err = EINVAL;
1729bcb5c89dSSowmini Varadhan 		break;
1730bcb5c89dSSowmini Varadhan 	}
1731bcb5c89dSSowmini Varadhan 
1732bcb5c89dSSowmini Varadhan 	return (err);
1733bcb5c89dSSowmini Varadhan }
1734bcb5c89dSSowmini Varadhan 
1735bcb5c89dSSowmini Varadhan static void
wl_get_authmode(struct ieee80211com * ic,void * wldp_buf)1736bcb5c89dSSowmini Varadhan wl_get_authmode(struct ieee80211com *ic, void *wldp_buf)
1737bcb5c89dSSowmini Varadhan {
1738bcb5c89dSSowmini Varadhan 	wl_authmode_t ow_auth;
1739bcb5c89dSSowmini Varadhan 
1740bcb5c89dSSowmini Varadhan 	ow_auth = ic->ic_bss->in_authmode;
1741bcb5c89dSSowmini Varadhan 	bcopy(&ow_auth, wldp_buf, sizeof (wl_authmode_t));
1742bcb5c89dSSowmini Varadhan 
1743bcb5c89dSSowmini Varadhan }
1744bcb5c89dSSowmini Varadhan 
1745bcb5c89dSSowmini Varadhan /*
1746bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_ENCRYPTION
1747bcb5c89dSSowmini Varadhan  */
1748bcb5c89dSSowmini Varadhan static int
wl_set_encrypt(struct ieee80211com * ic,const void * wldp_buf)1749bcb5c89dSSowmini Varadhan wl_set_encrypt(struct ieee80211com *ic, const void *wldp_buf)
1750bcb5c89dSSowmini Varadhan {
1751bcb5c89dSSowmini Varadhan 	int err = 0;
1752bcb5c89dSSowmini Varadhan 	uint32_t flags;
1753bcb5c89dSSowmini Varadhan 	wl_encryption_t *iw_encryp = (wl_encryption_t *)wldp_buf;
1754bcb5c89dSSowmini Varadhan 
1755bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_encrypt: "
1756bcb5c89dSSowmini Varadhan 	    "set encryption=%u\n", *iw_encryp);
1757bcb5c89dSSowmini Varadhan 
1758bcb5c89dSSowmini Varadhan 	flags = ic->ic_flags;
1759bcb5c89dSSowmini Varadhan 	if (*iw_encryp == WL_NOENCRYPTION)
1760bcb5c89dSSowmini Varadhan 		flags &= ~IEEE80211_F_PRIVACY;
1761bcb5c89dSSowmini Varadhan 	else
1762bcb5c89dSSowmini Varadhan 		flags |= IEEE80211_F_PRIVACY;
1763bcb5c89dSSowmini Varadhan 
1764bcb5c89dSSowmini Varadhan 	if (ic->ic_flags != flags) {
1765bcb5c89dSSowmini Varadhan 		ic->ic_flags = flags;
1766bcb5c89dSSowmini Varadhan 		err = ENETRESET;
1767bcb5c89dSSowmini Varadhan 	}
1768bcb5c89dSSowmini Varadhan 
1769bcb5c89dSSowmini Varadhan 	return (err);
1770bcb5c89dSSowmini Varadhan }
1771bcb5c89dSSowmini Varadhan 
1772bcb5c89dSSowmini Varadhan static void
wl_get_encrypt(struct ieee80211com * ic,void * wldp_buf)1773bcb5c89dSSowmini Varadhan wl_get_encrypt(struct ieee80211com *ic, void *wldp_buf)
1774bcb5c89dSSowmini Varadhan {
1775bcb5c89dSSowmini Varadhan 	wl_encryption_t *ow_encryp;
1776bcb5c89dSSowmini Varadhan 
1777bcb5c89dSSowmini Varadhan 	ow_encryp = (wl_encryption_t *)wldp_buf;
1778bcb5c89dSSowmini Varadhan 	*ow_encryp = (ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0;
1779bcb5c89dSSowmini Varadhan 	if (ic->ic_flags & IEEE80211_F_WPA)
1780bcb5c89dSSowmini Varadhan 		*ow_encryp = WL_ENC_WPA;
1781bcb5c89dSSowmini Varadhan 
1782bcb5c89dSSowmini Varadhan }
1783bcb5c89dSSowmini Varadhan 
1784bcb5c89dSSowmini Varadhan /*
1785bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_RSSI
1786bcb5c89dSSowmini Varadhan  */
1787bcb5c89dSSowmini Varadhan static void
wl_get_rssi(struct ieee80211com * ic,void * wldp_buf)1788bcb5c89dSSowmini Varadhan wl_get_rssi(struct ieee80211com *ic, void *wldp_buf)
1789bcb5c89dSSowmini Varadhan {
1790bcb5c89dSSowmini Varadhan 	wl_rssi_t *ow_rssi;
1791bcb5c89dSSowmini Varadhan 
1792bcb5c89dSSowmini Varadhan 	ow_rssi = (wl_rssi_t *)wldp_buf;
1793bcb5c89dSSowmini Varadhan 	*ow_rssi = wifi_getrssi(ic->ic_bss);
1794bcb5c89dSSowmini Varadhan 
1795bcb5c89dSSowmini Varadhan }
1796bcb5c89dSSowmini Varadhan 
1797bcb5c89dSSowmini Varadhan /*
1798bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_PHY_CONFIG
1799bcb5c89dSSowmini Varadhan  */
1800bcb5c89dSSowmini Varadhan 
1801bcb5c89dSSowmini Varadhan static int
wl_set_phy(struct ieee80211com * ic,const void * wldp_buf)1802bcb5c89dSSowmini Varadhan wl_set_phy(struct ieee80211com *ic, const void* wldp_buf)
1803bcb5c89dSSowmini Varadhan {
1804bcb5c89dSSowmini Varadhan 	int err = 0;
1805bcb5c89dSSowmini Varadhan 	int16_t ch;
1806bcb5c89dSSowmini Varadhan 	wl_dsss_t *dsss;
1807bcb5c89dSSowmini Varadhan 	wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)wldp_buf;
1808bcb5c89dSSowmini Varadhan 
1809bcb5c89dSSowmini Varadhan 	dsss = (wl_dsss_t *)iw_phy;
1810bcb5c89dSSowmini Varadhan 	ch = dsss->wl_dsss_channel;
1811bcb5c89dSSowmini Varadhan 
1812bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_phy: "
1813bcb5c89dSSowmini Varadhan 	    "set channel=%d\n", ch);
1814bcb5c89dSSowmini Varadhan 
1815bcb5c89dSSowmini Varadhan 	if (ch == 0 || ch == (int16_t)IEEE80211_CHAN_ANY) {
1816bcb5c89dSSowmini Varadhan 		ic->ic_des_chan = IEEE80211_CHAN_ANYC;
1817bcb5c89dSSowmini Varadhan 	} else if ((uint_t)ch > IEEE80211_CHAN_MAX ||
1818bcb5c89dSSowmini Varadhan 	    ieee80211_isclr(ic->ic_chan_active, ch)) {
1819bcb5c89dSSowmini Varadhan 		err = EINVAL;
1820bcb5c89dSSowmini Varadhan 		return (err);
1821bcb5c89dSSowmini Varadhan 	} else {
1822bcb5c89dSSowmini Varadhan 		ic->ic_des_chan = ic->ic_ibss_chan =
1823bcb5c89dSSowmini Varadhan 		    &ic->ic_sup_channels[ch];
1824bcb5c89dSSowmini Varadhan 	}
1825bcb5c89dSSowmini Varadhan 
1826bcb5c89dSSowmini Varadhan 	switch (ic->ic_state) {
1827bcb5c89dSSowmini Varadhan 	case IEEE80211_S_INIT:
1828bcb5c89dSSowmini Varadhan 	case IEEE80211_S_SCAN:
1829bcb5c89dSSowmini Varadhan 		err = ENETRESET;
1830bcb5c89dSSowmini Varadhan 		break;
1831bcb5c89dSSowmini Varadhan 	default:
1832bcb5c89dSSowmini Varadhan 		/*
1833bcb5c89dSSowmini Varadhan 		 * If hte desired channel has changed (to something
1834bcb5c89dSSowmini Varadhan 		 * other than any) and we're not already scanning,
1835bcb5c89dSSowmini Varadhan 		 * then kick the state machine.
1836bcb5c89dSSowmini Varadhan 		 */
1837bcb5c89dSSowmini Varadhan 		if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
1838bcb5c89dSSowmini Varadhan 		    ic->ic_bss->in_chan != ic->ic_des_chan &&
1839bcb5c89dSSowmini Varadhan 		    (ic->ic_flags & IEEE80211_F_SCAN) == 0)
1840bcb5c89dSSowmini Varadhan 			err = ENETRESET;
1841bcb5c89dSSowmini Varadhan 		break;
1842bcb5c89dSSowmini Varadhan 	}
1843bcb5c89dSSowmini Varadhan 
1844bcb5c89dSSowmini Varadhan 	return (err);
1845bcb5c89dSSowmini Varadhan }
1846bcb5c89dSSowmini Varadhan 
1847e2cf88acSQuaker Fang #define	WIFI_HT_MODE(in)	(((in)->in_flags & IEEE80211_NODE_HT) ? 1 : 0)
1848e2cf88acSQuaker Fang 
1849bcb5c89dSSowmini Varadhan static int
wl_get_phy(struct ieee80211com * ic,void * wldp_buf)1850bcb5c89dSSowmini Varadhan wl_get_phy(struct ieee80211com *ic, void *wldp_buf)
1851bcb5c89dSSowmini Varadhan {
1852bcb5c89dSSowmini Varadhan 	int err = 0;
1853bcb5c89dSSowmini Varadhan 	wl_phy_conf_t *ow_phy;
1854bcb5c89dSSowmini Varadhan 	struct ieee80211_channel *ch = ic->ic_curchan;
1855e2cf88acSQuaker Fang 	struct ieee80211_node *in = ic->ic_bss;
1856bcb5c89dSSowmini Varadhan 
1857bcb5c89dSSowmini Varadhan 	ow_phy = (wl_phy_conf_t *)wldp_buf;
1858bcb5c89dSSowmini Varadhan 	bzero(wldp_buf, sizeof (wl_phy_conf_t));
1859bcb5c89dSSowmini Varadhan 
1860bcb5c89dSSowmini Varadhan 	/* get current phy parameters: FH|DS|ERP */
1861bcb5c89dSSowmini Varadhan 	if (IEEE80211_IS_CHAN_A(ch) || IEEE80211_IS_CHAN_T(ch)) {
1862bcb5c89dSSowmini Varadhan 		wl_ofdm_t *ofdm = (wl_ofdm_t *)ow_phy;
1863bcb5c89dSSowmini Varadhan 		ofdm->wl_ofdm_subtype = WL_OFDM;
1864bcb5c89dSSowmini Varadhan 		ofdm->wl_ofdm_frequency = ch->ich_freq;
1865e2cf88acSQuaker Fang 		ofdm->wl_ofdm_ht_enabled = WIFI_HT_MODE(in);
1866bcb5c89dSSowmini Varadhan 	} else {
1867bcb5c89dSSowmini Varadhan 		switch (ic->ic_phytype) {
1868bcb5c89dSSowmini Varadhan 		case IEEE80211_T_FH: {
1869bcb5c89dSSowmini Varadhan 			wl_fhss_t *fhss = (wl_fhss_t *)ow_phy;
1870bcb5c89dSSowmini Varadhan 			fhss->wl_fhss_subtype = WL_FHSS;
1871bcb5c89dSSowmini Varadhan 			fhss->wl_fhss_channel =
1872bcb5c89dSSowmini Varadhan 			    ieee80211_chan2ieee(ic, ch);
1873bcb5c89dSSowmini Varadhan 			break;
1874bcb5c89dSSowmini Varadhan 		}
1875bcb5c89dSSowmini Varadhan 		case IEEE80211_T_DS: {
1876bcb5c89dSSowmini Varadhan 			wl_dsss_t *dsss = (wl_dsss_t *)ow_phy;
1877bcb5c89dSSowmini Varadhan 			dsss->wl_dsss_subtype = WL_DSSS;
1878bcb5c89dSSowmini Varadhan 			dsss->wl_dsss_channel =
1879bcb5c89dSSowmini Varadhan 			    ieee80211_chan2ieee(ic, ch);
1880bcb5c89dSSowmini Varadhan 			break;
1881bcb5c89dSSowmini Varadhan 		}
1882bcb5c89dSSowmini Varadhan 		case IEEE80211_T_OFDM: {
1883bcb5c89dSSowmini Varadhan 			wl_erp_t *erp = (wl_erp_t *)ow_phy;
1884bcb5c89dSSowmini Varadhan 			erp->wl_erp_subtype = WL_ERP;
1885bcb5c89dSSowmini Varadhan 			erp->wl_erp_channel =
1886bcb5c89dSSowmini Varadhan 			    ieee80211_chan2ieee(ic, ch);
1887e2cf88acSQuaker Fang 			erp->wl_erp_ht_enabled = WIFI_HT_MODE(in);
1888bcb5c89dSSowmini Varadhan 			break;
1889bcb5c89dSSowmini Varadhan 		}
1890bcb5c89dSSowmini Varadhan 		default:
1891bcb5c89dSSowmini Varadhan 			ieee80211_err("wl_get_phy: "
1892bcb5c89dSSowmini Varadhan 			    "unknown phy type, %x\n", ic->ic_phytype);
1893bcb5c89dSSowmini Varadhan 			err = EIO;
1894bcb5c89dSSowmini Varadhan 			break;
1895bcb5c89dSSowmini Varadhan 		}
1896bcb5c89dSSowmini Varadhan 	}
1897bcb5c89dSSowmini Varadhan 
1898bcb5c89dSSowmini Varadhan 	return (err);
1899bcb5c89dSSowmini Varadhan }
1900bcb5c89dSSowmini Varadhan 
1901bcb5c89dSSowmini Varadhan /*
1902bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_CAPABILITY
1903bcb5c89dSSowmini Varadhan  */
1904bcb5c89dSSowmini Varadhan static void
wl_get_capability(struct ieee80211com * ic,void * wldp_buf)1905bcb5c89dSSowmini Varadhan wl_get_capability(struct ieee80211com *ic, void *wldp_buf)
1906bcb5c89dSSowmini Varadhan {
1907bcb5c89dSSowmini Varadhan 	wl_capability_t ow_caps;
1908bcb5c89dSSowmini Varadhan 
1909bcb5c89dSSowmini Varadhan 	ow_caps.caps = ic->ic_caps;
1910bcb5c89dSSowmini Varadhan 	bcopy(&ow_caps, wldp_buf, sizeof (wl_capability_t));
1911bcb5c89dSSowmini Varadhan 
1912bcb5c89dSSowmini Varadhan }
1913bcb5c89dSSowmini Varadhan 
1914bcb5c89dSSowmini Varadhan /*
1915bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_WPA
1916bcb5c89dSSowmini Varadhan  */
1917bcb5c89dSSowmini Varadhan static int
wl_set_wpa(struct ieee80211com * ic,const void * wldp_buf)1918bcb5c89dSSowmini Varadhan wl_set_wpa(struct ieee80211com *ic, const void *wldp_buf)
1919bcb5c89dSSowmini Varadhan {
1920bcb5c89dSSowmini Varadhan 	int err = 0;
1921bcb5c89dSSowmini Varadhan 	wl_wpa_t *wpa = (wl_wpa_t *)wldp_buf;
1922bcb5c89dSSowmini Varadhan 
1923bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpa: "
1924bcb5c89dSSowmini Varadhan 	    "set wpa=%u\n", wpa->wpa_flag);
1925bcb5c89dSSowmini Varadhan 
1926bcb5c89dSSowmini Varadhan 	if (wpa->wpa_flag > 0) {
1927bcb5c89dSSowmini Varadhan 		/* enable wpa mode */
1928bcb5c89dSSowmini Varadhan 		ic->ic_flags |= IEEE80211_F_PRIVACY;
1929bcb5c89dSSowmini Varadhan 		ic->ic_flags |= IEEE80211_F_WPA;
1930bcb5c89dSSowmini Varadhan 	} else {
1931bcb5c89dSSowmini Varadhan 		ic->ic_flags &= ~IEEE80211_F_PRIVACY;
1932bcb5c89dSSowmini Varadhan 		ic->ic_flags &= ~IEEE80211_F_WPA;
1933bcb5c89dSSowmini Varadhan 	}
1934bcb5c89dSSowmini Varadhan 
1935bcb5c89dSSowmini Varadhan 	return (err);
1936bcb5c89dSSowmini Varadhan }
1937bcb5c89dSSowmini Varadhan 
1938bcb5c89dSSowmini Varadhan static void
wl_get_wpa(struct ieee80211com * ic,void * wldp_buf)1939bcb5c89dSSowmini Varadhan wl_get_wpa(struct ieee80211com *ic, void *wldp_buf)
1940bcb5c89dSSowmini Varadhan {
1941bcb5c89dSSowmini Varadhan 	wl_wpa_t *wpa;
1942bcb5c89dSSowmini Varadhan 
1943bcb5c89dSSowmini Varadhan 	wpa = (wl_wpa_t *)wldp_buf;
1944bcb5c89dSSowmini Varadhan 	wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA) ? 1 : 0);
1945bcb5c89dSSowmini Varadhan 
1946bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_get_wpa: "
1947bcb5c89dSSowmini Varadhan 	    "get wpa=%u\n", wpa->wpa_flag);
1948bcb5c89dSSowmini Varadhan 
1949bcb5c89dSSowmini Varadhan }
1950bcb5c89dSSowmini Varadhan 
1951bcb5c89dSSowmini Varadhan /*
1952bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_SCANRESULTS
1953bcb5c89dSSowmini Varadhan  */
1954bcb5c89dSSowmini Varadhan 
1955bcb5c89dSSowmini Varadhan static void
wl_get_scanresults(struct ieee80211com * ic,void * wldp_buf)1956bcb5c89dSSowmini Varadhan wl_get_scanresults(struct ieee80211com *ic, void *wldp_buf)
1957bcb5c89dSSowmini Varadhan {
1958bcb5c89dSSowmini Varadhan 	wl_wpa_ess_t *sr;
1959bcb5c89dSSowmini Varadhan 	ieee80211_node_t *in;
1960bcb5c89dSSowmini Varadhan 	ieee80211_node_table_t *nt;
1961bcb5c89dSSowmini Varadhan 	int ap_num;
1962bcb5c89dSSowmini Varadhan 	int len;
1963bcb5c89dSSowmini Varadhan 
1964bcb5c89dSSowmini Varadhan 	sr = (wl_wpa_ess_t *)wldp_buf;
1965bcb5c89dSSowmini Varadhan 	sr->count = 0;
1966bcb5c89dSSowmini Varadhan 	ap_num = 0;
1967bcb5c89dSSowmini Varadhan 
1968bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_WPA, "wl_get_scanrelults\n");
1969bcb5c89dSSowmini Varadhan 
1970bcb5c89dSSowmini Varadhan 	nt = &ic->ic_scan;
1971bcb5c89dSSowmini Varadhan 	IEEE80211_NODE_LOCK(nt);
1972bcb5c89dSSowmini Varadhan 	in = list_head(&nt->nt_node);
1973bcb5c89dSSowmini Varadhan 
1974bcb5c89dSSowmini Varadhan 	while (in != NULL) {
1975bcb5c89dSSowmini Varadhan 		/* filter out non-wpa APs */
1976bcb5c89dSSowmini Varadhan 		if (in->in_wpa_ie == NULL) {
1977bcb5c89dSSowmini Varadhan 			in = list_next(&nt->nt_node, in);
1978bcb5c89dSSowmini Varadhan 			continue;
1979bcb5c89dSSowmini Varadhan 		}
1980bcb5c89dSSowmini Varadhan 		bcopy(in->in_bssid, sr->ess[ap_num].bssid,
1981bcb5c89dSSowmini Varadhan 		    IEEE80211_ADDR_LEN);
1982bcb5c89dSSowmini Varadhan 		sr->ess[ap_num].ssid_len = in->in_esslen;
1983bcb5c89dSSowmini Varadhan 		bcopy(in->in_essid, sr->ess[ap_num].ssid,
1984bcb5c89dSSowmini Varadhan 		    in->in_esslen);
1985bcb5c89dSSowmini Varadhan 		sr->ess[ap_num].freq = in->in_chan->ich_freq;
1986bcb5c89dSSowmini Varadhan 
1987bcb5c89dSSowmini Varadhan 		len = in->in_wpa_ie[1] + 2;
1988bcb5c89dSSowmini Varadhan 		bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len);
1989bcb5c89dSSowmini Varadhan 		sr->ess[ap_num].wpa_ie_len = len;
1990bcb5c89dSSowmini Varadhan 
1991bcb5c89dSSowmini Varadhan 		ap_num++;
1992bcb5c89dSSowmini Varadhan 		in = list_next(&nt->nt_node, in);
1993bcb5c89dSSowmini Varadhan 	}
1994bcb5c89dSSowmini Varadhan 	IEEE80211_NODE_UNLOCK(nt);
1995bcb5c89dSSowmini Varadhan 	sr->count = ap_num;
1996bcb5c89dSSowmini Varadhan 
1997bcb5c89dSSowmini Varadhan }
1998bcb5c89dSSowmini Varadhan 
1999bcb5c89dSSowmini Varadhan /*
2000bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_ESS_LIST
2001bcb5c89dSSowmini Varadhan  */
2002bcb5c89dSSowmini Varadhan static void
wl_get_esslist(struct ieee80211com * ic,void * wldp_buf)2003bcb5c89dSSowmini Varadhan wl_get_esslist(struct ieee80211com *ic, void *wldp_buf)
2004bcb5c89dSSowmini Varadhan {
2005bcb5c89dSSowmini Varadhan 	wl_ess_list_t *ess_list;
2006bcb5c89dSSowmini Varadhan 
2007bcb5c89dSSowmini Varadhan 	ess_list = (wl_ess_list_t *)wldp_buf;
2008bcb5c89dSSowmini Varadhan 
2009bcb5c89dSSowmini Varadhan 	ess_list->wl_ess_list_num = 0;
2010bcb5c89dSSowmini Varadhan 	ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ess_list);
2011bcb5c89dSSowmini Varadhan 
2012bcb5c89dSSowmini Varadhan }
2013bcb5c89dSSowmini Varadhan 
2014bcb5c89dSSowmini Varadhan /*
2015bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_WEP_KEY
2016bcb5c89dSSowmini Varadhan  */
2017bcb5c89dSSowmini Varadhan static int
wl_set_wepkey(struct ieee80211com * ic,const void * wldp_buf)2018bcb5c89dSSowmini Varadhan wl_set_wepkey(struct ieee80211com *ic, const void *wldp_buf)
2019bcb5c89dSSowmini Varadhan {
2020bcb5c89dSSowmini Varadhan 	int	 err = 0;
2021bcb5c89dSSowmini Varadhan 	uint16_t i;
2022bcb5c89dSSowmini Varadhan 	uint32_t klen;
2023bcb5c89dSSowmini Varadhan 	struct ieee80211_key *key;
2024bcb5c89dSSowmini Varadhan 	wl_wep_key_t *wepkey = (wl_wep_key_t *)wldp_buf;
2025bcb5c89dSSowmini Varadhan 
2026bcb5c89dSSowmini Varadhan 	/* set all valid keys */
2027bcb5c89dSSowmini Varadhan 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2028bcb5c89dSSowmini Varadhan 		if (wepkey[i].wl_wep_operation != WL_ADD)
2029bcb5c89dSSowmini Varadhan 			continue;
2030bcb5c89dSSowmini Varadhan 		klen = wepkey[i].wl_wep_length;
2031bcb5c89dSSowmini Varadhan 		if (klen > IEEE80211_KEYBUF_SIZE) {
2032bcb5c89dSSowmini Varadhan 			ieee80211_err("wl_set_wepkey: "
2033bcb5c89dSSowmini Varadhan 			    "invalid wepkey length, %u\n", klen);
2034bcb5c89dSSowmini Varadhan 			err = EINVAL;
2035bcb5c89dSSowmini Varadhan 			continue;  /* continue to set other keys */
2036bcb5c89dSSowmini Varadhan 		}
2037bcb5c89dSSowmini Varadhan 		if (klen == 0)
2038bcb5c89dSSowmini Varadhan 			continue;
2039bcb5c89dSSowmini Varadhan 
2040bcb5c89dSSowmini Varadhan 		/*
2041bcb5c89dSSowmini Varadhan 		 *  Set key contents. Only WEP is supported
2042bcb5c89dSSowmini Varadhan 		 */
2043bcb5c89dSSowmini Varadhan 		ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_wepkey: "
2044bcb5c89dSSowmini Varadhan 		    "set key %u, len=%u\n", i, klen);
2045bcb5c89dSSowmini Varadhan 		key = &ic->ic_nw_keys[i];
2046bcb5c89dSSowmini Varadhan 		if (ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_WEP,
2047bcb5c89dSSowmini Varadhan 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key) == 0) {
2048bcb5c89dSSowmini Varadhan 			ieee80211_err("wl_set_wepkey: "
2049bcb5c89dSSowmini Varadhan 			    "abort, create key failed. id=%u\n", i);
2050bcb5c89dSSowmini Varadhan 			err = EIO;
2051bcb5c89dSSowmini Varadhan 			continue;
2052bcb5c89dSSowmini Varadhan 		}
2053bcb5c89dSSowmini Varadhan 
2054bcb5c89dSSowmini Varadhan 		key->wk_keyix = i;
2055bcb5c89dSSowmini Varadhan 		key->wk_keylen = (uint8_t)klen;
2056bcb5c89dSSowmini Varadhan 		key->wk_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
2057bcb5c89dSSowmini Varadhan 		bzero(key->wk_key, IEEE80211_KEYBUF_SIZE);
2058bcb5c89dSSowmini Varadhan 		bcopy(wepkey[i].wl_wep_key, key->wk_key, klen);
2059bcb5c89dSSowmini Varadhan 		if (ieee80211_crypto_setkey(ic, key, ic->ic_macaddr)
2060bcb5c89dSSowmini Varadhan 		    == 0) {
2061bcb5c89dSSowmini Varadhan 			ieee80211_err("wl_set_wepkey: "
2062bcb5c89dSSowmini Varadhan 			    "set key failed len=%u\n", klen);
2063bcb5c89dSSowmini Varadhan 			err = EIO;
2064bcb5c89dSSowmini Varadhan 		}
2065bcb5c89dSSowmini Varadhan 	}
2066bcb5c89dSSowmini Varadhan 	if (err == 0)
2067bcb5c89dSSowmini Varadhan 		err = ENETRESET;
2068bcb5c89dSSowmini Varadhan 
2069bcb5c89dSSowmini Varadhan 	return (err);
2070bcb5c89dSSowmini Varadhan }
2071bcb5c89dSSowmini Varadhan 
2072bcb5c89dSSowmini Varadhan /*
2073bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_SETOPTIE
2074bcb5c89dSSowmini Varadhan  */
2075bcb5c89dSSowmini Varadhan static int
wl_set_optie(struct ieee80211com * ic,const void * wldp_buf)2076bcb5c89dSSowmini Varadhan wl_set_optie(struct ieee80211com *ic, const void *wldp_buf)
2077bcb5c89dSSowmini Varadhan {
2078bcb5c89dSSowmini Varadhan 	int err = 0;
2079bcb5c89dSSowmini Varadhan 	char *ie;
2080bcb5c89dSSowmini Varadhan 	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)wldp_buf;
2081bcb5c89dSSowmini Varadhan 
2082bcb5c89dSSowmini Varadhan 	if (ic->ic_opmode != IEEE80211_M_STA) {
2083bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_optie: opmode err\n");
2084bcb5c89dSSowmini Varadhan 		err = EINVAL;
2085bcb5c89dSSowmini Varadhan 		return (err);
2086bcb5c89dSSowmini Varadhan 	}
2087bcb5c89dSSowmini Varadhan 	if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) {
2088bcb5c89dSSowmini Varadhan 
2089bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_optie: optie is too long\n");
2090bcb5c89dSSowmini Varadhan 
2091bcb5c89dSSowmini Varadhan 		err = EINVAL;
2092bcb5c89dSSowmini Varadhan 		return (err);
2093bcb5c89dSSowmini Varadhan 	}
2094bcb5c89dSSowmini Varadhan 
2095bcb5c89dSSowmini Varadhan 	ie = ieee80211_malloc(ie_in->wpa_ie_len);
2096bcb5c89dSSowmini Varadhan 	(void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len);
2097bcb5c89dSSowmini Varadhan 	if (ic->ic_opt_ie != NULL) {
2098bcb5c89dSSowmini Varadhan 		ieee80211_dbg(IEEE80211_MSG_BRUSSELS,
2099bcb5c89dSSowmini Varadhan 		    "wl_set_optie:ic_opt_ie!=NULL\n");
2100bcb5c89dSSowmini Varadhan 		ieee80211_free(ic->ic_opt_ie);
2101bcb5c89dSSowmini Varadhan 	}
2102bcb5c89dSSowmini Varadhan 	ic->ic_opt_ie = ie;
2103bcb5c89dSSowmini Varadhan 	ic->ic_opt_ie_len = ie_in->wpa_ie_len;
2104bcb5c89dSSowmini Varadhan 
2105bcb5c89dSSowmini Varadhan 	return (err);
2106bcb5c89dSSowmini Varadhan }
2107bcb5c89dSSowmini Varadhan 
2108bcb5c89dSSowmini Varadhan /*
2109bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_DELKEY
2110bcb5c89dSSowmini Varadhan  */
2111bcb5c89dSSowmini Varadhan static int
wl_set_delkey(struct ieee80211com * ic,const void * wldp_buf)2112bcb5c89dSSowmini Varadhan wl_set_delkey(struct ieee80211com *ic, const void *wldp_buf)
2113bcb5c89dSSowmini Varadhan {
2114bcb5c89dSSowmini Varadhan 	int err = 0;
2115bcb5c89dSSowmini Varadhan 	int kid;
2116bcb5c89dSSowmini Varadhan 	wl_del_key_t *dk = (wl_del_key_t *)wldp_buf;
2117bcb5c89dSSowmini Varadhan 
2118bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_delkey(): "
2119bcb5c89dSSowmini Varadhan 	    "keyix=%d\n", dk->idk_keyix);
2120bcb5c89dSSowmini Varadhan 
2121bcb5c89dSSowmini Varadhan 	kid = dk->idk_keyix;
2122bcb5c89dSSowmini Varadhan 
2123bcb5c89dSSowmini Varadhan 	if (kid == IEEE80211_KEYIX_NONE ||
2124bcb5c89dSSowmini Varadhan 	    kid >= IEEE80211_WEP_NKID) {
2125bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_delkey: incorrect keyix\n");
2126bcb5c89dSSowmini Varadhan 		err = EINVAL;
2127bcb5c89dSSowmini Varadhan 		return (err);
2128bcb5c89dSSowmini Varadhan 	} else {
2129bcb5c89dSSowmini Varadhan 		(void) ieee80211_crypto_delkey(ic,
2130bcb5c89dSSowmini Varadhan 		    &ic->ic_nw_keys[kid]);
2131bcb5c89dSSowmini Varadhan 		ieee80211_mac_update(ic);
2132bcb5c89dSSowmini Varadhan 	}
2133bcb5c89dSSowmini Varadhan 
2134bcb5c89dSSowmini Varadhan 	return (err);
2135bcb5c89dSSowmini Varadhan }
2136bcb5c89dSSowmini Varadhan 
2137bcb5c89dSSowmini Varadhan /*
2138bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_MLME
2139bcb5c89dSSowmini Varadhan  */
2140bcb5c89dSSowmini Varadhan 
2141bcb5c89dSSowmini Varadhan static int
wl_set_mlme(struct ieee80211com * ic,const void * wldp_buf)2142bcb5c89dSSowmini Varadhan wl_set_mlme(struct ieee80211com *ic, const void *wldp_buf)
2143bcb5c89dSSowmini Varadhan {
2144bcb5c89dSSowmini Varadhan 	int err = 0;
2145bcb5c89dSSowmini Varadhan 	uint32_t flags;
2146bcb5c89dSSowmini Varadhan 	ieee80211_node_t *in;
2147bcb5c89dSSowmini Varadhan 	wl_mlme_t *mlme = (wl_mlme_t *)wldp_buf;
2148bcb5c89dSSowmini Varadhan 
2149bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_WPA, "wl_set_mlme: "
2150bcb5c89dSSowmini Varadhan 	    "op=%d\n", mlme->im_op);
2151bcb5c89dSSowmini Varadhan 
2152bcb5c89dSSowmini Varadhan 	switch (mlme->im_op) {
2153bcb5c89dSSowmini Varadhan 	case IEEE80211_MLME_DISASSOC:
2154bcb5c89dSSowmini Varadhan 	case IEEE80211_MLME_DEAUTH:
2155bcb5c89dSSowmini Varadhan 		if (ic->ic_opmode == IEEE80211_M_STA) {
2156bcb5c89dSSowmini Varadhan 			/*
2157bcb5c89dSSowmini Varadhan 			 * Mask ic_flags of IEEE80211_F_WPA to disable
2158bcb5c89dSSowmini Varadhan 			 * ieee80211_notify temporarily.
2159bcb5c89dSSowmini Varadhan 			 */
2160bcb5c89dSSowmini Varadhan 			flags = ic->ic_flags;
2161bcb5c89dSSowmini Varadhan 			ic->ic_flags &= ~IEEE80211_F_WPA;
2162bcb5c89dSSowmini Varadhan 
2163bcb5c89dSSowmini Varadhan 			IEEE80211_UNLOCK(ic);
2164bcb5c89dSSowmini Varadhan 			ieee80211_new_state(ic, IEEE80211_S_INIT,
2165bcb5c89dSSowmini Varadhan 			    mlme->im_reason);
2166bcb5c89dSSowmini Varadhan 			IEEE80211_LOCK(ic);
2167bcb5c89dSSowmini Varadhan 
2168bcb5c89dSSowmini Varadhan 			ic->ic_flags = flags;
2169bcb5c89dSSowmini Varadhan 		}
2170bcb5c89dSSowmini Varadhan 		break;
2171bcb5c89dSSowmini Varadhan 	case IEEE80211_MLME_ASSOC:
2172bcb5c89dSSowmini Varadhan 		if (ic->ic_opmode != IEEE80211_M_STA) {
2173bcb5c89dSSowmini Varadhan 			ieee80211_err("wifi_cfg_setmlme: opmode err\n");
2174bcb5c89dSSowmini Varadhan 			err = EINVAL;
2175bcb5c89dSSowmini Varadhan 			break;
2176bcb5c89dSSowmini Varadhan 		}
2177bcb5c89dSSowmini Varadhan 		if (ic->ic_des_esslen != 0) {
2178bcb5c89dSSowmini Varadhan 		/*
2179bcb5c89dSSowmini Varadhan 		 * Desired ssid specified; must match both bssid and
2180bcb5c89dSSowmini Varadhan 		 * ssid to distinguish ap advertising multiple ssid's.
2181bcb5c89dSSowmini Varadhan 		 */
2182bcb5c89dSSowmini Varadhan 			in = ieee80211_find_node_with_ssid(&ic->ic_scan,
2183bcb5c89dSSowmini Varadhan 			    mlme->im_macaddr,
2184bcb5c89dSSowmini Varadhan 			    ic->ic_des_esslen,
2185bcb5c89dSSowmini Varadhan 			    ic->ic_des_essid);
2186bcb5c89dSSowmini Varadhan 		} else {
2187bcb5c89dSSowmini Varadhan 		/*
2188bcb5c89dSSowmini Varadhan 		 * Normal case; just match bssid.
2189bcb5c89dSSowmini Varadhan 		 */
2190bcb5c89dSSowmini Varadhan 			in = ieee80211_find_node(&ic->ic_scan,
2191bcb5c89dSSowmini Varadhan 			    mlme->im_macaddr);
2192bcb5c89dSSowmini Varadhan 		}
2193bcb5c89dSSowmini Varadhan 		if (in == NULL) {
2194bcb5c89dSSowmini Varadhan 			ieee80211_err("wifi_cfg_setmlme: "
2195bcb5c89dSSowmini Varadhan 			    "no matched node\n");
2196bcb5c89dSSowmini Varadhan 			err = EINVAL;
2197bcb5c89dSSowmini Varadhan 			break;
2198bcb5c89dSSowmini Varadhan 		}
2199bcb5c89dSSowmini Varadhan 		IEEE80211_UNLOCK(ic);
2200bcb5c89dSSowmini Varadhan 		ieee80211_sta_join(ic, in);
2201bcb5c89dSSowmini Varadhan 		IEEE80211_LOCK(ic);
2202bcb5c89dSSowmini Varadhan 		break;
2203bcb5c89dSSowmini Varadhan 	default:
2204bcb5c89dSSowmini Varadhan 		err = EINVAL;
2205bcb5c89dSSowmini Varadhan 		break;
2206bcb5c89dSSowmini Varadhan 	}
2207bcb5c89dSSowmini Varadhan 
2208bcb5c89dSSowmini Varadhan 	return (err);
2209bcb5c89dSSowmini Varadhan }
2210bcb5c89dSSowmini Varadhan 
2211bcb5c89dSSowmini Varadhan /*
2212bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_WPA_KEY
2213bcb5c89dSSowmini Varadhan  */
2214bcb5c89dSSowmini Varadhan static int
wl_set_wpakey(struct ieee80211com * ic,const void * wldp_buf)2215bcb5c89dSSowmini Varadhan wl_set_wpakey(struct ieee80211com *ic, const void *wldp_buf)
2216bcb5c89dSSowmini Varadhan {
2217bcb5c89dSSowmini Varadhan 	int err = 0;
2218bcb5c89dSSowmini Varadhan 	uint16_t kid;
2219bcb5c89dSSowmini Varadhan 	struct ieee80211_node *in;
2220bcb5c89dSSowmini Varadhan 	struct ieee80211_key *wk;
2221b510adaeSfei feng - Sun Microsystems - Beijing China 	wl_key_t ik;
2222b510adaeSfei feng - Sun Microsystems - Beijing China 
2223b510adaeSfei feng - Sun Microsystems - Beijing China 	bcopy(wldp_buf, &ik, sizeof (wl_key_t));
2224bcb5c89dSSowmini Varadhan 
2225bcb5c89dSSowmini Varadhan 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpakey: "
2226b510adaeSfei feng - Sun Microsystems - Beijing China 	    "idx=%d\n", ik.ik_keyix);
2227bcb5c89dSSowmini Varadhan 
2228bcb5c89dSSowmini Varadhan 	/*
2229bcb5c89dSSowmini Varadhan 	 * cipher support is verified by ieee80211_crypt_newkey
2230b510adaeSfei feng - Sun Microsystems - Beijing China 	 * this also checks ik.ik_keylen > sizeof(wk->wk_key)
2231bcb5c89dSSowmini Varadhan 	 */
2232b510adaeSfei feng - Sun Microsystems - Beijing China 	if (ik.ik_keylen > sizeof (ik.ik_keydata)) {
2233bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_wpakey: key is too long\n");
2234bcb5c89dSSowmini Varadhan 		err = EINVAL;
2235bcb5c89dSSowmini Varadhan 		return (err);
2236bcb5c89dSSowmini Varadhan 	}
2237b510adaeSfei feng - Sun Microsystems - Beijing China 	kid = ik.ik_keyix;
2238bcb5c89dSSowmini Varadhan 	if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) {
2239bcb5c89dSSowmini Varadhan 		ieee80211_err("wl_set_wpakey: incorrect keyix\n");
2240bcb5c89dSSowmini Varadhan 		err = EINVAL;
2241bcb5c89dSSowmini Varadhan 		return (err);
2242bcb5c89dSSowmini Varadhan 	} else {
2243bcb5c89dSSowmini Varadhan 		wk = &ic->ic_nw_keys[kid];
2244bcb5c89dSSowmini Varadhan 		/*
2245bcb5c89dSSowmini Varadhan 		 * Globle slots start off w/o any assigned key index.
2246bcb5c89dSSowmini Varadhan 		 * Force one here for consistency with WEPKEY.
2247bcb5c89dSSowmini Varadhan 		 */
2248bcb5c89dSSowmini Varadhan 		if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
2249bcb5c89dSSowmini Varadhan 			wk->wk_keyix = kid;
2250bcb5c89dSSowmini Varadhan 		in = NULL;
2251bcb5c89dSSowmini Varadhan 	}
2252bcb5c89dSSowmini Varadhan 
2253bcb5c89dSSowmini Varadhan 	KEY_UPDATE_BEGIN(ic);
2254b510adaeSfei feng - Sun Microsystems - Beijing China 	if (ieee80211_crypto_newkey(ic, ik.ik_type,
2255b510adaeSfei feng - Sun Microsystems - Beijing China 	    ik.ik_flags, wk)) {
2256b510adaeSfei feng - Sun Microsystems - Beijing China 		wk->wk_keylen = ik.ik_keylen;
2257bcb5c89dSSowmini Varadhan 		/* MIC presence is implied by cipher type */
2258bcb5c89dSSowmini Varadhan 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
2259bcb5c89dSSowmini Varadhan 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
2260b510adaeSfei feng - Sun Microsystems - Beijing China 		wk->wk_keyrsc = ik.ik_keyrsc;
2261bcb5c89dSSowmini Varadhan 		wk->wk_keytsc = 0;
2262b510adaeSfei feng - Sun Microsystems - Beijing China 		wk->wk_flags |= ik.ik_flags &
2263bcb5c89dSSowmini Varadhan 		    (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
2264bcb5c89dSSowmini Varadhan 		(void) memset(wk->wk_key, 0, sizeof (wk->wk_key));
2265b510adaeSfei feng - Sun Microsystems - Beijing China 		(void) memcpy(wk->wk_key, ik.ik_keydata,
2266b510adaeSfei feng - Sun Microsystems - Beijing China 		    ik.ik_keylen);
2267bcb5c89dSSowmini Varadhan 		if (!ieee80211_crypto_setkey(ic, wk,
2268b510adaeSfei feng - Sun Microsystems - Beijing China 		    in != NULL ? in->in_macaddr : ik.ik_macaddr)) {
2269bcb5c89dSSowmini Varadhan 			err = EIO;
2270b510adaeSfei feng - Sun Microsystems - Beijing China 		} else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT)) {
2271bcb5c89dSSowmini Varadhan 			ic->ic_def_txkey = kid;
2272bcb5c89dSSowmini Varadhan 			ieee80211_mac_update(ic);
2273bcb5c89dSSowmini Varadhan 		}
2274bcb5c89dSSowmini Varadhan 	} else {
2275bcb5c89dSSowmini Varadhan 		err = EIO;
2276bcb5c89dSSowmini Varadhan 	}
2277bcb5c89dSSowmini Varadhan 	KEY_UPDATE_END(ic);
2278bcb5c89dSSowmini Varadhan 
2279bcb5c89dSSowmini Varadhan 	return (err);
2280bcb5c89dSSowmini Varadhan }
2281bcb5c89dSSowmini Varadhan 
2282bcb5c89dSSowmini Varadhan /*
2283bcb5c89dSSowmini Varadhan  * MAC_PROP_WL_SUP_RATE
2284bcb5c89dSSowmini Varadhan  */
2285bcb5c89dSSowmini Varadhan static void
wl_get_suprates(struct ieee80211com * ic,void * wldp_buf)2286bcb5c89dSSowmini Varadhan wl_get_suprates(struct ieee80211com *ic, void *wldp_buf)
2287bcb5c89dSSowmini Varadhan {
2288bcb5c89dSSowmini Varadhan 	int i, j, k, l;
2289bcb5c89dSSowmini Varadhan 	uint8_t srates;
2290bcb5c89dSSowmini Varadhan 	uint8_t *drates;
2291bcb5c89dSSowmini Varadhan 	wl_rates_t *wl_rates;
2292bcb5c89dSSowmini Varadhan 	const struct ieee80211_rateset *srs;
2293bcb5c89dSSowmini Varadhan 
2294bcb5c89dSSowmini Varadhan 	wl_rates = (wl_rates_t *)wldp_buf;
2295bcb5c89dSSowmini Varadhan 
2296bcb5c89dSSowmini Varadhan 	wl_rates->wl_rates_num = 0;
2297bcb5c89dSSowmini Varadhan 	drates = (uint8_t *)wl_rates->wl_rates_rates;
2298bcb5c89dSSowmini Varadhan 	for (i = 0; i < IEEE80211_MODE_MAX; i++) {
2299bcb5c89dSSowmini Varadhan 		srs = &ic->ic_sup_rates[i];
2300bcb5c89dSSowmini Varadhan 		if (srs->ir_nrates == 0)
2301bcb5c89dSSowmini Varadhan 			continue;
2302bcb5c89dSSowmini Varadhan 		for (j = 0; j < srs->ir_nrates; j++) {
2303bcb5c89dSSowmini Varadhan 			srates = IEEE80211_RV(srs->ir_rates[j]);
2304bcb5c89dSSowmini Varadhan 			/* sort & skip duplicated rates */
2305bcb5c89dSSowmini Varadhan 			for (k = 0; k < wl_rates->wl_rates_num; k++) {
2306bcb5c89dSSowmini Varadhan 				if (srates <= drates[k])
2307bcb5c89dSSowmini Varadhan 					break;
2308bcb5c89dSSowmini Varadhan 			}
2309bcb5c89dSSowmini Varadhan 			if (srates == drates[k])
2310bcb5c89dSSowmini Varadhan 				/* skip duplicated rates */
2311bcb5c89dSSowmini Varadhan 				continue;
2312bcb5c89dSSowmini Varadhan 			/* sort */
2313bcb5c89dSSowmini Varadhan 			for (l = wl_rates->wl_rates_num; l > k; l--)
2314bcb5c89dSSowmini Varadhan 				drates[l] = drates[l-1];
2315bcb5c89dSSowmini Varadhan 			drates[k] = srates;
2316bcb5c89dSSowmini Varadhan 			wl_rates->wl_rates_num++;
2317bcb5c89dSSowmini Varadhan 		}
2318bcb5c89dSSowmini Varadhan 	}
2319bcb5c89dSSowmini Varadhan 
2320bcb5c89dSSowmini Varadhan }
2321bcb5c89dSSowmini Varadhan 
2322127ac1c2Sfei feng - Sun Microsystems - Beijing China /*
2323127ac1c2Sfei feng - Sun Microsystems - Beijing China  * MAC_PROP_WL_CREATE_IBSS
2324127ac1c2Sfei feng - Sun Microsystems - Beijing China  */
2325127ac1c2Sfei feng - Sun Microsystems - Beijing China static int
wl_set_createibss(struct ieee80211com * ic,const void * wldp_buf)2326127ac1c2Sfei feng - Sun Microsystems - Beijing China wl_set_createibss(struct ieee80211com *ic, const void *wldp_buf)
2327127ac1c2Sfei feng - Sun Microsystems - Beijing China {
2328127ac1c2Sfei feng - Sun Microsystems - Beijing China 	wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)wldp_buf;
2329127ac1c2Sfei feng - Sun Microsystems - Beijing China 	int err = 0;
2330127ac1c2Sfei feng - Sun Microsystems - Beijing China 
2331127ac1c2Sfei feng - Sun Microsystems - Beijing China 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_ibss: "
2332127ac1c2Sfei feng - Sun Microsystems - Beijing China 	    "set createibss=%u\n", *iw_ibss);
2333127ac1c2Sfei feng - Sun Microsystems - Beijing China 
2334127ac1c2Sfei feng - Sun Microsystems - Beijing China 	if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) {
2335127ac1c2Sfei feng - Sun Microsystems - Beijing China 		err = ENOTSUP;
2336127ac1c2Sfei feng - Sun Microsystems - Beijing China 		return (err);
2337127ac1c2Sfei feng - Sun Microsystems - Beijing China 	}
2338127ac1c2Sfei feng - Sun Microsystems - Beijing China 	if (*iw_ibss) {
2339127ac1c2Sfei feng - Sun Microsystems - Beijing China 		if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
2340127ac1c2Sfei feng - Sun Microsystems - Beijing China 			ic->ic_flags |= IEEE80211_F_IBSSON;
2341127ac1c2Sfei feng - Sun Microsystems - Beijing China 			ic->ic_opmode = IEEE80211_M_IBSS;
2342127ac1c2Sfei feng - Sun Microsystems - Beijing China 			/*
2343127ac1c2Sfei feng - Sun Microsystems - Beijing China 			 * Yech, slot time may change depending on the
2344127ac1c2Sfei feng - Sun Microsystems - Beijing China 			 * operating mode so reset it to be sure
2345127ac1c2Sfei feng - Sun Microsystems - Beijing China 			 * everything is setup appropriately.
2346127ac1c2Sfei feng - Sun Microsystems - Beijing China 			 */
2347127ac1c2Sfei feng - Sun Microsystems - Beijing China 			ieee80211_reset_erp(ic);
2348127ac1c2Sfei feng - Sun Microsystems - Beijing China 			err = ENETRESET;
2349127ac1c2Sfei feng - Sun Microsystems - Beijing China 		}
2350127ac1c2Sfei feng - Sun Microsystems - Beijing China 	} else {
2351127ac1c2Sfei feng - Sun Microsystems - Beijing China 		if (ic->ic_flags & IEEE80211_F_IBSSON) {
2352127ac1c2Sfei feng - Sun Microsystems - Beijing China 			ic->ic_flags &= ~IEEE80211_F_IBSSON;
2353127ac1c2Sfei feng - Sun Microsystems - Beijing China 			err = ENETRESET;
2354127ac1c2Sfei feng - Sun Microsystems - Beijing China 		}
2355127ac1c2Sfei feng - Sun Microsystems - Beijing China 	}
2356127ac1c2Sfei feng - Sun Microsystems - Beijing China 
2357127ac1c2Sfei feng - Sun Microsystems - Beijing China 	return (err);
2358127ac1c2Sfei feng - Sun Microsystems - Beijing China }
2359127ac1c2Sfei feng - Sun Microsystems - Beijing China 
2360127ac1c2Sfei feng - Sun Microsystems - Beijing China static void
wl_get_createibss(struct ieee80211com * ic,void * wldp_buf)2361127ac1c2Sfei feng - Sun Microsystems - Beijing China wl_get_createibss(struct ieee80211com *ic, void *wldp_buf)
2362127ac1c2Sfei feng - Sun Microsystems - Beijing China {
2363127ac1c2Sfei feng - Sun Microsystems - Beijing China 	wl_create_ibss_t *ow_ibss = (wl_create_ibss_t *)wldp_buf;
2364127ac1c2Sfei feng - Sun Microsystems - Beijing China 
2365127ac1c2Sfei feng - Sun Microsystems - Beijing China 	*ow_ibss = (ic->ic_flags & IEEE80211_F_IBSSON)? 1 : 0;
2366127ac1c2Sfei feng - Sun Microsystems - Beijing China }
2367127ac1c2Sfei feng - Sun Microsystems - Beijing China 
2368bcb5c89dSSowmini Varadhan /*
2369bcb5c89dSSowmini Varadhan  * Typically invoked by drivers in response to request for
2370bcb5c89dSSowmini Varadhan  * information or to change settings from the userland.
2371bcb5c89dSSowmini Varadhan  *
2372bcb5c89dSSowmini Varadhan  * Return value should be checked by WiFI drivers. Return 0
2373bcb5c89dSSowmini Varadhan  * on success. Otherwise, return non-zero value to indicate
2374bcb5c89dSSowmini Varadhan  * the error. Driver should operate as below when the return
2375bcb5c89dSSowmini Varadhan  * error is:
2376bcb5c89dSSowmini Varadhan  * ENETRESET	Reset wireless network and re-start to join a
2377bcb5c89dSSowmini Varadhan  * 		WLAN, ENETRESET is returned when a configuration
2378bcb5c89dSSowmini Varadhan  * 		parameter has been changed.
2379bcb5c89dSSowmini Varadhan  * 		When acknowledge a M_IOCTL message, this error
2380bcb5c89dSSowmini Varadhan  * 		is ignored
2381bcb5c89dSSowmini Varadhan  */
2382bcb5c89dSSowmini Varadhan /* ARGSUSED */
2383bcb5c89dSSowmini Varadhan int
ieee80211_setprop(void * ic_arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)2384bcb5c89dSSowmini Varadhan ieee80211_setprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2385bcb5c89dSSowmini Varadhan     uint_t wldp_length, const void *wldp_buf)
2386bcb5c89dSSowmini Varadhan {
2387bcb5c89dSSowmini Varadhan 	int err = 0;
2388bcb5c89dSSowmini Varadhan 	struct ieee80211com *ic = ic_arg;
2389bcb5c89dSSowmini Varadhan 
2390bcb5c89dSSowmini Varadhan 	ASSERT(ic != NULL);
2391bcb5c89dSSowmini Varadhan 	IEEE80211_LOCK(ic);
2392bcb5c89dSSowmini Varadhan 
2393bcb5c89dSSowmini Varadhan 	switch (wldp_pr_num) {
2394bcb5c89dSSowmini Varadhan 	/* mac_prop_id */
2395bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_ESSID:
2396bcb5c89dSSowmini Varadhan 		err = wl_set_essid(ic, wldp_buf);
2397bcb5c89dSSowmini Varadhan 		break;
2398bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_BSSID:
2399bcb5c89dSSowmini Varadhan 		err = wl_set_bssid(ic, wldp_buf);
2400bcb5c89dSSowmini Varadhan 		break;
2401bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_PHY_CONFIG:
2402bcb5c89dSSowmini Varadhan 		err = wl_set_phy(ic, wldp_buf);
2403bcb5c89dSSowmini Varadhan 		break;
2404bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_KEY_TAB:
2405bcb5c89dSSowmini Varadhan 		err = wl_set_wepkey(ic, wldp_buf);
2406bcb5c89dSSowmini Varadhan 		break;
2407bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_AUTH_MODE:
2408bcb5c89dSSowmini Varadhan 		err = wl_set_authmode(ic, wldp_buf);
2409bcb5c89dSSowmini Varadhan 		break;
2410bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_ENCRYPTION:
2411bcb5c89dSSowmini Varadhan 		err = wl_set_encrypt(ic, wldp_buf);
2412bcb5c89dSSowmini Varadhan 		break;
2413bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_BSSTYPE:
2414bcb5c89dSSowmini Varadhan 		err = wl_set_bsstype(ic, wldp_buf);
2415bcb5c89dSSowmini Varadhan 		break;
2416bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_DESIRED_RATES:
2417bcb5c89dSSowmini Varadhan 		err = wl_set_desrates(ic, wldp_buf);
2418bcb5c89dSSowmini Varadhan 		break;
2419bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_WPA:
2420bcb5c89dSSowmini Varadhan 		err = wl_set_wpa(ic, wldp_buf);
2421bcb5c89dSSowmini Varadhan 		break;
2422bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_KEY:
2423bcb5c89dSSowmini Varadhan 		err = wl_set_wpakey(ic, wldp_buf);
2424bcb5c89dSSowmini Varadhan 		break;
2425bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_DELKEY:
2426bcb5c89dSSowmini Varadhan 		err = wl_set_delkey(ic, wldp_buf);
2427bcb5c89dSSowmini Varadhan 		break;
2428bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_SETOPTIE:
2429bcb5c89dSSowmini Varadhan 		err = wl_set_optie(ic, wldp_buf);
2430bcb5c89dSSowmini Varadhan 		break;
2431bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_MLME:
2432bcb5c89dSSowmini Varadhan 		err = wl_set_mlme(ic, wldp_buf);
2433bcb5c89dSSowmini Varadhan 		break;
2434127ac1c2Sfei feng - Sun Microsystems - Beijing China 	case MAC_PROP_WL_CREATE_IBSS:
2435127ac1c2Sfei feng - Sun Microsystems - Beijing China 		err = wl_set_createibss(ic, wldp_buf);
2436127ac1c2Sfei feng - Sun Microsystems - Beijing China 		break;
2437bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_LINKSTATUS:
2438bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_ESS_LIST:
2439bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_SUPPORTED_RATES:
2440bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_RSSI:
2441bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_CAPABILITY:
2442bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_SCANRESULTS:
2443bcb5c89dSSowmini Varadhan 		ieee80211_err("ieee80211_setprop: opmode err\n");
2444bcb5c89dSSowmini Varadhan 		err = EINVAL;
2445bcb5c89dSSowmini Varadhan 		break;
2446bcb5c89dSSowmini Varadhan 	default:
2447bcb5c89dSSowmini Varadhan 		ieee80211_err("ieee80211_setprop: opmode not support\n");
2448bcb5c89dSSowmini Varadhan 		err = ENOTSUP;
2449bcb5c89dSSowmini Varadhan 		break;
2450bcb5c89dSSowmini Varadhan 	}
2451bcb5c89dSSowmini Varadhan 
2452bcb5c89dSSowmini Varadhan 	IEEE80211_UNLOCK(ic);
2453bcb5c89dSSowmini Varadhan 
2454bcb5c89dSSowmini Varadhan 	return (err);
2455bcb5c89dSSowmini Varadhan }
2456bcb5c89dSSowmini Varadhan 
2457bcb5c89dSSowmini Varadhan /* ARGSUSED */
2458bcb5c89dSSowmini Varadhan int
ieee80211_getprop(void * ic_arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)2459bcb5c89dSSowmini Varadhan ieee80211_getprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2460*0dc2366fSVenugopal Iyer     uint_t wldp_length, void *wldp_buf)
2461bcb5c89dSSowmini Varadhan {
2462bcb5c89dSSowmini Varadhan 	int err = 0;
2463bcb5c89dSSowmini Varadhan 	struct ieee80211com *ic = ic_arg;
2464bcb5c89dSSowmini Varadhan 
2465bcb5c89dSSowmini Varadhan 	ASSERT(ic != NULL);
2466bcb5c89dSSowmini Varadhan 	IEEE80211_LOCK(ic);
2467bcb5c89dSSowmini Varadhan 
2468bcb5c89dSSowmini Varadhan 	switch (wldp_pr_num) {
2469bcb5c89dSSowmini Varadhan 	/* mac_prop_id */
2470bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_ESSID:
2471bcb5c89dSSowmini Varadhan 		wl_get_essid(ic, wldp_buf);
2472bcb5c89dSSowmini Varadhan 		break;
2473bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_BSSID:
2474bcb5c89dSSowmini Varadhan 		wl_get_bssid(ic, wldp_buf);
2475bcb5c89dSSowmini Varadhan 		break;
2476bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_PHY_CONFIG:
2477bcb5c89dSSowmini Varadhan 		err = wl_get_phy(ic, wldp_buf);
2478bcb5c89dSSowmini Varadhan 		break;
2479bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_AUTH_MODE:
2480bcb5c89dSSowmini Varadhan 		wl_get_authmode(ic, wldp_buf);
2481bcb5c89dSSowmini Varadhan 		break;
2482bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_ENCRYPTION:
2483bcb5c89dSSowmini Varadhan 		wl_get_encrypt(ic, wldp_buf);
2484bcb5c89dSSowmini Varadhan 		break;
2485bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_BSSTYPE:
2486bcb5c89dSSowmini Varadhan 		wl_get_bsstype(ic, wldp_buf);
2487bcb5c89dSSowmini Varadhan 		break;
2488bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_DESIRED_RATES:
2489bcb5c89dSSowmini Varadhan 		wl_get_desrates(ic, wldp_buf);
2490bcb5c89dSSowmini Varadhan 		break;
2491bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_LINKSTATUS:
2492bcb5c89dSSowmini Varadhan 		wl_get_linkstatus(ic, wldp_buf);
2493bcb5c89dSSowmini Varadhan 		break;
2494bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_ESS_LIST:
2495bcb5c89dSSowmini Varadhan 		wl_get_esslist(ic, wldp_buf);
2496bcb5c89dSSowmini Varadhan 		break;
2497bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_SUPPORTED_RATES:
2498bcb5c89dSSowmini Varadhan 		wl_get_suprates(ic, wldp_buf);
2499bcb5c89dSSowmini Varadhan 		break;
2500bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_RSSI:
2501bcb5c89dSSowmini Varadhan 		wl_get_rssi(ic, wldp_buf);
2502bcb5c89dSSowmini Varadhan 		break;
2503bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_CAPABILITY:
2504bcb5c89dSSowmini Varadhan 		wl_get_capability(ic, wldp_buf);
2505bcb5c89dSSowmini Varadhan 		break;
2506bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_WPA:
2507bcb5c89dSSowmini Varadhan 		wl_get_wpa(ic, wldp_buf);
2508bcb5c89dSSowmini Varadhan 		break;
2509bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_SCANRESULTS:
2510bcb5c89dSSowmini Varadhan 		wl_get_scanresults(ic, wldp_buf);
2511bcb5c89dSSowmini Varadhan 		break;
2512127ac1c2Sfei feng - Sun Microsystems - Beijing China 	case MAC_PROP_WL_CREATE_IBSS:
2513127ac1c2Sfei feng - Sun Microsystems - Beijing China 		wl_get_createibss(ic, wldp_buf);
2514127ac1c2Sfei feng - Sun Microsystems - Beijing China 		break;
2515bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_KEY_TAB:
2516bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_KEY:
2517bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_DELKEY:
2518bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_SETOPTIE:
2519bcb5c89dSSowmini Varadhan 	case MAC_PROP_WL_MLME:
2520bcb5c89dSSowmini Varadhan 		ieee80211_err("ieee80211_setprop: opmode err\n");
2521bcb5c89dSSowmini Varadhan 		err = EINVAL;
2522bcb5c89dSSowmini Varadhan 		break;
2523bcb5c89dSSowmini Varadhan 	default:
2524bcb5c89dSSowmini Varadhan 		ieee80211_err("ieee80211_setprop: opmode not support\n");
2525bcb5c89dSSowmini Varadhan 		err = ENOTSUP;
2526bcb5c89dSSowmini Varadhan 		break;
2527bcb5c89dSSowmini Varadhan 	}
2528bcb5c89dSSowmini Varadhan 
2529bcb5c89dSSowmini Varadhan 	IEEE80211_UNLOCK(ic);
2530bcb5c89dSSowmini Varadhan 
2531bcb5c89dSSowmini Varadhan 	return (err);
2532bcb5c89dSSowmini Varadhan }
2533*0dc2366fSVenugopal Iyer 
ieee80211_propinfo(void * ic_arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t prh)2534*0dc2366fSVenugopal Iyer void ieee80211_propinfo(void *ic_arg, const char *pr_name,
2535*0dc2366fSVenugopal Iyer     mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t prh)
2536*0dc2366fSVenugopal Iyer {
2537*0dc2366fSVenugopal Iyer         _NOTE(ARGUNUSED(pr_name, ic_arg));
2538*0dc2366fSVenugopal Iyer 
2539*0dc2366fSVenugopal Iyer 	/*
2540*0dc2366fSVenugopal Iyer 	 * By default permissions are read/write unless specified
2541*0dc2366fSVenugopal Iyer 	 * otherwise by the driver.
2542*0dc2366fSVenugopal Iyer 	 */
2543*0dc2366fSVenugopal Iyer 
2544*0dc2366fSVenugopal Iyer 	switch (wldp_pr_num) {
2545*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_LINKSTATUS:
2546*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_ESS_LIST:
2547*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_SUPPORTED_RATES:
2548*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_RSSI:
2549*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_CAPABILITY:
2550*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_SCANRESULTS:
2551*0dc2366fSVenugopal Iyer 	case MAC_PROP_WL_CREATE_IBSS:
2552*0dc2366fSVenugopal Iyer 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2553*0dc2366fSVenugopal Iyer 	}
2554*0dc2366fSVenugopal Iyer }
2555