xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_wext.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file  moal_wext.c
2  *
3  * @brief This file contains wireless extension standard ioctl functions
4  *
5  *
6  * Copyright 2008-2021 NXP
7  *
8  * This software file (the File) is distributed by NXP
9  * under the terms of the GNU General Public License Version 2, June 1991
10  * (the License).  You may use, redistribute and/or modify the File in
11  * accordance with the terms and conditions of the License, a copy of which
12  * is available by writing to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  * this warranty disclaimer.
20  *
21  */
22 
23 /************************************************************************
24 Change log:
25     10/21/2008: initial version
26 ************************************************************************/
27 
28 #include "moal_main.h"
29 
30 #ifdef STA_SUPPORT
31 /** Approximate amount of data needed to pass a scan result back to iwlist */
32 #define MAX_SCAN_CELL_SIZE                                                     \
33 	(IW_EV_ADDR_LEN + MLAN_MAX_SSID_LENGTH + IW_EV_UINT_LEN +              \
34 	 IW_EV_FREQ_LEN + IW_EV_QUAL_LEN + MLAN_MAX_SSID_LENGTH +              \
35 	 IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
36 
37 /********************************************************
38 			Local Variables
39 ********************************************************/
40 /**
41  * iwpriv ioctl handlers
42  */
43 static const struct iw_priv_args woal_private_args[] = {
44 	{WOAL_SETONEINT_GETWORDCHAR, IW_PRIV_TYPE_INT | 1,
45 	 IW_PRIV_TYPE_CHAR | 128, ""},
46 	{WOAL_VERSION, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128,
47 	 "version"},
48 	{WOAL_VEREXT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128, "verext"},
49 	{WOAL_SETNONE_GETNONE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, ""},
50 	{WOAL_WARMRESET, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "warmreset"},
51 #ifdef CONFIG_USB_SUSPEND
52 	{WOAL_USB_SUSPEND, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "usbsuspend"},
53 	{WOAL_USB_RESUME, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "usbresume"},
54 #endif /* CONFIG_USB_SUSPEND */
55 	{WOAL_SETONEINT_GETONEINT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
56 	 ""},
57 	{WOAL_SET_GET_TXRATE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
58 	 "txratecfg"},
59 	{WOAL_SET_GET_REGIONCODE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
60 	 "regioncode"},
61 	{WOAL_SET_RADIO, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
62 	 "radioctrl"},
63 	{WOAL_WMM_ENABLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "wmmcfg"},
64 	{WOAL_11D_ENABLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "11dcfg"},
65 	{WOAL_11D_CLR_CHAN_TABLE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE,
66 	 "11dclrtbl"},
67 	{WOAL_SET_GET_QOS_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
68 	 "qoscfg"},
69 #ifndef OPCHAN
70 	{WOAL_SET_GET_WWS_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
71 	 "wwscfg"},
72 #endif
73 #if defined(REASSOCIATION)
74 	{WOAL_SET_GET_REASSOC, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
75 	 "reassoctrl"},
76 #endif
77 	{WOAL_TXBUF_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
78 	 "txbufcfg"},
79 	{WOAL_SLEEP_PD, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "sleeppd"},
80 	{WOAL_AUTH_TYPE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
81 	 "authtype"},
82 	{WOAL_PORT_CTRL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
83 	 "port_ctrl"},
84 #ifdef WIFI_DIRECT_SUPPORT
85 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
86 	{WOAL_SET_GET_BSS_ROLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
87 	 "bssrole"},
88 #endif
89 #endif
90 	{WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT, IW_PRIV_TYPE_INT | 1,
91 	 IW_PRIV_TYPE_INT | 1, "powercons"},
92 	{WOAL_HT_STREAM_CFG, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
93 	 "htstreamcfg"},
94 	{WOAL_MAC_CONTROL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
95 	 "macctrl"},
96 	{WOAL_THERMAL, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1, "thermal"},
97 	{WOAL_CFG_HOTSPOT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
98 	 "hotspotcfg"},
99 	{WOAL_SET_GET_SIXTEEN_INT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
100 	 ""},
101 	{WOAL_TX_POWERCFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
102 	 "txpowercfg"},
103 #ifdef DEBUG_LEVEL1
104 	{WOAL_DRV_DBG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "drvdbg"},
105 #endif
106 	{WOAL_BEACON_INTERVAL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
107 	 "bcninterval"},
108 	{WOAL_SIGNAL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
109 	 "getsignal"},
110 	{
111 		WOAL_DEEP_SLEEP,
112 		IW_PRIV_TYPE_INT | 16,
113 		IW_PRIV_TYPE_INT | 16,
114 		"deepsleep",
115 	},
116 	{WOAL_11N_TX_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
117 	 "httxcfg"},
118 	{WOAL_11N_HTCAP_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
119 	 "htcapinfo"},
120 	{WOAL_PRIO_TBL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
121 	 "aggrpriotbl"},
122 	{WOAL_11N_AMSDU_AGGR_CTRL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
123 	 "amsduaggrctrl"},
124 	{WOAL_ADDBA_UPDT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
125 	 "addbapara"},
126 	{WOAL_ADDBA_REJECT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
127 	 "addbareject"},
128 	{WOAL_TX_BF_CAP, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
129 	 "httxbfcap"},
130 	{WOAL_HS_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "hscfg"},
131 	{WOAL_HS_SETPARA, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
132 	 "hssetpara"},
133 	{WOAL_REG_READ_WRITE, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
134 	 "regrdwr"},
135 	{WOAL_BAND_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
136 	 "bandcfg"},
137 	{WOAL_INACTIVITY_TIMEOUT_EXT, IW_PRIV_TYPE_INT | 16,
138 	 IW_PRIV_TYPE_INT | 16, "inactivityto"},
139 #ifdef SDIO
140 	{WOAL_SDIO_CLOCK, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
141 	 "sdioclock"},
142 	{WOAL_CMD_52RDWR, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
143 	 "sdcmd52rw"},
144 #endif
145 	{WOAL_SCAN_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
146 	 "scancfg"},
147 	{WOAL_PS_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "pscfg"},
148 	{WOAL_MEM_READ_WRITE, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
149 	 "memrdwr"},
150 #ifdef SDIO
151 	{WOAL_SDIO_MPA_CTRL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
152 	 "mpactrl"},
153 #endif
154 	{WOAL_SLEEP_PARAMS, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
155 	 "sleepparams"},
156 	{WOAL_NET_MONITOR, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
157 	 "netmon"},
158 	{WOAL_DFS_TESTING, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
159 	 "dfstesting"},
160 	{WOAL_MGMT_FRAME_CTRL, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
161 	 "mgmtframectrl"},
162 	{WOAL_CFP_CODE, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
163 	 "cfpcode"},
164 	{WOAL_SET_GET_TX_RX_ANT, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
165 	 "antcfg"},
166 	{WOAL_IND_RST_CFG, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16,
167 	 "indrstcfg"},
168 	{WOALGETLOG, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
169 	 "getlog"},
170 	{WOAL_SETADDR_GETNONE, IW_PRIV_TYPE_ADDR | 1, IW_PRIV_TYPE_NONE, ""},
171 	{WOAL_DEAUTH, IW_PRIV_TYPE_ADDR | 1, IW_PRIV_TYPE_NONE, "deauth"},
172 	{WOAL_SET_GET_256_CHAR, IW_PRIV_TYPE_CHAR | 256,
173 	 IW_PRIV_TYPE_CHAR | 256, ""},
174 	{WOAL_PASSPHRASE, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
175 	 "passphrase"},
176 	{WOAL_GET_KEY, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
177 	 "getkey"},
178 	{WOAL_ASSOCIATE, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
179 	 "associate"},
180 	{WOAL_WMM_QUEUE_STATUS, IW_PRIV_TYPE_CHAR | 256,
181 	 IW_PRIV_TYPE_CHAR | 256, "qstatus"},
182 	{WOAL_WMM_TS_STATUS, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
183 	 "ts_status"},
184 	{WOAL_IP_ADDRESS, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
185 	 "ipaddr"},
186 	{WOAL_TX_BF_CFG, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
187 	 "httxbfcfg"},
188 	{WOAL_SETNONE_GETTWELVE_CHAR, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | 12,
189 	 ""},
190 	{WOAL_WPS_SESSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | 12,
191 	 "wpssession"},
192 	{WOAL_SETNONE_GET_FOUR_INT, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | 4,
193 	 ""},
194 	{WOAL_DATA_RATE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | 4,
195 	 "getdatarate"},
196 	{WOAL_ESUPP_MODE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | 4, "esuppmode"},
197 	{WOAL_SET_GET_64_INT, IW_PRIV_TYPE_INT | 64, IW_PRIV_TYPE_INT | 64, ""},
198 	{WOAL_ECL_SYS_CLOCK, IW_PRIV_TYPE_INT | 64, IW_PRIV_TYPE_INT | 64,
199 	 "sysclock"},
200 	{WOAL_HOST_CMD, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_BYTE | 2047,
201 	 "hostcmd"},
202 	{WOAL_ARP_FILTER, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_BYTE | 2047,
203 	 "arpfilter"},
204 	{WOAL_SET_INTS_GET_CHARS, IW_PRIV_TYPE_INT | 16,
205 	 IW_PRIV_TYPE_BYTE | 256, ""},
206 	{WOAL_READ_EEPROM, IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_BYTE | 256,
207 	 "rdeeprom"},
208 	{WOAL_SET_GET_2K_BYTES, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
209 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, ""},
210 #if defined(SDIO)
211 	{WOAL_CMD_53RDWR, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
212 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "sdcmd53rw"},
213 #endif
214 	{WOAL_SET_USER_SCAN, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
215 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "setuserscan"},
216 	{WOAL_GET_SCAN_TABLE, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
217 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "getscantable"},
218 	{WOAL_SET_USER_SCAN_EXT, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
219 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "setuserscanext"},
220 	{WOAL_WMM_ADDTS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
221 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "addts"},
222 	{WOAL_WMM_DELTS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
223 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "delts"},
224 	{WOAL_WMM_QUEUE_CONFIG, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
225 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "qconfig"},
226 	{WOAL_WMM_QUEUE_STATS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
227 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "qstats"},
228 	{WOAL_BYPASSED_PACKET, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES,
229 	 IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "pb_bypass"},
230 #ifdef UAP_WEXT
231 	{WOAL_FROYO_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "START"},
232 	{WOAL_FROYO_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "STOP"},
233 	{WOAL_FROYO_WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256,
234 	 IW_PRIV_TYPE_CHAR | 256, "WL_FW_RELOAD"},
235 #endif
236 };
237 
238 /********************************************************
239 			Local Functions
240 ********************************************************/
241 
242 /**
243  *  @brief Compare two SSIDs
244  *
245  *  @param ssid1    A pointer to ssid to compare
246  *  @param ssid2    A pointer to ssid to compare
247  *
248  *  @return         0--ssid is same, otherwise is different
249  */
woal_ssid_cmp(mlan_802_11_ssid * ssid1,mlan_802_11_ssid * ssid2)250 static t_s32 woal_ssid_cmp(mlan_802_11_ssid *ssid1, mlan_802_11_ssid *ssid2)
251 {
252 	ENTER();
253 
254 	if (!ssid1 || !ssid2) {
255 		LEAVE();
256 		return -1;
257 	}
258 	if (ssid1->ssid_len != ssid2->ssid_len) {
259 		LEAVE();
260 		return -1;
261 	}
262 
263 	LEAVE();
264 	return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
265 }
266 
267 /**
268  *  @brief Sort Channels
269  *
270  *  @param freq                 A pointer to iw_freq structure
271  *  @param num                  Number of Channels
272  *
273  *  @return                     N/A
274  */
woal_sort_channels(struct iw_freq * freq,int num)275 static inline void woal_sort_channels(struct iw_freq *freq, int num)
276 {
277 	int i, j;
278 	struct iw_freq temp;
279 
280 	for (i = 0; i < num; i++)
281 		for (j = i + 1; j < num; j++)
282 			if (freq[i].i > freq[j].i) {
283 				temp.i = freq[i].i;
284 				temp.m = freq[i].m;
285 
286 				freq[i].i = freq[j].i;
287 				freq[i].m = freq[j].m;
288 
289 				freq[j].i = temp.i;
290 				freq[j].m = temp.m;
291 			}
292 }
293 
294 /**
295  *  @brief Convert RSSI to quality
296  *
297  *  @param rssi     RSSI in dBm
298  *
299  *  @return         Quality of the link (0-5)
300  */
woal_rssi_to_quality(t_s16 rssi)301 static t_u8 woal_rssi_to_quality(t_s16 rssi)
302 {
303 /** Macro for RSSI range */
304 #define MOAL_RSSI_NO_SIGNAL -90
305 #define MOAL_RSSI_VERY_LOW -80
306 #define MOAL_RSSI_LOW -70
307 #define MOAL_RSSI_GOOD -60
308 #define MOAL_RSSI_VERY_GOOD -50
309 #define MOAL_RSSI_INVALID 0
310 	if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID)
311 		return 0;
312 	else if (rssi <= MOAL_RSSI_VERY_LOW)
313 		return 1;
314 	else if (rssi <= MOAL_RSSI_LOW)
315 		return 2;
316 	else if (rssi <= MOAL_RSSI_GOOD)
317 		return 3;
318 	else if (rssi <= MOAL_RSSI_VERY_GOOD)
319 		return 4;
320 	else
321 		return 5;
322 }
323 
324 /**
325  *  @brief Set Adapter Node Name
326  *
327  *  @param dev                  A pointer to net_device structure
328  *  @param info                 A pointer to iw_request_info structure
329  *  @param dwrq                 A pointer to iw_point structure
330  *  @param extra                A pointer to extra data buf
331  *
332  *  @return                     0 --success, otherwise fail
333  */
woal_set_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)334 static int woal_set_nick(struct net_device *dev, struct iw_request_info *info,
335 			 struct iw_point *dwrq, char *extra)
336 {
337 	moal_private *priv = (moal_private *)netdev_priv(dev);
338 	ENTER();
339 	/*
340 	 * Check the size of the string
341 	 */
342 	if (dwrq->length > 16) {
343 		LEAVE();
344 		return -E2BIG;
345 	}
346 	memset(priv->nick_name, 0, sizeof(priv->nick_name));
347 	moal_memcpy_ext(priv->phandle, priv->nick_name, extra, dwrq->length,
348 			sizeof(priv->nick_name));
349 	LEAVE();
350 	return 0;
351 }
352 
353 /**
354  *  @brief Get Adapter Node Name
355  *
356  *  @param dev                  A pointer to net_device structure
357  *  @param info                 A pointer to iw_request_info structure
358  *  @param dwrq                 A pointer to iw_point structure
359  *  @param extra                A pointer to extra data buf
360  *
361  *  @return                     0 --success
362  */
woal_get_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)363 static int woal_get_nick(struct net_device *dev, struct iw_request_info *info,
364 			 struct iw_point *dwrq, char *extra)
365 {
366 	moal_private *priv = (moal_private *)netdev_priv(dev);
367 	ENTER();
368 	/*
369 	 * Get the Nick Name saved
370 	 */
371 	strncpy(extra, (char *)priv->nick_name, 16);
372 	extra[16] = '\0';
373 	/*
374 	 * If none, we may want to get the one that was set
375 	 */
376 
377 	/*
378 	 * Push it out !
379 	 */
380 	dwrq->length = strlen(extra) + 1;
381 	LEAVE();
382 	return 0;
383 }
384 
385 /**
386  *  @brief Commit handler: called after a bunch of SET operations
387  *
388  *  @param dev          A pointer to net_device structure
389  *  @param info         A pointer to iw_request_info structure
390  *  @param cwrq         A pointer to char buffer
391  *  @param extra        A pointer to extra data buf
392  *
393  *  @return             0 --success
394  */
woal_config_commit(struct net_device * dev,struct iw_request_info * info,union iwreq_data * cwrq,char * extra)395 static int woal_config_commit(struct net_device *dev,
396 			      struct iw_request_info *info,
397 			      union iwreq_data *cwrq, char *extra)
398 {
399 	ENTER();
400 
401 	LEAVE();
402 	return 0;
403 }
404 
405 /**
406  *  @brief Get name
407  *
408  *  @param dev          A pointer to net_device structure
409  *  @param info         A pointer to iw_request_info structure
410  *  @param cwrq         A pointer to char buffer
411  *  @param extra        A pointer to extra data buf
412  *
413  *  @return             0 --success
414  */
woal_get_name(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)415 static int woal_get_name(struct net_device *dev, struct iw_request_info *info,
416 			 union iwreq_data *wrqu, char *extra)
417 {
418 	char *cwrq = wrqu->name;
419 	ENTER();
420 	strcpy(cwrq, "IEEE 802.11-DS");
421 	LEAVE();
422 	return 0;
423 }
424 
425 /**
426  *  @brief Set frequency
427  *
428  *  @param dev                  A pointer to net_device structure
429  *  @param info                 A pointer to iw_request_info structure
430  *  @param fwrq                 A pointer to iw_freq structure
431  *  @param extra                A pointer to extra data buf
432  *
433  *  @return                     0 --success, otherwise fail
434  */
woal_set_freq(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)435 static int woal_set_freq(struct net_device *dev, struct iw_request_info *info,
436 			 union iwreq_data *wrqu, char *extra)
437 {
438 	int ret = 0;
439 	moal_private *priv = (moal_private *)netdev_priv(dev);
440 	struct iw_freq *fwrq = &wrqu->freq;
441 	mlan_ds_bss *bss = NULL;
442 	mlan_ioctl_req *req = NULL;
443 	mlan_status status = MLAN_STATUS_SUCCESS;
444 
445 	ENTER();
446 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
447 	if (req == NULL) {
448 		ret = -ENOMEM;
449 		goto done;
450 	}
451 	bss = (mlan_ds_bss *)req->pbuf;
452 	/*
453 	 * If setting by frequency, convert to a channel
454 	 */
455 	if (fwrq->e == 1) {
456 		long f = fwrq->m / 100000;
457 		bss->param.bss_chan.freq = f;
458 	} else
459 		bss->param.bss_chan.channel = fwrq->m;
460 
461 	bss->sub_command = MLAN_OID_BSS_CHANNEL;
462 	req->req_id = MLAN_IOCTL_BSS;
463 	req->action = MLAN_ACT_SET;
464 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
465 	if (status != MLAN_STATUS_SUCCESS) {
466 		ret = -EFAULT;
467 		goto done;
468 	}
469 	if (MLAN_STATUS_SUCCESS !=
470 	    woal_change_adhoc_chan(priv, bss->param.bss_chan.channel,
471 				   MOAL_IOCTL_WAIT))
472 		ret = -EFAULT;
473 
474 done:
475 	if (status != MLAN_STATUS_PENDING)
476 		kfree(req);
477 	LEAVE();
478 	return ret;
479 }
480 
481 /**
482  *  @brief Get frequency
483  *
484  *  @param dev                  A pointer to net_device structure
485  *  @param info                 A pointer to iw_request_info structure
486  *  @param fwrq                 A pointer to iw_freq structure
487  *  @param extra                A pointer to extra data buf
488  *
489  *  @return                     0 --success, otherwise fail
490  */
woal_get_freq(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)491 static int woal_get_freq(struct net_device *dev, struct iw_request_info *info,
492 			 union iwreq_data *wrqu, char *extra)
493 {
494 	int ret = 0;
495 	moal_private *priv = (moal_private *)netdev_priv(dev);
496 	struct iw_freq *fwrq = &wrqu->freq;
497 	mlan_ds_bss *bss = NULL;
498 	mlan_ioctl_req *req = NULL;
499 	mlan_status status = MLAN_STATUS_SUCCESS;
500 
501 	ENTER();
502 
503 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
504 	if (req == NULL) {
505 		ret = -ENOMEM;
506 		goto done;
507 	}
508 	bss = (mlan_ds_bss *)req->pbuf;
509 	bss->sub_command = MLAN_OID_BSS_CHANNEL;
510 	req->req_id = MLAN_IOCTL_BSS;
511 	req->action = MLAN_ACT_GET;
512 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
513 	if (status != MLAN_STATUS_SUCCESS) {
514 		ret = -EFAULT;
515 		goto done;
516 	}
517 	fwrq->m = (long)bss->param.bss_chan.freq;
518 	fwrq->i = (long)bss->param.bss_chan.channel;
519 	fwrq->e = 6;
520 	fwrq->flags = IW_FREQ_FIXED;
521 done:
522 	if (status != MLAN_STATUS_PENDING)
523 		kfree(req);
524 	LEAVE();
525 	return ret;
526 }
527 
528 /**
529  *  @brief Set wlan mode
530  *
531  *  @param dev                  A pointer to net_device structure
532  *  @param info                 A pointer to iw_request_info structure
533  *  @param uwrq                 Wireless mode to set
534  *  @param extra                A pointer to extra data buf
535  *
536  *  @return                     0 --success, otherwise fail
537  */
woal_set_bss_mode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)538 static int woal_set_bss_mode(struct net_device *dev,
539 			     struct iw_request_info *info,
540 			     union iwreq_data *wrqu, char *extra)
541 {
542 	int ret = 0;
543 	moal_private *priv = (moal_private *)netdev_priv(dev);
544 	t_u32 *uwrq = &wrqu->mode;
545 	mlan_ds_bss *bss = NULL;
546 	mlan_ioctl_req *req = NULL;
547 	mlan_status status = MLAN_STATUS_SUCCESS;
548 
549 	ENTER();
550 
551 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
552 	if (req == NULL) {
553 		ret = -ENOMEM;
554 		goto done;
555 	}
556 	bss = (mlan_ds_bss *)req->pbuf;
557 	bss->sub_command = MLAN_OID_BSS_MODE;
558 	req->req_id = MLAN_IOCTL_BSS;
559 	req->action = MLAN_ACT_SET;
560 
561 	switch (*uwrq) {
562 	case IW_MODE_INFRA:
563 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
564 		break;
565 	case IW_MODE_ADHOC:
566 		bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
567 		break;
568 	case IW_MODE_AUTO:
569 		bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
570 		break;
571 	default:
572 		ret = -EINVAL;
573 		break;
574 	}
575 	if (ret)
576 		goto done;
577 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
578 	if (status != MLAN_STATUS_SUCCESS) {
579 		ret = -EFAULT;
580 		goto done;
581 	}
582 done:
583 	if (status != MLAN_STATUS_PENDING)
584 		kfree(req);
585 	LEAVE();
586 	return ret;
587 }
588 
589 /**
590  *  @brief Get current BSSID
591  *
592  *  @param dev          A pointer to net_device structure
593  *  @param info         A pointer to iw_request_info structure
594  *  @param awrq         A pointer to sockaddr structure
595  *  @param extra        A pointer to extra data buf
596  *
597  *  @return             0 --success
598  */
woal_get_wap(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)599 static int woal_get_wap(struct net_device *dev, struct iw_request_info *info,
600 			union iwreq_data *wrqu, char *extra)
601 {
602 	int ret = 0;
603 	moal_private *priv = (moal_private *)netdev_priv(dev);
604 	struct sockaddr *awrq = &wrqu->addr;
605 	mlan_bss_info bss_info;
606 
607 	ENTER();
608 
609 	memset(&bss_info, 0, sizeof(bss_info));
610 
611 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
612 
613 	if (bss_info.media_connected == MTRUE)
614 		moal_memcpy_ext(priv->phandle, awrq->sa_data, &bss_info.bssid,
615 				MLAN_MAC_ADDR_LENGTH, sizeof(awrq->sa_data));
616 	else
617 		memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
618 	awrq->sa_family = ARPHRD_ETHER;
619 
620 	LEAVE();
621 	return ret;
622 }
623 
624 /**
625  *  @brief Connect to the AP or Ad-hoc Network with specific bssid
626  *
627  * NOTE: Scan should be issued by application before this function is called
628  *
629  *  @param dev          A pointer to net_device structure
630  *  @param info         A pointer to iw_request_info structure
631  *  @param awrq         A pointer to iw_param structure
632  *  @param extra        A pointer to extra data buf
633  *
634  *  @return             0 --success, otherwise fail
635  */
woal_set_wap(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)636 static int woal_set_wap(struct net_device *dev, struct iw_request_info *info,
637 			union iwreq_data *wrqu, char *extra)
638 {
639 	int ret = 0;
640 	const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {255, 255, 255, 255, 255, 255};
641 	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
642 	moal_private *priv = (moal_private *)netdev_priv(dev);
643 	struct sockaddr *awrq = &wrqu->addr;
644 	mlan_ssid_bssid ssid_bssid;
645 	mlan_bss_info bss_info;
646 
647 	ENTER();
648 
649 	if (awrq->sa_family != ARPHRD_ETHER) {
650 		ret = -EINVAL;
651 		goto done;
652 	}
653 
654 	PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
655 	       MAC2STR((t_u8 *)awrq->sa_data));
656 
657 	if (MLAN_STATUS_SUCCESS !=
658 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
659 		ret = -EFAULT;
660 		goto done;
661 	}
662 
663 #ifdef REASSOCIATION
664 	/* Cancel re-association */
665 	priv->reassoc_required = MFALSE;
666 #endif
667 
668 	/* zero_mac means disconnect */
669 	if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
670 		woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
671 				DEF_DEAUTH_REASON_CODE);
672 		goto done;
673 	}
674 
675 	/* Broadcast MAC means search for best network */
676 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
677 
678 	if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
679 		/* Check if we are already assoicated to the AP */
680 		if (bss_info.media_connected == MTRUE) {
681 			if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
682 				goto done;
683 		}
684 		moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data,
685 				ETH_ALEN, sizeof(ssid_bssid.bssid));
686 	}
687 
688 	if (MLAN_STATUS_SUCCESS !=
689 	    woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
690 		PRINTM(MERROR,
691 		       "ASSOC: WAP: MAC address not found in BSSID List\n");
692 		ret = -ENETUNREACH;
693 		goto done;
694 	}
695 	/* Zero SSID implies use BSSID to connect */
696 	memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
697 	if (MLAN_STATUS_SUCCESS !=
698 	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
699 		ret = -EFAULT;
700 		goto done;
701 	}
702 
703 #ifdef REASSOCIATION
704 	memset(&bss_info, 0, sizeof(bss_info));
705 	if (MLAN_STATUS_SUCCESS !=
706 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
707 		ret = -EFAULT;
708 		goto done;
709 	}
710 	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
711 			&bss_info.ssid, sizeof(mlan_802_11_ssid),
712 			sizeof(priv->prev_ssid_bssid.ssid));
713 	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
714 			&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
715 			sizeof(priv->prev_ssid_bssid.bssid));
716 #endif /* REASSOCIATION */
717 
718 done:
719 
720 	LEAVE();
721 	return ret;
722 }
723 
724 /**
725  *  @brief Get wlan mode
726  *
727  *  @param dev                  A pointer to net_device structure
728  *  @param info                 A pointer to iw_request_info structure
729  *  @param uwrq                 A pointer to t_u32 string
730  *  @param extra                A pointer to extra data buf
731  *
732  *  @return                     0 --success
733  */
woal_get_bss_mode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)734 static int woal_get_bss_mode(struct net_device *dev,
735 			     struct iw_request_info *info,
736 			     union iwreq_data *wrqu, char *extra)
737 {
738 	moal_private *priv = (moal_private *)netdev_priv(dev);
739 	t_u32 *uwrq = &wrqu->mode;
740 	ENTER();
741 	*uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
742 	LEAVE();
743 	return 0;
744 }
745 
746 /**
747  *  @brief Set sensitivity
748  *
749  *  @param dev                  A pointer to net_device structure
750  *  @param info                 A pointer to iw_request_info structure
751  *  @param vwrq                 A pointer to iw_param structure
752  *  @param extra                A pointer to extra data buf
753  *
754  *  @return                     0 --success
755  */
woal_set_sens(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)756 static int woal_set_sens(struct net_device *dev, struct iw_request_info *info,
757 			 union iwreq_data *wrqu, char *extra)
758 {
759 	int ret = 0;
760 
761 	ENTER();
762 
763 	LEAVE();
764 	return ret;
765 }
766 
767 /**
768  *  @brief Get sensitivity
769  *
770  *  @param dev                  A pointer to net_device structure
771  *  @param info                 A pointer to iw_request_info structure
772  *  @param vwrq                 A pointer to iw_param structure
773  *  @param extra                A pointer to extra data buf
774  *
775  *  @return                     -1
776  */
woal_get_sens(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)777 static int woal_get_sens(struct net_device *dev, struct iw_request_info *info,
778 			 union iwreq_data *wrqu, char *extra)
779 {
780 	int ret = -1;
781 
782 	ENTER();
783 
784 	LEAVE();
785 	return ret;
786 }
787 
788 /**
789  *  @brief Set Tx power
790  *
791  *  @param dev                  A pointer to net_device structure
792  *  @param info                 A pointer to iw_request_info structure
793  *  @param vwrq                 A pointer to iw_param structure
794  *  @param extra                A pointer to extra data buf
795  *
796  *  @return                     0 --success, otherwise fail
797  */
woal_set_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)798 static int woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
799 			  struct iw_param *vwrq, char *extra)
800 {
801 	int ret = 0;
802 	moal_private *priv = (moal_private *)netdev_priv(dev);
803 	mlan_power_cfg_t power_cfg;
804 
805 	ENTER();
806 	if (vwrq->disabled) {
807 		woal_set_radio(priv, 0);
808 		goto done;
809 	}
810 	woal_set_radio(priv, 1);
811 
812 	if (!vwrq->fixed)
813 		power_cfg.is_power_auto = 1;
814 	else {
815 		power_cfg.is_power_auto = 0;
816 		power_cfg.power_level = vwrq->value;
817 	}
818 
819 	if (MLAN_STATUS_SUCCESS !=
820 	    woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) {
821 		ret = -EFAULT;
822 		goto done;
823 	}
824 
825 done:
826 	LEAVE();
827 	return ret;
828 }
829 
830 /**
831  *  @brief Get Tx power
832  *
833  *  @param dev                  A pointer to net_device structure
834  *  @param info                 A pointer to iw_request_info structure
835  *  @param vwrq                 A pointer to iw_param structure
836  *  @param extra                A pointer to extra data buf
837  *
838  *  @return                     0 --success, otherwise fail
839  */
woal_get_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)840 static int woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
841 			  struct iw_param *vwrq, char *extra)
842 {
843 	int ret = 0;
844 	moal_private *priv = (moal_private *)netdev_priv(dev);
845 	mlan_power_cfg_t power_cfg;
846 	mlan_bss_info bss_info;
847 
848 	ENTER();
849 
850 	memset(&power_cfg, 0, sizeof(mlan_power_cfg_t));
851 	memset(&bss_info, 0, sizeof(bss_info));
852 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
853 
854 	if (MLAN_STATUS_SUCCESS !=
855 	    woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
856 		ret = -EFAULT;
857 		goto done;
858 	}
859 
860 	vwrq->value = power_cfg.power_level;
861 	if (power_cfg.is_power_auto)
862 		vwrq->fixed = 0;
863 	else
864 		vwrq->fixed = 1;
865 	if (bss_info.radio_on) {
866 		vwrq->disabled = 0;
867 		vwrq->flags = IW_TXPOW_DBM;
868 	} else {
869 		vwrq->disabled = 1;
870 	}
871 
872 done:
873 	LEAVE();
874 	return ret;
875 }
876 
877 /**
878  *  @brief  Set power management
879  *
880  *  @param dev                  A pointer to net_device structure
881  *  @param info                 A pointer to iw_request_info structure
882  *  @param vwrq                 A pointer to iw_param structure
883  *  @param extra                A pointer to extra data buf
884  *
885  *  @return                     MLAN_STATUS_SUCCESS --success, otherwise fail
886  */
woal_set_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)887 static int woal_set_power(struct net_device *dev, struct iw_request_info *info,
888 			  struct iw_param *vwrq, char *extra)
889 {
890 	int ret = 0, disabled;
891 	moal_private *priv = (moal_private *)netdev_priv(dev);
892 
893 	ENTER();
894 
895 	if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
896 		PRINTM(MIOCTL, "block set power in hw_test mode\n");
897 		LEAVE();
898 		return ret;
899 	}
900 	disabled = vwrq->disabled;
901 
902 	if (MLAN_STATUS_SUCCESS !=
903 	    woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, vwrq->flags,
904 				    MOAL_IOCTL_WAIT)) {
905 		ret = -EFAULT;
906 	}
907 
908 	LEAVE();
909 	return ret;
910 }
911 
912 /**
913  *  @brief  Get power management
914  *
915  *  @param dev                  A pointer to net_device structure
916  *  @param info                 A pointer to iw_request_info structure
917  *  @param vwrq                 A pointer to iw_param structure
918  *  @param extra                A pointer to extra data buf
919  *
920  *  @return                     MLAN_STATUS_SUCCESS --success, otherwise fail
921  */
woal_get_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)922 static int woal_get_power(struct net_device *dev, struct iw_request_info *info,
923 			  struct iw_param *vwrq, char *extra)
924 {
925 	int ret = 0, ps_mode = 0;
926 	moal_private *priv = (moal_private *)netdev_priv(dev);
927 
928 	ENTER();
929 
930 	if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
931 							   &ps_mode, 0,
932 							   MOAL_IOCTL_WAIT)) {
933 		ret = -EFAULT;
934 	}
935 
936 	if (ps_mode)
937 		vwrq->disabled = 0;
938 	else
939 		vwrq->disabled = 1;
940 
941 	vwrq->value = 0;
942 
943 	LEAVE();
944 	return ret;
945 }
946 
947 /**
948  *  @brief Set Tx retry count
949  *
950  *  @param dev                  A pointer to net_device structure
951  *  @param info                 A pointer to iw_request_info structure
952  *  @param vwrq                 A pointer to iw_param structure
953  *  @param extra                A pointer to extra data buf
954  *
955  *  @return                     0 --success, otherwise fail
956  */
woal_set_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)957 static int woal_set_retry(struct net_device *dev, struct iw_request_info *info,
958 			  struct iw_param *vwrq, char *extra)
959 {
960 	int ret = 0, retry_val = vwrq->value;
961 	moal_private *priv = (moal_private *)netdev_priv(dev);
962 
963 	ENTER();
964 
965 	if (vwrq->flags == IW_RETRY_LIMIT) {
966 		/*
967 		 * The MAC has a 4-bit Total_Tx_Count register
968 		 * Total_Tx_Count = 1 + Tx_Retry_Count
969 		 */
970 
971 		if (MLAN_STATUS_SUCCESS !=
972 		    woal_set_get_retry(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
973 				       &retry_val)) {
974 			ret = -EFAULT;
975 			goto done;
976 		}
977 	} else {
978 		ret = -EOPNOTSUPP;
979 		goto done;
980 	}
981 
982 done:
983 	LEAVE();
984 	return ret;
985 }
986 
987 /**
988  *  @brief Get Tx retry count
989  *
990  *  @param dev                  A pointer to net_device structure
991  *  @param info                 A pointer to iw_request_info structure
992  *  @param vwrq                 A pointer to iw_param structure
993  *  @param extra                A pointer to extra data buf
994  *
995  *  @return                     0 --success, otherwise fail
996  */
woal_get_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)997 static int woal_get_retry(struct net_device *dev, struct iw_request_info *info,
998 			  struct iw_param *vwrq, char *extra)
999 {
1000 	int retry_val, ret = 0;
1001 	moal_private *priv = (moal_private *)netdev_priv(dev);
1002 
1003 	ENTER();
1004 
1005 	if (MLAN_STATUS_SUCCESS != woal_set_get_retry(priv, MLAN_ACT_GET,
1006 						      MOAL_IOCTL_WAIT,
1007 						      &retry_val)) {
1008 		ret = -EFAULT;
1009 		goto done;
1010 	}
1011 
1012 	vwrq->disabled = 0;
1013 	if (!vwrq->flags) {
1014 		vwrq->flags = IW_RETRY_LIMIT;
1015 		/* Get Tx retry count */
1016 		vwrq->value = retry_val;
1017 	}
1018 
1019 done:
1020 	LEAVE();
1021 	return ret;
1022 }
1023 
1024 /**
1025  *  @brief Set encryption key
1026  *
1027  *  @param dev                  A pointer to net_device structure
1028  *  @param info                 A pointer to iw_request_info structure
1029  *  @param dwrq                 A pointer to iw_point structure
1030  *  @param extra                A pointer to extra data buf
1031  *
1032  *  @return                     0 --success, otherwise fail
1033  */
woal_set_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1034 static int woal_set_encode(struct net_device *dev, struct iw_request_info *info,
1035 			   struct iw_point *dwrq, char *extra)
1036 {
1037 	int ret = 0;
1038 	moal_private *priv = (moal_private *)netdev_priv(dev);
1039 	mlan_ds_sec_cfg *sec = NULL;
1040 	mlan_ioctl_req *req = NULL;
1041 	int index = 0;
1042 	t_u32 auth_mode = 0;
1043 	mlan_status status = MLAN_STATUS_SUCCESS;
1044 
1045 	ENTER();
1046 
1047 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1048 	if (req == NULL) {
1049 		ret = -ENOMEM;
1050 		goto done;
1051 	}
1052 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1053 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1054 	req->req_id = MLAN_IOCTL_SEC_CFG;
1055 	req->action = MLAN_ACT_SET;
1056 
1057 	/* Check index */
1058 	index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1059 	if (index > 3) {
1060 		PRINTM(MERROR, "Key index #%d out of range\n", index);
1061 		ret = -EINVAL;
1062 		goto done;
1063 	}
1064 
1065 	sec->param.encrypt_key.key_len = 0;
1066 	if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
1067 		if (dwrq->length > MAX_WEP_KEY_SIZE) {
1068 			PRINTM(MERROR, "Key length (%d) out of range\n",
1069 			       dwrq->length);
1070 			ret = -EINVAL;
1071 			goto done;
1072 		}
1073 		if (index < 0)
1074 			sec->param.encrypt_key.key_index =
1075 				MLAN_KEY_INDEX_DEFAULT;
1076 		else
1077 			sec->param.encrypt_key.key_index = index;
1078 		moal_memcpy_ext(priv->phandle,
1079 				sec->param.encrypt_key.key_material, extra,
1080 				dwrq->length,
1081 				sizeof(sec->param.encrypt_key.key_material));
1082 		/* Set the length */
1083 		if (dwrq->length > MIN_WEP_KEY_SIZE)
1084 			sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
1085 		else
1086 			sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
1087 	} else {
1088 		/*
1089 		 * No key provided so it is either enable key,
1090 		 * on or off
1091 		 */
1092 		if (dwrq->flags & IW_ENCODE_DISABLED) {
1093 			PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
1094 			sec->param.encrypt_key.key_disable = MTRUE;
1095 		} else {
1096 			/*
1097 			 * iwconfig mlanX key [n]
1098 			 * iwconfig mlanX key on
1099 			 * iwconfig mlanX key open
1100 			 * iwconfig mlanX key restricted
1101 			 * Do we want to just set the transmit key index ?
1102 			 */
1103 			if (index < 0) {
1104 				PRINTM(MINFO,
1105 				       "*** iwconfig mlanX key on ***\n");
1106 				sec->param.encrypt_key.key_index =
1107 					MLAN_KEY_INDEX_DEFAULT;
1108 			} else
1109 				sec->param.encrypt_key.key_index = index;
1110 			sec->param.encrypt_key.is_current_wep_key = MTRUE;
1111 		}
1112 	}
1113 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1114 	if (status != MLAN_STATUS_SUCCESS) {
1115 		ret = -EFAULT;
1116 		goto done;
1117 	}
1118 	if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
1119 		switch (dwrq->flags & 0xf000) {
1120 		case IW_ENCODE_RESTRICTED:
1121 			/* iwconfig mlanX restricted key [1] */
1122 			auth_mode = MLAN_AUTH_MODE_SHARED;
1123 			PRINTM(MINFO, "Auth mode restricted!\n");
1124 			break;
1125 		case IW_ENCODE_OPEN:
1126 			/* iwconfig mlanX key [2] open */
1127 			auth_mode = MLAN_AUTH_MODE_OPEN;
1128 			PRINTM(MINFO, "Auth mode open!\n");
1129 			break;
1130 		case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
1131 		default:
1132 			/* iwconfig mlanX key [2] open restricted */
1133 			auth_mode = MLAN_AUTH_MODE_AUTO;
1134 			PRINTM(MINFO, "Auth mode auto!\n");
1135 			break;
1136 		}
1137 		if (MLAN_STATUS_SUCCESS !=
1138 		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
1139 			ret = -EFAULT;
1140 	}
1141 done:
1142 	if (status != MLAN_STATUS_PENDING)
1143 		kfree(req);
1144 	LEAVE();
1145 	return ret;
1146 }
1147 
1148 /**
1149  *  @brief Get encryption key
1150  *
1151  *  @param dev                  A pointer to net_device structure
1152  *  @param info                 A pointer to iw_request_info structure
1153  *  @param dwrq                 A pointer to iw_point structure
1154  *  @param extra                A pointer to extra data buf
1155  *
1156  *  @return                     0 --success, otherwise fail
1157  */
woal_get_encode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1158 static int woal_get_encode(struct net_device *dev, struct iw_request_info *info,
1159 			   union iwreq_data *wrqu, char *extra)
1160 {
1161 	int ret = 0;
1162 	moal_private *priv = (moal_private *)netdev_priv(dev);
1163 	struct iw_point *dwrq = &wrqu->data;
1164 	mlan_ds_sec_cfg *sec = NULL;
1165 	mlan_ioctl_req *req = NULL;
1166 	t_u32 auth_mode;
1167 	int index = (dwrq->flags & IW_ENCODE_INDEX);
1168 	mlan_status status = MLAN_STATUS_SUCCESS;
1169 
1170 	ENTER();
1171 	if (index < 0 || index > 4) {
1172 		PRINTM(MERROR, "Key index #%d out of range\n", index);
1173 		ret = -EINVAL;
1174 		goto done;
1175 	}
1176 	if (MLAN_STATUS_SUCCESS !=
1177 	    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
1178 		ret = -EFAULT;
1179 		goto done;
1180 	}
1181 	dwrq->flags = 0;
1182 	/*
1183 	 * Check encryption mode
1184 	 */
1185 	switch (auth_mode) {
1186 	case MLAN_AUTH_MODE_OPEN:
1187 		dwrq->flags = IW_ENCODE_OPEN;
1188 		break;
1189 
1190 	case MLAN_AUTH_MODE_SHARED:
1191 	case MLAN_AUTH_MODE_NETWORKEAP:
1192 		dwrq->flags = IW_ENCODE_RESTRICTED;
1193 		break;
1194 
1195 	case MLAN_AUTH_MODE_AUTO:
1196 		dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED;
1197 		break;
1198 
1199 	default:
1200 		dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1201 		break;
1202 	}
1203 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1204 	if (req == NULL) {
1205 		ret = -ENOMEM;
1206 		goto done;
1207 	}
1208 
1209 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1210 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1211 	req->req_id = MLAN_IOCTL_SEC_CFG;
1212 	req->action = MLAN_ACT_GET;
1213 
1214 	if (!index)
1215 		sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
1216 	else
1217 		sec->param.encrypt_key.key_index = index - 1;
1218 
1219 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1220 	if (status != MLAN_STATUS_SUCCESS) {
1221 		ret = -EFAULT;
1222 		goto done;
1223 	}
1224 	memset(extra, 0, 16);
1225 	if (sec->param.encrypt_key.key_len) {
1226 		moal_memcpy_ext(priv->phandle, extra,
1227 				sec->param.encrypt_key.key_material,
1228 				sec->param.encrypt_key.key_len,
1229 				sec->param.encrypt_key.key_len);
1230 		dwrq->length = sec->param.encrypt_key.key_len;
1231 		dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
1232 		dwrq->flags &= ~IW_ENCODE_DISABLED;
1233 	} else if (sec->param.encrypt_key.key_disable)
1234 		dwrq->flags |= IW_ENCODE_DISABLED;
1235 	else
1236 		dwrq->flags &= ~IW_ENCODE_DISABLED;
1237 
1238 	dwrq->flags |= IW_ENCODE_NOKEY;
1239 done:
1240 	if (status != MLAN_STATUS_PENDING)
1241 		kfree(req);
1242 	LEAVE();
1243 	return ret;
1244 }
1245 
1246 /**
1247  *  @brief Set data rate
1248  *
1249  *  @param dev          A pointer to net_device structure
1250  *  @param info         A pointer to iw_request_info structure
1251  *  @param vwrq         A pointer to iw_param structure
1252  *  @param extra        A pointer to extra data buf
1253  *
1254  *  @return             0 --success, otherwise fail
1255  */
woal_set_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1256 static int woal_set_rate(struct net_device *dev, struct iw_request_info *info,
1257 			 struct iw_param *vwrq, char *extra)
1258 {
1259 	int ret = 0;
1260 	moal_private *priv = (moal_private *)netdev_priv(dev);
1261 	mlan_rate_cfg_t rate_cfg;
1262 
1263 	ENTER();
1264 
1265 	if (vwrq->value == -1) {
1266 		rate_cfg.is_rate_auto = 1;
1267 	} else {
1268 		rate_cfg.is_rate_auto = 0;
1269 		rate_cfg.rate_type = MLAN_RATE_VALUE;
1270 		rate_cfg.rate = vwrq->value / 500000;
1271 	}
1272 	if (MLAN_STATUS_SUCCESS !=
1273 	    woal_set_get_data_rate(priv, MLAN_ACT_SET, &rate_cfg)) {
1274 		ret = -EFAULT;
1275 	}
1276 
1277 	LEAVE();
1278 	return ret;
1279 }
1280 
1281 /**
1282  *  @brief Get data rate
1283  *
1284  *  @param dev          A pointer to net_device structure
1285  *  @param info         A pointer to iw_request_info structure
1286  *  @param vwrq         A pointer to iw_param structure
1287  *  @param extra        A pointer to extra data buf
1288  *
1289  *  @return             0 --success, otherwise fail
1290  */
woal_get_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1291 static int woal_get_rate(struct net_device *dev, struct iw_request_info *info,
1292 			 struct iw_param *vwrq, char *extra)
1293 {
1294 	int ret = 0;
1295 	moal_private *priv = (moal_private *)netdev_priv(dev);
1296 	mlan_rate_cfg_t rate_cfg;
1297 
1298 	ENTER();
1299 
1300 	if (MLAN_STATUS_SUCCESS !=
1301 	    woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate_cfg)) {
1302 		ret = -EFAULT;
1303 		goto done;
1304 	}
1305 
1306 	if (rate_cfg.is_rate_auto)
1307 		vwrq->fixed = 0;
1308 	else
1309 		vwrq->fixed = 1;
1310 	vwrq->value = rate_cfg.rate * 500000;
1311 done:
1312 	LEAVE();
1313 	return ret;
1314 }
1315 
1316 /**
1317  *  @brief Set RTS threshold
1318  *
1319  *  @param dev                  A pointer to net_device structure
1320  *  @param info                 A pointer to iw_request_info structure
1321  *  @param vwrq                 A pointer to iw_param structure
1322  *  @param extra                A pointer to extra data buf
1323  *
1324  *  @return                     0 --success, otherwise fail
1325  */
woal_set_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1326 static int woal_set_rts(struct net_device *dev, struct iw_request_info *info,
1327 			struct iw_param *vwrq, char *extra)
1328 {
1329 	int ret = 0;
1330 	moal_private *priv = (moal_private *)netdev_priv(dev);
1331 	int rthr = vwrq->value;
1332 
1333 	ENTER();
1334 
1335 	if (vwrq->disabled) {
1336 		rthr = MLAN_RTS_MAX_VALUE;
1337 	} else {
1338 		if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
1339 			ret = -EINVAL;
1340 			goto done;
1341 		}
1342 	}
1343 
1344 	if (MLAN_STATUS_SUCCESS !=
1345 	    woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) {
1346 		ret = -EFAULT;
1347 		goto done;
1348 	}
1349 
1350 done:
1351 	LEAVE();
1352 	return ret;
1353 }
1354 
1355 /**
1356  *  @brief Get RTS threshold
1357  *
1358  *  @param dev                  A pointer to net_device structure
1359  *  @param info                 A pointer to iw_request_info structure
1360  *  @param vwrq                 A pointer to iw_param structure
1361  *  @param extra                A pointer to extra data buf
1362  *
1363  *  @return                     0 --success, otherwise fail
1364  */
woal_get_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1365 static int woal_get_rts(struct net_device *dev, struct iw_request_info *info,
1366 			struct iw_param *vwrq, char *extra)
1367 {
1368 	int rthr, ret = 0;
1369 	moal_private *priv = (moal_private *)netdev_priv(dev);
1370 
1371 	ENTER();
1372 
1373 	if (MLAN_STATUS_SUCCESS !=
1374 	    woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) {
1375 		ret = -EFAULT;
1376 		goto done;
1377 	}
1378 
1379 	vwrq->value = rthr;
1380 	vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE) ||
1381 			  (vwrq->value > MLAN_RTS_MAX_VALUE));
1382 	vwrq->fixed = 1;
1383 
1384 done:
1385 	LEAVE();
1386 	return ret;
1387 }
1388 
1389 /**
1390  *  @brief Set Fragment threshold
1391  *
1392  *  @param dev                  A pointer to net_device structure
1393  *  @param info                 A pointer to iw_request_info structure
1394  *  @param vwrq                 A pointer to iw_param structure
1395  *  @param extra                A pointer to extra data buf
1396  *
1397  *  @return                     0 --success, otherwise fail
1398  */
woal_set_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1399 static int woal_set_frag(struct net_device *dev, struct iw_request_info *info,
1400 			 struct iw_param *vwrq, char *extra)
1401 {
1402 	int ret = 0;
1403 	moal_private *priv = (moal_private *)netdev_priv(dev);
1404 	int fthr = vwrq->value;
1405 
1406 	ENTER();
1407 
1408 	if (vwrq->disabled) {
1409 		fthr = MLAN_FRAG_MAX_VALUE;
1410 	} else {
1411 		if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
1412 			ret = -EINVAL;
1413 			goto done;
1414 		}
1415 	}
1416 
1417 	if (MLAN_STATUS_SUCCESS !=
1418 	    woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) {
1419 		ret = -EFAULT;
1420 		goto done;
1421 	}
1422 
1423 done:
1424 	LEAVE();
1425 	return ret;
1426 }
1427 
1428 /**
1429  *  @brief Get Fragment threshold
1430  *
1431  *  @param dev                  A pointer to net_device structure
1432  *  @param info                 A pointer to iw_request_info structure
1433  *  @param vwrq                 A pointer to iw_param structure
1434  *  @param extra                A pointer to extra data buf
1435  *
1436  *  @return                     0 --success, otherwise fail
1437  */
woal_get_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1438 static int woal_get_frag(struct net_device *dev, struct iw_request_info *info,
1439 			 struct iw_param *vwrq, char *extra)
1440 {
1441 	int ret = 0, fthr;
1442 	moal_private *priv = (moal_private *)netdev_priv(dev);
1443 
1444 	ENTER();
1445 
1446 	if (MLAN_STATUS_SUCCESS !=
1447 	    woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) {
1448 		ret = -EFAULT;
1449 		goto done;
1450 	}
1451 
1452 	vwrq->value = fthr;
1453 	vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE) ||
1454 			  (vwrq->value > MLAN_FRAG_MAX_VALUE));
1455 	vwrq->fixed = 1;
1456 
1457 done:
1458 	LEAVE();
1459 	return ret;
1460 }
1461 
1462 #if (WIRELESS_EXT >= 18)
1463 /**
1464  *  @brief Get IE
1465  *
1466  *  @param dev                  A pointer to net_device structure
1467  *  @param info                 A pointer to iw_request_info structure
1468  *  @param dwrq                 A pointer to iw_point structure
1469  *  @param extra                A pointer to extra data buf
1470  *
1471  *  @return                     0 --success, otherwise fail
1472  */
woal_get_gen_ie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1473 static int woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
1474 			   union iwreq_data *wrqu, char *extra)
1475 {
1476 	int ret = 0;
1477 	moal_private *priv = (moal_private *)netdev_priv(dev);
1478 	struct iw_point *dwrq = &wrqu->data;
1479 	int copy_size = 0, ie_len;
1480 	t_u8 ie[MAX_IE_SIZE];
1481 
1482 	ENTER();
1483 
1484 	if (MLAN_STATUS_SUCCESS != woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie,
1485 						       &ie_len,
1486 						       MOAL_IOCTL_WAIT)) {
1487 		ret = -EFAULT;
1488 		goto done;
1489 	}
1490 
1491 	copy_size = MIN(ie_len, dwrq->length);
1492 	moal_memcpy_ext(priv->phandle, extra, ie, copy_size, copy_size);
1493 	dwrq->length = copy_size;
1494 
1495 done:
1496 	LEAVE();
1497 	return ret;
1498 }
1499 
1500 /**
1501  *  @brief Set IE
1502  *
1503  *  Pass an opaque block of data, expected to be IEEE IEs, to the driver
1504  *    for eventual passthrough to the firmware in an associate/join
1505  *    (and potentially start) command.
1506  *
1507  *  @param dev                  A pointer to net_device structure
1508  *  @param info                 A pointer to iw_request_info structure
1509  *  @param dwrq                 A pointer to iw_point structure
1510  *  @param extra                A pointer to extra data buf
1511  *
1512  *  @return                     0 --success, otherwise fail
1513  */
woal_set_gen_ie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1514 static int woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
1515 			   union iwreq_data *wrqu, char *extra)
1516 {
1517 	int ret = 0;
1518 	moal_private *priv = (moal_private *)netdev_priv(dev);
1519 	struct iw_point *dwrq = &wrqu->data;
1520 	int ie_len = dwrq->length;
1521 	const t_u8 wps_oui[] = {0x00, 0x50, 0xf2, 0x04};
1522 	mlan_ds_wps_cfg *pwps = NULL;
1523 	mlan_ioctl_req *req = NULL;
1524 	mlan_status status = MLAN_STATUS_SUCCESS;
1525 
1526 	ENTER();
1527 
1528 	/* extra + 2 to skip element id and length */
1529 	if (!memcmp((t_u8 *)(extra + 2), wps_oui, sizeof(wps_oui))) {
1530 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
1531 		if (req == NULL) {
1532 			ret = -ENOMEM;
1533 			goto done;
1534 		}
1535 
1536 		pwps = (mlan_ds_wps_cfg *)req->pbuf;
1537 		req->req_id = MLAN_IOCTL_WPS_CFG;
1538 		req->action = MLAN_ACT_SET;
1539 		pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
1540 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
1541 
1542 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1543 		if (status != MLAN_STATUS_SUCCESS) {
1544 			ret = -EFAULT;
1545 			goto done;
1546 		}
1547 	}
1548 
1549 	if (MLAN_STATUS_SUCCESS != woal_set_get_gen_ie(priv, MLAN_ACT_SET,
1550 						       (t_u8 *)extra, &ie_len,
1551 						       MOAL_IOCTL_WAIT)) {
1552 		ret = -EFAULT;
1553 		goto done;
1554 	}
1555 
1556 done:
1557 	if (status != MLAN_STATUS_PENDING)
1558 		kfree(req);
1559 
1560 	LEAVE();
1561 	return ret;
1562 }
1563 
1564 /**
1565  *  @brief  Extended version of encoding configuration
1566  *
1567  *  @param dev          A pointer to net_device structure
1568  *  @param info         A pointer to iw_request_info structure
1569  *  @param dwrq         A pointer to iw_point structure
1570  *  @param extra        A pointer to extra data buf
1571  *
1572  *  @return              0 --success, otherwise fail
1573  */
woal_set_encode_ext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1574 static int woal_set_encode_ext(struct net_device *dev,
1575 			       struct iw_request_info *info,
1576 			       union iwreq_data *wrqu, char *extra)
1577 {
1578 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1579 	moal_private *priv = (moal_private *)netdev_priv(dev);
1580 	struct iw_point *dwrq = &wrqu->data;
1581 	int key_index;
1582 	t_u8 *pkey_material = NULL;
1583 	mlan_ioctl_req *req = NULL;
1584 	mlan_ds_sec_cfg *sec = NULL;
1585 	int ret = 0;
1586 	mlan_status status = MLAN_STATUS_SUCCESS;
1587 
1588 	ENTER();
1589 	key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1590 	if (key_index < 0 || key_index > 5) {
1591 		ret = -EINVAL;
1592 		goto done;
1593 	}
1594 	if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
1595 		ret = -EINVAL;
1596 		goto done;
1597 	}
1598 	if (ext->key_len > (MLAN_MAX_KEY_LENGTH)) {
1599 		ret = -EINVAL;
1600 		goto done;
1601 	}
1602 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1603 	if (req == NULL) {
1604 		ret = -ENOMEM;
1605 		goto done;
1606 	}
1607 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1608 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1609 	req->req_id = MLAN_IOCTL_SEC_CFG;
1610 	req->action = MLAN_ACT_SET;
1611 	pkey_material = (t_u8 *)(ext + 1);
1612 	sec->param.encrypt_key.key_len = ext->key_len;
1613 	moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
1614 			(u8 *)ext->addr.sa_data, ETH_ALEN,
1615 			sizeof(sec->param.encrypt_key.mac_addr));
1616 	/* Disable and Remove Key */
1617 	if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
1618 		sec->param.encrypt_key.key_remove = MTRUE;
1619 		sec->param.encrypt_key.key_index = key_index;
1620 		sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
1621 		PRINTM(MIOCTL,
1622 		       "Remove key key_index=%d, dwrq->flags=0x%x " MACSTR "\n",
1623 		       key_index, dwrq->flags,
1624 		       MAC2STR(sec->param.encrypt_key.mac_addr));
1625 	} else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
1626 		/* Set WEP key */
1627 		sec->param.encrypt_key.key_index = key_index;
1628 		sec->param.encrypt_key.key_flags = ext->ext_flags;
1629 		moal_memcpy_ext(priv->phandle,
1630 				sec->param.encrypt_key.key_material,
1631 				pkey_material, ext->key_len,
1632 				sizeof(sec->param.encrypt_key.key_material));
1633 		if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
1634 			sec->param.encrypt_key.is_current_wep_key = MTRUE;
1635 	} else {
1636 		/* Set WPA key */
1637 		sec->param.encrypt_key.key_index = key_index;
1638 		sec->param.encrypt_key.key_flags = ext->ext_flags;
1639 		if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
1640 			moal_memcpy_ext(priv->phandle,
1641 					sec->param.encrypt_key.pn,
1642 					(t_u8 *)ext->rx_seq, SEQ_MAX_SIZE,
1643 					sizeof(sec->param.encrypt_key.pn));
1644 			DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn,
1645 				    SEQ_MAX_SIZE);
1646 		}
1647 		if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
1648 			moal_memcpy_ext(priv->phandle,
1649 					sec->param.encrypt_key.pn,
1650 					(t_u8 *)ext->tx_seq, SEQ_MAX_SIZE,
1651 					sizeof(sec->param.encrypt_key.pn));
1652 			DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn,
1653 				    SEQ_MAX_SIZE);
1654 		}
1655 		moal_memcpy_ext(priv->phandle,
1656 				sec->param.encrypt_key.key_material,
1657 				pkey_material, ext->key_len,
1658 				sizeof(sec->param.encrypt_key.key_material));
1659 		PRINTM(MIOCTL,
1660 		       "set wpa key key_index=%d, key_len=%d key_flags=0x%x " MACSTR
1661 		       "\n",
1662 		       key_index, ext->key_len,
1663 		       sec->param.encrypt_key.key_flags,
1664 		       MAC2STR(sec->param.encrypt_key.mac_addr));
1665 		DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len);
1666 #define IW_ENCODE_ALG_AES_CMAC 5
1667 		if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
1668 			sec->param.encrypt_key.key_flags |=
1669 				KEY_FLAG_AES_MCAST_IGTK;
1670 #define IW_ENCODE_ALG_SMS4 0x20
1671 		/* Set WAPI key */
1672 		if (ext->alg == IW_ENCODE_ALG_SMS4) {
1673 			sec->param.encrypt_key.is_wapi_key = MTRUE;
1674 			moal_memcpy_ext(priv->phandle,
1675 					sec->param.encrypt_key.pn,
1676 					(t_u8 *)ext->tx_seq, SEQ_MAX_SIZE,
1677 					sizeof(sec->param.encrypt_key.pn));
1678 			moal_memcpy_ext(
1679 				priv->phandle,
1680 				&sec->param.encrypt_key.pn[SEQ_MAX_SIZE],
1681 				(t_u8 *)ext->rx_seq, SEQ_MAX_SIZE,
1682 				sizeof(sec->param.encrypt_key.pn) -
1683 					SEQ_MAX_SIZE);
1684 			DBG_HEXDUMP(MCMD_D, "WAPI PN",
1685 				    sec->param.encrypt_key.pn, PN_SIZE);
1686 		}
1687 	}
1688 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1689 	if (status != MLAN_STATUS_SUCCESS)
1690 		ret = -EFAULT;
1691 done:
1692 	if (status != MLAN_STATUS_PENDING)
1693 		kfree(req);
1694 	LEAVE();
1695 	return ret;
1696 }
1697 
1698 /**
1699  *  @brief  Extended version of encoding configuration
1700  *
1701  *  @param dev          A pointer to net_device structure
1702  *  @param info         A pointer to iw_request_info structure
1703  *  @param dwrq         A pointer to iw_point structure
1704  *  @param extra        A pointer to extra data buf
1705  *
1706  *  @return             -EOPNOTSUPP
1707  */
woal_get_encode_ext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1708 static int woal_get_encode_ext(struct net_device *dev,
1709 			       struct iw_request_info *info,
1710 			       union iwreq_data *wrqu, char *extra)
1711 {
1712 	ENTER();
1713 	LEAVE();
1714 	return -EOPNOTSUPP;
1715 }
1716 
1717 /**
1718  *  @brief  Request MLME operation
1719  *
1720  *  @param dev          A pointer to net_device structure
1721  *  @param info         A pointer to iw_request_info structure
1722  *  @param dwrq         A pointer to iw_point structure
1723  *  @param extra        A pointer to extra data buf
1724  *
1725  *  @return             0--success, otherwise fail
1726  */
woal_set_mlme(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1727 static int woal_set_mlme(struct net_device *dev, struct iw_request_info *info,
1728 			 union iwreq_data *wrqu, char *extra)
1729 {
1730 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
1731 	moal_private *priv = (moal_private *)netdev_priv(dev);
1732 	int ret = 0;
1733 
1734 	ENTER();
1735 	if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
1736 		if (MLAN_STATUS_SUCCESS !=
1737 		    woal_disconnect(priv, MOAL_IOCTL_WAIT,
1738 				    (t_u8 *)mlme->addr.sa_data,
1739 				    DEF_DEAUTH_REASON_CODE))
1740 			ret = -EFAULT;
1741 	}
1742 	LEAVE();
1743 	return ret;
1744 }
1745 
1746 /** @brief Set authentication mode parameters
1747  *
1748  *  @param dev                  A pointer to net_device structure
1749  *  @param info                 A pointer to iw_request_info structure
1750  *  @param vwrq                 A pointer to iw_param structure
1751  *  @param extra                A pointer to extra data buf
1752  *
1753  *  @return                     0 --success, otherwise fail
1754  */
woal_set_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1755 static int woal_set_auth(struct net_device *dev, struct iw_request_info *info,
1756 			 union iwreq_data *wrqu, char *extra)
1757 {
1758 	int ret = 0;
1759 	moal_private *priv = (moal_private *)netdev_priv(dev);
1760 	struct iw_param *vwrq = &wrqu->param;
1761 	t_u32 auth_mode = 0;
1762 	t_u32 encrypt_mode = 0;
1763 	ENTER();
1764 
1765 	switch (vwrq->flags & IW_AUTH_INDEX) {
1766 	case IW_AUTH_CIPHER_PAIRWISE:
1767 	case IW_AUTH_CIPHER_GROUP:
1768 		if (vwrq->value & IW_AUTH_CIPHER_NONE)
1769 			encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
1770 		else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
1771 			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
1772 		else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
1773 			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
1774 		else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
1775 			encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
1776 		else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
1777 			encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
1778 		if (MLAN_STATUS_SUCCESS !=
1779 		    woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
1780 			ret = -EFAULT;
1781 		break;
1782 	case IW_AUTH_80211_AUTH_ALG:
1783 		switch (vwrq->value) {
1784 		case IW_AUTH_ALG_SHARED_KEY:
1785 			PRINTM(MINFO, "Auth mode shared key!\n");
1786 			auth_mode = MLAN_AUTH_MODE_SHARED;
1787 			break;
1788 		case IW_AUTH_ALG_LEAP:
1789 			PRINTM(MINFO, "Auth mode LEAP!\n");
1790 			auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
1791 			break;
1792 		case IW_AUTH_ALG_OPEN_SYSTEM:
1793 			PRINTM(MINFO, "Auth mode open!\n");
1794 			auth_mode = MLAN_AUTH_MODE_OPEN;
1795 			break;
1796 		case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM:
1797 		default:
1798 			PRINTM(MINFO, "Auth mode auto!\n");
1799 			auth_mode = MLAN_AUTH_MODE_AUTO;
1800 			break;
1801 		}
1802 		if (MLAN_STATUS_SUCCESS !=
1803 		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
1804 			ret = -EFAULT;
1805 		break;
1806 	case IW_AUTH_WPA_ENABLED:
1807 		if (MLAN_STATUS_SUCCESS !=
1808 		    woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
1809 			ret = -EFAULT;
1810 		break;
1811 #define IW_AUTH_WAPI_ENABLED 0x20
1812 	case IW_AUTH_WAPI_ENABLED:
1813 		if (MLAN_STATUS_SUCCESS !=
1814 		    woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
1815 			ret = -EFAULT;
1816 		break;
1817 	case IW_AUTH_WPA_VERSION:
1818 		/* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
1819 		priv->wpa_version = vwrq->value;
1820 		break;
1821 	case IW_AUTH_KEY_MGMT:
1822 		/* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
1823 		priv->key_mgmt = vwrq->value;
1824 		break;
1825 	case IW_AUTH_TKIP_COUNTERMEASURES:
1826 	case IW_AUTH_DROP_UNENCRYPTED:
1827 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1828 	case IW_AUTH_ROAMING_CONTROL:
1829 	case IW_AUTH_PRIVACY_INVOKED:
1830 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1831 	case IW_AUTH_MFP:
1832 #endif
1833 		break;
1834 	default:
1835 		ret = -EOPNOTSUPP;
1836 		break;
1837 	}
1838 	LEAVE();
1839 	return ret;
1840 }
1841 
1842 /**
1843  *  @brief Get authentication mode parameters
1844  *
1845  *  @param dev                  A pointer to net_device structure
1846  *  @param info                 A pointer to iw_request_info structure
1847  *  @param vwrq                 A pointer to iw_param structure
1848  *  @param extra                A pointer to extra data buf
1849  *
1850  *  @return                     0 --success, otherwise fail
1851  */
woal_get_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1852 static int woal_get_auth(struct net_device *dev, struct iw_request_info *info,
1853 			 union iwreq_data *wrqu, char *extra)
1854 {
1855 	int ret = 0;
1856 	moal_private *priv = (moal_private *)netdev_priv(dev);
1857 	struct iw_param *vwrq = &wrqu->param;
1858 	t_u32 encrypt_mode = 0;
1859 	t_u32 auth_mode;
1860 	t_u32 wpa_enable;
1861 	ENTER();
1862 	switch (vwrq->flags & IW_AUTH_INDEX) {
1863 	case IW_AUTH_CIPHER_PAIRWISE:
1864 	case IW_AUTH_CIPHER_GROUP:
1865 		if (MLAN_STATUS_SUCCESS !=
1866 		    woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
1867 			ret = -EFAULT;
1868 		else {
1869 			if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
1870 				vwrq->value = IW_AUTH_CIPHER_NONE;
1871 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
1872 				vwrq->value = IW_AUTH_CIPHER_WEP40;
1873 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
1874 				vwrq->value = IW_AUTH_CIPHER_TKIP;
1875 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
1876 				vwrq->value = IW_AUTH_CIPHER_CCMP;
1877 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
1878 				vwrq->value = IW_AUTH_CIPHER_WEP104;
1879 		}
1880 		break;
1881 	case IW_AUTH_80211_AUTH_ALG:
1882 		if (MLAN_STATUS_SUCCESS !=
1883 		    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
1884 			ret = -EFAULT;
1885 		else {
1886 			if (auth_mode == MLAN_AUTH_MODE_SHARED)
1887 				vwrq->value = IW_AUTH_ALG_SHARED_KEY;
1888 			else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
1889 				vwrq->value = IW_AUTH_ALG_LEAP;
1890 			else
1891 				vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
1892 		}
1893 		break;
1894 	case IW_AUTH_WPA_ENABLED:
1895 		if (MLAN_STATUS_SUCCESS !=
1896 		    woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
1897 			ret = -EFAULT;
1898 		else
1899 			vwrq->value = wpa_enable;
1900 		break;
1901 	case IW_AUTH_WPA_VERSION:
1902 		vwrq->value = priv->wpa_version;
1903 		break;
1904 	case IW_AUTH_KEY_MGMT:
1905 		vwrq->value = priv->key_mgmt;
1906 		break;
1907 	case IW_AUTH_TKIP_COUNTERMEASURES:
1908 	case IW_AUTH_DROP_UNENCRYPTED:
1909 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1910 	case IW_AUTH_ROAMING_CONTROL:
1911 	case IW_AUTH_PRIVACY_INVOKED:
1912 	default:
1913 		ret = -EOPNOTSUPP;
1914 		goto done;
1915 	}
1916 
1917 done:
1918 	LEAVE();
1919 	return ret;
1920 }
1921 
1922 /**
1923  *  @brief Set PMKSA Cache
1924  *
1925  *  @param dev      A pointer to net_device structure
1926  *  @param info     A pointer to iw_request_info structure
1927  *  @param vwrq     A pointer to iw_param structure
1928  *  @param extra    A pointer to extra data buf
1929  *
1930  *  @return         -EOPNOTSUPP
1931  */
woal_set_pmksa(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1932 static int woal_set_pmksa(struct net_device *dev, struct iw_request_info *info,
1933 			  struct iw_param *vwrq, char *extra)
1934 {
1935 	ENTER();
1936 	LEAVE();
1937 	return -EOPNOTSUPP;
1938 }
1939 
1940 #endif /* WE >= 18 */
1941 
1942 /* Data rate listing
1943  *      MULTI_BANDS:
1944  *              abg             a       b       b/g
1945  *  Infra       G(12)           A(8)    B(4)    G(12)
1946  *  Adhoc       A+B(12)         A(8)    B(4)    B(4)
1947  *      non-MULTI_BANDS:
1948 										b       b/g
1949  *  Infra                               B(4)    G(12)
1950  *  Adhoc                               B(4)    B(4)
1951  */
1952 /**
1953  *  @brief Get Range Info
1954  *
1955  *  @param dev                  A pointer to net_device structure
1956  *  @param info                 A pointer to iw_request_info structure
1957  *  @param dwrq                 A pointer to iw_point structure
1958  *  @param extra                A pointer to extra data buf
1959  *
1960  *  @return                     0 --success, otherwise fail
1961  */
woal_get_range(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1962 static int woal_get_range(struct net_device *dev, struct iw_request_info *info,
1963 			  union iwreq_data *wrqu, char *extra)
1964 {
1965 	int i;
1966 	moal_private *priv = (moal_private *)netdev_priv(dev);
1967 	struct iw_point *dwrq = &wrqu->data;
1968 	struct iw_range *range = (struct iw_range *)extra;
1969 	moal_802_11_rates rates;
1970 	mlan_chan_list *pchan_list = NULL;
1971 	mlan_bss_info bss_info;
1972 	gfp_t flag;
1973 
1974 	ENTER();
1975 
1976 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
1977 	pchan_list = kzalloc(sizeof(mlan_chan_list), flag);
1978 	if (!pchan_list) {
1979 		LEAVE();
1980 		return -ENOMEM;
1981 	}
1982 
1983 	dwrq->length = sizeof(struct iw_range);
1984 	memset(range, 0, sizeof(struct iw_range));
1985 
1986 	range->min_nwid = 0;
1987 	range->max_nwid = 0;
1988 
1989 	memset(&rates, 0, sizeof(rates));
1990 	woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
1991 	range->num_bitrates = rates.num_of_rates;
1992 
1993 	for (i = 0;
1994 	     i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
1995 	     i++) {
1996 		range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
1997 	}
1998 	range->num_bitrates = i;
1999 	PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
2000 	       range->num_bitrates);
2001 
2002 	range->num_frequency = 0;
2003 
2004 	woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list);
2005 
2006 	range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES);
2007 
2008 	for (i = 0; i < range->num_frequency; i++) {
2009 		range->freq[i].i = (long)pchan_list->cf[i].channel;
2010 		range->freq[i].m = (long)pchan_list->cf[i].freq * 100000;
2011 		range->freq[i].e = 1;
2012 	}
2013 	kfree(pchan_list);
2014 
2015 	PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
2016 	       IW_MAX_FREQUENCIES, range->num_frequency);
2017 
2018 	range->num_channels = range->num_frequency;
2019 
2020 	woal_sort_channels(&range->freq[0], range->num_frequency);
2021 
2022 	/*
2023 	 * Set an indication of the max TCP throughput in bit/s that we can
2024 	 * expect using this interface
2025 	 */
2026 	if (i > 2)
2027 		range->throughput = 5000 * 1000;
2028 	else
2029 		range->throughput = 1500 * 1000;
2030 
2031 	range->min_rts = MLAN_RTS_MIN_VALUE;
2032 	range->max_rts = MLAN_RTS_MAX_VALUE;
2033 	range->min_frag = MLAN_FRAG_MIN_VALUE;
2034 	range->max_frag = MLAN_FRAG_MAX_VALUE;
2035 
2036 	range->encoding_size[0] = 5;
2037 	range->encoding_size[1] = 13;
2038 	range->num_encoding_sizes = 2;
2039 	range->max_encoding_tokens = 4;
2040 
2041 /** Minimum power period */
2042 #define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
2043 /** Maximum power period */
2044 #define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
2045 /** Minimum power timeout value */
2046 #define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms  */
2047 /** Maximim power timeout value */
2048 #define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
2049 
2050 	/* Power Management duration & timeout */
2051 	range->min_pmp = IW_POWER_PERIOD_MIN;
2052 	range->max_pmp = IW_POWER_PERIOD_MAX;
2053 	range->min_pmt = IW_POWER_TIMEOUT_MIN;
2054 	range->max_pmt = IW_POWER_TIMEOUT_MAX;
2055 	range->pmp_flags = IW_POWER_PERIOD;
2056 	range->pmt_flags = IW_POWER_TIMEOUT;
2057 	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
2058 
2059 	/*
2060 	 * Minimum version we recommend
2061 	 */
2062 	range->we_version_source = 15;
2063 
2064 	/*
2065 	 * Version we are compiled with
2066 	 */
2067 	range->we_version_compiled = WIRELESS_EXT;
2068 
2069 	range->retry_capa = IW_RETRY_LIMIT;
2070 	range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
2071 
2072 	range->min_retry = MLAN_TX_RETRY_MIN;
2073 	range->max_retry = MLAN_TX_RETRY_MAX;
2074 
2075 	/*
2076 	 * Set the qual, level and noise range values
2077 	 */
2078 	/*
2079 	 * need to put the right values here
2080 	 */
2081 /** Maximum quality percentage */
2082 #define IW_MAX_QUAL_PERCENT 5
2083 /** Average quality percentage */
2084 #define IW_AVG_QUAL_PERCENT 3
2085 	range->max_qual.qual = IW_MAX_QUAL_PERCENT;
2086 	range->max_qual.level = 0;
2087 	range->max_qual.noise = 0;
2088 
2089 	range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
2090 	range->avg_qual.level = 0;
2091 	range->avg_qual.noise = 0;
2092 
2093 	range->sensitivity = 0;
2094 
2095 	/*
2096 	 * Setup the supported power level ranges
2097 	 */
2098 	memset(range->txpower, 0, sizeof(range->txpower));
2099 
2100 	memset(&bss_info, 0, sizeof(bss_info));
2101 
2102 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2103 
2104 	range->txpower[0] = bss_info.min_power_level;
2105 	range->txpower[1] = bss_info.max_power_level;
2106 	range->num_txpower = 2;
2107 	range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
2108 
2109 #if (WIRELESS_EXT >= 18)
2110 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
2111 			  IW_ENC_CAPA_CIPHER_CCMP | IW_ENC_CAPA_CIPHER_TKIP;
2112 #endif
2113 	LEAVE();
2114 	return 0;
2115 }
2116 
2117 #ifdef MEF_CFG_RX_FILTER
2118 /**
2119  *  @brief Enable/disable Rx broadcast/multicast filter in non-HS mode
2120  *
2121  *  @param priv                 A pointer to moal_private structure
2122  *  @param enable               MTRUE/MFALSE: enable/disable
2123  *
2124  *  @return                     0 -- success, otherwise fail
2125  */
woal_set_rxfilter(moal_private * priv,BOOLEAN enable)2126 static int woal_set_rxfilter(moal_private *priv, BOOLEAN enable)
2127 {
2128 	int ret = 0;
2129 	mlan_ioctl_req *req = NULL;
2130 	mlan_ds_misc_cfg *misc = NULL;
2131 	mlan_ds_misc_mef_cfg *mef_cfg = NULL;
2132 	mlan_status status = MLAN_STATUS_SUCCESS;
2133 
2134 	ENTER();
2135 
2136 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
2137 	if (req == NULL) {
2138 		ret = -ENOMEM;
2139 		goto done;
2140 	}
2141 	misc = (mlan_ds_misc_cfg *)req->pbuf;
2142 	mef_cfg = &misc->param.mef_cfg;
2143 	req->req_id = MLAN_IOCTL_MISC_CFG;
2144 	misc->sub_command = MLAN_OID_MISC_MEF_CFG;
2145 	req->action = MLAN_ACT_SET;
2146 
2147 	mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE);
2148 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2149 	if (status != MLAN_STATUS_SUCCESS) {
2150 		ret = -EFAULT;
2151 		goto done;
2152 	}
2153 
2154 done:
2155 	if (status != MLAN_STATUS_PENDING)
2156 		kfree(req);
2157 	LEAVE();
2158 	return ret;
2159 }
2160 #endif
2161 
2162 /**
2163  *  @brief Set priv command
2164  *
2165  *  @param dev          A pointer to net_device structure
2166  *  @param info         A pointer to iw_request_info structure
2167  *  @param dwrq         A pointer to iw_point structure
2168  *  @param extra        A pointer to extra data buf
2169  *
2170  *  @return                     0 --success, otherwise fail
2171  */
woal_set_priv(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)2172 static int woal_set_priv(struct net_device *dev, struct iw_request_info *info,
2173 			 union iwreq_data *wrqu, char *extra)
2174 {
2175 	int ret = 0;
2176 	moal_private *priv = (moal_private *)netdev_priv(dev);
2177 	struct iw_point *dwrq = &wrqu->data;
2178 	char *buf = NULL;
2179 	int power_mode = 0;
2180 	int band = 0;
2181 	char *pband = NULL;
2182 	mlan_bss_info bss_info;
2183 	mlan_ds_get_signal signal;
2184 	mlan_rate_cfg_t rate;
2185 	char *pdata = NULL;
2186 	t_u8 country_code[COUNTRY_CODE_LEN];
2187 	int len = 0;
2188 	gfp_t flag;
2189 	ENTER();
2190 	if (!priv || !priv->phandle) {
2191 		PRINTM(MERROR, "priv or handle is NULL\n");
2192 		ret = -EFAULT;
2193 		goto done;
2194 	}
2195 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
2196 	buf = kzalloc(dwrq->length + 1, flag);
2197 	if (!buf) {
2198 		ret = -ENOMEM;
2199 		goto done;
2200 	}
2201 	if (copy_from_user(buf, dwrq->pointer, dwrq->length)) {
2202 		ret = -EFAULT;
2203 		goto done;
2204 	}
2205 	buf[dwrq->length] = '\0';
2206 	PRINTM(MIOCTL, "SIOCSIWPRIV request = %s\n", buf);
2207 	if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) ==
2208 	    0) {
2209 		if (dwrq->length > strlen("RSSILOW-THRESHOLD") + 1) {
2210 			pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
2211 			if (MLAN_STATUS_SUCCESS !=
2212 			    woal_set_rssi_low_threshold(priv, pdata,
2213 							MOAL_IOCTL_WAIT)) {
2214 				ret = -EFAULT;
2215 				goto done;
2216 			}
2217 			len = sprintf(buf, "OK\n") + 1;
2218 		} else {
2219 			ret = -EFAULT;
2220 			goto done;
2221 		}
2222 	} else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
2223 		if (MLAN_STATUS_SUCCESS !=
2224 		    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2225 			ret = -EFAULT;
2226 			goto done;
2227 		}
2228 		if (bss_info.media_connected) {
2229 			if (MLAN_STATUS_SUCCESS !=
2230 			    woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
2231 						 &signal)) {
2232 				ret = -EFAULT;
2233 				goto done;
2234 			}
2235 			len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
2236 				      signal.bcn_rssi_avg) +
2237 			      1;
2238 		} else {
2239 			len = sprintf(buf, "OK\n") + 1;
2240 		}
2241 	} else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
2242 		if (MLAN_STATUS_SUCCESS !=
2243 		    woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
2244 			ret = -EFAULT;
2245 			goto done;
2246 		}
2247 		PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
2248 		len = sprintf(buf, "LinkSpeed %d\n",
2249 			      (int)(rate.rate * 500000 / 1000000)) +
2250 		      1;
2251 	} else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
2252 		len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2253 			      priv->current_addr[0], priv->current_addr[1],
2254 			      priv->current_addr[2], priv->current_addr[3],
2255 			      priv->current_addr[4], priv->current_addr[5]) +
2256 		      1;
2257 	} else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
2258 		if (MLAN_STATUS_SUCCESS !=
2259 		    woal_get_powermode(priv, &power_mode)) {
2260 			ret = -EFAULT;
2261 			goto done;
2262 		}
2263 		len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
2264 	} else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
2265 		if (MLAN_STATUS_SUCCESS !=
2266 		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
2267 			ret = -EFAULT;
2268 			goto done;
2269 		}
2270 		priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
2271 		PRINTM(MIOCTL, "Set Active Scan\n");
2272 		len = sprintf(buf, "OK\n") + 1;
2273 	} else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
2274 		if (MLAN_STATUS_SUCCESS !=
2275 		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
2276 			ret = -EFAULT;
2277 			goto done;
2278 		}
2279 		priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
2280 		PRINTM(MIOCTL, "Set Passive Scan\n");
2281 		len = sprintf(buf, "OK\n") + 1;
2282 	} else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
2283 		if (dwrq->length > strlen("POWERMODE") + 1) {
2284 			pdata = buf + strlen("POWERMODE") + 1;
2285 			if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
2286 				if (MLAN_STATUS_SUCCESS !=
2287 				    woal_set_powermode(priv, pdata)) {
2288 					ret = -EFAULT;
2289 					goto done;
2290 				}
2291 			}
2292 			len = sprintf(buf, "OK\n") + 1;
2293 		} else {
2294 			ret = -EFAULT;
2295 			goto done;
2296 		}
2297 	} else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
2298 		memset(country_code, 0, sizeof(country_code));
2299 		if ((strlen(buf) - strlen("COUNTRY") - 1) > COUNTRY_CODE_LEN) {
2300 			ret = -EFAULT;
2301 			goto done;
2302 		}
2303 		moal_memcpy_ext(priv->phandle, country_code,
2304 				buf + strlen("COUNTRY") + 1,
2305 				COUNTRY_CODE_LEN - 1, sizeof(country_code) - 1);
2306 		PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
2307 		if (MLAN_STATUS_SUCCESS !=
2308 		    woal_set_region_code(priv, country_code)) {
2309 			ret = -EFAULT;
2310 			goto done;
2311 		}
2312 		len = sprintf(buf, "OK\n") + 1;
2313 	} else if (memcmp(buf, WEXT_CSCAN_HEADER, strlen(WEXT_CSCAN_HEADER)) ==
2314 		   0) {
2315 		PRINTM(MIOCTL, "Set Combo Scan\n");
2316 		if (MLAN_STATUS_SUCCESS !=
2317 		    woal_set_combo_scan(priv, buf, dwrq->length)) {
2318 			ret = -EFAULT;
2319 			goto done;
2320 		}
2321 		len = sprintf(buf, "OK\n") + 1;
2322 	} else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
2323 		if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
2324 			ret = -EFAULT;
2325 			goto done;
2326 		}
2327 		len = sprintf(buf, "Band %d\n", band) + 1;
2328 	} else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
2329 		pband = buf + strlen("SETBAND") + 1;
2330 		if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
2331 			ret = -EFAULT;
2332 			goto done;
2333 		}
2334 		len = sprintf(buf, "OK\n") + 1;
2335 	} else if (strncmp(buf, "START", strlen("START")) == 0) {
2336 		len = sprintf(buf, "OK\n") + 1;
2337 	} else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
2338 		len = sprintf(buf, "OK\n") + 1;
2339 	} else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) ==
2340 		   0) {
2341 		/* it will be done by GUI */
2342 		len = sprintf(buf, "OK\n") + 1;
2343 	} else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
2344 		len = sprintf(buf, "OK\n") + 1;
2345 	} else if (strncmp(buf, "BTCOEXSCAN-START",
2346 			   strlen("BTCOEXSCAN-START")) == 0) {
2347 		len = sprintf(buf, "OK\n") + 1;
2348 	} else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
2349 		   0) {
2350 		len = sprintf(buf, "OK\n") + 1;
2351 	} else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
2352 		len = sprintf(buf, "OK\n") + 1;
2353 	} else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) ==
2354 		   0) {
2355 		if (MLAN_STATUS_SUCCESS !=
2356 		    woal_set_bg_scan(priv, buf, dwrq->length)) {
2357 			ret = -EFAULT;
2358 			goto done;
2359 		}
2360 		priv->bg_scan_start = MTRUE;
2361 		priv->bg_scan_reported = MFALSE;
2362 		len = sprintf(buf, "OK\n") + 1;
2363 	} else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
2364 		if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
2365 			if (MLAN_STATUS_SUCCESS !=
2366 			    woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT)) {
2367 				ret = -EFAULT;
2368 				goto done;
2369 			}
2370 			priv->bg_scan_start = MFALSE;
2371 			priv->bg_scan_reported = MFALSE;
2372 		}
2373 		len = sprintf(buf, "OK\n") + 1;
2374 	} else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
2375 		   0) {
2376 #ifdef MEF_CFG_RX_FILTER
2377 		ret = woal_set_rxfilter(priv, MTRUE);
2378 		if (ret)
2379 			goto done;
2380 #endif
2381 		len = sprintf(buf, "OK\n") + 1;
2382 	} else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) ==
2383 		   0) {
2384 #ifdef MEF_CFG_RX_FILTER
2385 		ret = woal_set_rxfilter(priv, MFALSE);
2386 		if (ret)
2387 			goto done;
2388 #endif
2389 		len = sprintf(buf, "OK\n") + 1;
2390 	} else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
2391 		if (dwrq->length > strlen("RXFILTER-ADD") + 1) {
2392 			pdata = buf + strlen("RXFILTER-ADD") + 1;
2393 			if (MLAN_STATUS_SUCCESS !=
2394 			    woal_add_rxfilter(priv, pdata)) {
2395 				ret = -EFAULT;
2396 				goto done;
2397 			}
2398 			len = sprintf(buf, "OK\n") + 1;
2399 		} else {
2400 			ret = -EFAULT;
2401 			goto done;
2402 		}
2403 	} else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
2404 		   0) {
2405 		if (dwrq->length > strlen("RXFILTER-REMOVE") + 1) {
2406 			pdata = buf + strlen("RXFILTER-REMOVE") + 1;
2407 			if (MLAN_STATUS_SUCCESS !=
2408 			    woal_remove_rxfilter(priv, pdata)) {
2409 				ret = -EFAULT;
2410 				goto done;
2411 			}
2412 			len = sprintf(buf, "OK\n") + 1;
2413 		} else {
2414 			ret = -EFAULT;
2415 			goto done;
2416 		}
2417 	} else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
2418 		if (dwrq->length > strlen("QOSINFO") + 1) {
2419 			pdata = buf + strlen("QOSINFO") + 1;
2420 			if (MLAN_STATUS_SUCCESS !=
2421 			    woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
2422 				ret = -EFAULT;
2423 				goto done;
2424 			}
2425 			len = sprintf(buf, "OK\n") + 1;
2426 		} else {
2427 			ret = -EFAULT;
2428 			goto done;
2429 		}
2430 	} else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
2431 		if (dwrq->length > strlen("SLEEPPD") + 1) {
2432 			pdata = buf + strlen("SLEEPPD") + 1;
2433 			if (MLAN_STATUS_SUCCESS !=
2434 			    woal_set_sleeppd(priv, pdata)) {
2435 				ret = -EFAULT;
2436 				goto done;
2437 			}
2438 			len = sprintf(buf, "OK\n") + 1;
2439 		} else {
2440 			ret = -EFAULT;
2441 			goto done;
2442 		}
2443 	} else {
2444 		PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
2445 		ret = -EFAULT;
2446 		goto done;
2447 	}
2448 	PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
2449 	dwrq->length = (t_u16)len;
2450 	if (copy_to_user((void __user *)dwrq->pointer, buf, dwrq->length))
2451 		ret = -EFAULT;
2452 done:
2453 	kfree(buf);
2454 	LEAVE();
2455 	return ret;
2456 }
2457 
2458 /**
2459  *  @brief Request a scan
2460  *
2461  *  @param priv                 A pointer to moal_private structure
2462  *  @param wait_option          Wait option
2463  *  @param req_ssid             A pointer to mlan_802_11_ssid structure
2464  *
2465  *  @return                     MLAN_STATUS_SUCCESS -- success, otherwise fail
2466  */
woal_wext_request_scan(moal_private * priv,t_u8 wait_option,mlan_802_11_ssid * req_ssid)2467 static mlan_status woal_wext_request_scan(moal_private *priv, t_u8 wait_option,
2468 					  mlan_802_11_ssid *req_ssid)
2469 {
2470 	wlan_user_scan_cfg *scan_req;
2471 	mlan_scan_cfg scan_cfg;
2472 	mlan_status status;
2473 	ENTER();
2474 	if (!woal_is_any_interface_active(priv->phandle)) {
2475 		LEAVE();
2476 		return woal_request_scan(priv, wait_option, req_ssid);
2477 	}
2478 	scan_req = (wlan_user_scan_cfg *)kmalloc(sizeof(wlan_user_scan_cfg),
2479 						 GFP_KERNEL);
2480 	if (!scan_req) {
2481 		PRINTM(MERROR, "Malloc buffer failed\n");
2482 		LEAVE();
2483 		return MLAN_STATUS_FAILURE;
2484 	}
2485 
2486 	memset(&scan_cfg, 0, sizeof(scan_cfg));
2487 	memset(scan_req, 0, sizeof(wlan_user_scan_cfg));
2488 	if (req_ssid && req_ssid->ssid_len != 0) {
2489 		moal_memcpy_ext(priv->phandle, scan_req->ssid_list[0].ssid,
2490 				req_ssid->ssid, req_ssid->ssid_len,
2491 				MLAN_MAX_SSID_LENGTH);
2492 		scan_req->ssid_list[0].max_len = 0;
2493 	}
2494 	woal_get_scan_config(priv, &scan_cfg);
2495 	if (scan_cfg.scan_chan_gap)
2496 		scan_req->scan_chan_gap = scan_cfg.scan_chan_gap;
2497 	else
2498 		scan_req->scan_chan_gap = priv->phandle->scan_chan_gap;
2499 	/** indicate FW, gap is optional */
2500 	if (scan_req->scan_chan_gap && priv->phandle->pref_mac)
2501 		scan_req->scan_chan_gap |= GAP_FLAG_OPTIONAL;
2502 	status = woal_request_userscan(priv, wait_option, scan_req);
2503 	kfree(scan_req);
2504 	LEAVE();
2505 	return status;
2506 }
2507 
2508 /**
2509  *  @brief Scan Network
2510  *
2511  *  @param dev          A pointer to net_device structure
2512  *  @param info         A pointer to iw_request_info structure
2513  *  @param vwrq         A pointer to iw_param structure
2514  *  @param extra        A pointer to extra data buf
2515  *
2516  *  @return             0--success, otherwise fail
2517  */
woal_set_scan(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2518 static int woal_set_scan(struct net_device *dev, struct iw_request_info *info,
2519 			 struct iw_param *vwrq, char *extra)
2520 {
2521 	int ret = 0;
2522 	moal_private *priv = (moal_private *)netdev_priv(dev);
2523 	moal_handle *handle = priv->phandle;
2524 #if WIRELESS_EXT >= 18
2525 	struct iw_scan_req *req;
2526 	struct iw_point *dwrq = (struct iw_point *)vwrq;
2527 #endif
2528 	mlan_802_11_ssid req_ssid;
2529 
2530 	ENTER();
2531 	if (handle->scan_pending_on_block == MTRUE) {
2532 		PRINTM(MINFO, "scan already in processing...\n");
2533 		LEAVE();
2534 		return ret;
2535 	}
2536 #ifdef REASSOCIATION
2537 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2538 		PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
2539 		LEAVE();
2540 		return -EBUSY;
2541 	}
2542 #endif /* REASSOCIATION */
2543 	priv->report_scan_result = MTRUE;
2544 
2545 	memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
2546 
2547 #if WIRELESS_EXT >= 18
2548 	if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
2549 	    (dwrq->length == sizeof(struct iw_scan_req))) {
2550 		req = (struct iw_scan_req *)extra;
2551 
2552 		if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
2553 			req_ssid.ssid_len = req->essid_len;
2554 			moal_memcpy_ext(priv->phandle, req_ssid.ssid,
2555 					(t_u8 *)req->essid, req->essid_len,
2556 					sizeof(req_ssid.ssid));
2557 			if (MLAN_STATUS_SUCCESS !=
2558 			    woal_wext_request_scan(priv, MOAL_NO_WAIT,
2559 						   &req_ssid)) {
2560 				ret = -EFAULT;
2561 				goto done;
2562 			}
2563 		}
2564 	} else {
2565 #endif
2566 		if (MLAN_STATUS_SUCCESS !=
2567 		    woal_wext_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
2568 			ret = -EFAULT;
2569 			goto done;
2570 		}
2571 #if WIRELESS_EXT >= 18
2572 	}
2573 #endif
2574 
2575 	if (priv->phandle->surprise_removed) {
2576 		ret = -EFAULT;
2577 		goto done;
2578 	}
2579 
2580 done:
2581 #ifdef REASSOCIATION
2582 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2583 #endif
2584 
2585 	LEAVE();
2586 	return ret;
2587 }
2588 
2589 /**
2590  *  @brief Set essid
2591  *
2592  *  @param dev          A pointer to net_device structure
2593  *  @param info         A pointer to iw_request_info structure
2594  *  @param dwrq         A pointer to iw_point structure
2595  *  @param extra        A pointer to extra data buf
2596  *
2597  *  @return             0--success, otherwise fail
2598  */
woal_set_essid(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)2599 static int woal_set_essid(struct net_device *dev, struct iw_request_info *info,
2600 			  union iwreq_data *wrqu, char *extra)
2601 {
2602 	moal_private *priv = (moal_private *)netdev_priv(dev);
2603 	struct iw_point *dwrq = &wrqu->data;
2604 	mlan_802_11_ssid req_ssid;
2605 	mlan_ssid_bssid ssid_bssid;
2606 #ifdef REASSOCIATION
2607 	moal_handle *handle = priv->phandle;
2608 	mlan_bss_info bss_info;
2609 #endif
2610 	int ret = 0;
2611 	t_u32 mode = 0;
2612 
2613 	ENTER();
2614 
2615 #ifdef REASSOCIATION
2616 	/* Cancel re-association */
2617 	priv->reassoc_required = MFALSE;
2618 
2619 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2620 		PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
2621 		LEAVE();
2622 		return -EBUSY;
2623 	}
2624 #endif /* REASSOCIATION */
2625 
2626 	/* Check the size of the string */
2627 	if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
2628 		ret = -E2BIG;
2629 		goto setessid_ret;
2630 	}
2631 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2632 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
2633 	memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
2634 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
2635 
2636 #if WIRELESS_EXT > 20
2637 	req_ssid.ssid_len = dwrq->length;
2638 #else
2639 	req_ssid.ssid_len = dwrq->length - 1;
2640 #endif
2641 
2642 	/*
2643 	 * Check if we asked for `any' or 'particular'
2644 	 */
2645 	if (!dwrq->flags) {
2646 #ifdef REASSOCIATION
2647 		if (!req_ssid.ssid_len) {
2648 			memset(&priv->prev_ssid_bssid.ssid, 0x00,
2649 			       sizeof(mlan_802_11_ssid));
2650 			memset(&priv->prev_ssid_bssid.bssid, 0x00,
2651 			       MLAN_MAC_ADDR_LENGTH);
2652 			goto setessid_ret;
2653 		}
2654 #endif
2655 		/* Do normal SSID scanning */
2656 		if (MLAN_STATUS_SUCCESS !=
2657 		    woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
2658 			ret = -EFAULT;
2659 			goto setessid_ret;
2660 		}
2661 	} else {
2662 		/* Set the SSID */
2663 		moal_memcpy_ext(priv->phandle, req_ssid.ssid, extra,
2664 				MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH),
2665 				sizeof(req_ssid.ssid));
2666 		if (!req_ssid.ssid_len ||
2667 		    (MFALSE == woal_ssid_valid(&req_ssid))) {
2668 			PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
2669 			ret = -EINVAL;
2670 			goto setessid_ret;
2671 		}
2672 
2673 		PRINTM(MINFO, "Requested new SSID = %s\n",
2674 		       (char *)req_ssid.ssid);
2675 		moal_memcpy_ext(priv->phandle, &ssid_bssid.ssid, &req_ssid,
2676 				sizeof(mlan_802_11_ssid),
2677 				sizeof(ssid_bssid.ssid));
2678 		if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
2679 			PRINTM(MIOCTL, "Already connect to the network\n");
2680 			goto setessid_ret;
2681 		}
2682 
2683 		priv->auto_assoc_priv.drv_assoc.status = MFALSE;
2684 		priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
2685 #ifdef REASSOCIATION
2686 		if (priv->reassoc_on == MTRUE) {
2687 			if (priv->auto_assoc_priv.auto_assoc_type_on &
2688 			    (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
2689 				if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2690 					woal_set_scan_type(
2691 						priv, MLAN_SCAN_TYPE_PASSIVE);
2692 				MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2693 				moal_memcpy_ext(
2694 					priv->phandle,
2695 					&priv->prev_ssid_bssid.ssid, &req_ssid,
2696 					sizeof(mlan_802_11_ssid),
2697 					sizeof(priv->prev_ssid_bssid.ssid));
2698 				priv->auto_assoc_priv.auto_assoc_trigger_flag =
2699 					AUTO_ASSOC_TYPE_DRV_ASSOC;
2700 				priv->auto_assoc_priv.drv_assoc.status = MTRUE;
2701 				priv->reassoc_required = MTRUE;
2702 				priv->phandle->is_reassoc_timer_set = MTRUE;
2703 				PRINTM(MINFO,
2704 				       " auto assoc: trigger driver auto assoc\n");
2705 				woal_mod_timer(&priv->phandle->reassoc_timer,
2706 					       0);
2707 				ret = MLAN_STATUS_SUCCESS;
2708 
2709 				LEAVE();
2710 				return ret;
2711 			}
2712 		}
2713 #endif
2714 
2715 		if (dwrq->flags != 0xFFFF) {
2716 			if (MLAN_STATUS_SUCCESS !=
2717 			    woal_find_essid(priv, &ssid_bssid,
2718 					    MOAL_IOCTL_WAIT)) {
2719 				/* Do specific SSID scanning */
2720 				if (MLAN_STATUS_SUCCESS !=
2721 				    woal_request_scan(priv, MOAL_IOCTL_WAIT,
2722 						      &req_ssid)) {
2723 					ret = -EFAULT;
2724 					goto setessid_ret;
2725 				}
2726 			}
2727 		}
2728 	}
2729 
2730 	mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
2731 	if (mode == IW_MODE_ADHOC)
2732 		/* disconnect before try to associate */
2733 		woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
2734 				DEF_DEAUTH_REASON_CODE);
2735 
2736 	if (mode != IW_MODE_ADHOC) {
2737 		if (MLAN_STATUS_SUCCESS !=
2738 		    woal_find_best_network(priv, MOAL_IOCTL_WAIT,
2739 					   &ssid_bssid)) {
2740 			ret = -EFAULT;
2741 			goto setessid_ret;
2742 		}
2743 		if (MLAN_STATUS_SUCCESS !=
2744 		    woal_11d_check_ap_channel(priv, MOAL_IOCTL_WAIT,
2745 					      &ssid_bssid)) {
2746 			PRINTM(MERROR,
2747 			       "The AP's channel is invalid for current region\n");
2748 			ret = -EFAULT;
2749 			goto setessid_ret;
2750 		}
2751 	} else if (MLAN_STATUS_SUCCESS !=
2752 		   woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
2753 		/* Adhoc start, Check the channel command */
2754 		woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
2755 
2756 #ifdef REASSOCIATION
2757 	if (priv->reassoc_on == MTRUE && req_ssid.ssid_len) {
2758 		moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
2759 				&req_ssid, sizeof(mlan_802_11_ssid),
2760 				sizeof(priv->prev_ssid_bssid.ssid));
2761 		memset(&priv->prev_ssid_bssid.bssid, 0x00,
2762 		       MLAN_MAC_ADDR_LENGTH);
2763 	}
2764 #endif /* REASSOCIATION */
2765 
2766 	/* Connect to BSS by ESSID */
2767 	memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
2768 
2769 	if (MLAN_STATUS_SUCCESS !=
2770 	    woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
2771 		ret = -EFAULT;
2772 		goto setessid_ret;
2773 	}
2774 
2775 #ifdef REASSOCIATION
2776 	memset(&bss_info, 0, sizeof(bss_info));
2777 	if (MLAN_STATUS_SUCCESS !=
2778 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2779 		ret = -EFAULT;
2780 		goto setessid_ret;
2781 	}
2782 	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
2783 			&bss_info.ssid, sizeof(mlan_802_11_ssid),
2784 			sizeof(priv->prev_ssid_bssid.ssid));
2785 	moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
2786 			&bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
2787 			sizeof(priv->prev_ssid_bssid.bssid));
2788 #endif /* REASSOCIATION */
2789 
2790 setessid_ret:
2791 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2792 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
2793 #ifdef REASSOCIATION
2794 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2795 #endif
2796 	LEAVE();
2797 	return ret;
2798 }
2799 
2800 /**
2801  *  @brief Get current essid
2802  *
2803  *  @param dev      A pointer to net_device structure
2804  *  @param info     A pointer to iw_request_info structure
2805  *  @param dwrq     A pointer to iw_point structure
2806  *  @param extra    A pointer to extra data buf
2807  *
2808  *  @return         0--success, otherwise fail
2809  */
woal_get_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2810 static int woal_get_essid(struct net_device *dev, struct iw_request_info *info,
2811 			  struct iw_point *dwrq, char *extra)
2812 {
2813 	moal_private *priv = (moal_private *)netdev_priv(dev);
2814 	mlan_bss_info bss_info;
2815 	int ret = 0;
2816 
2817 	ENTER();
2818 
2819 	memset(&bss_info, 0, sizeof(bss_info));
2820 
2821 	if (MLAN_STATUS_SUCCESS !=
2822 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2823 		ret = -EFAULT;
2824 		goto done;
2825 	}
2826 
2827 	if (bss_info.media_connected) {
2828 		dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
2829 		moal_memcpy_ext(priv->phandle, extra, bss_info.ssid.ssid,
2830 				dwrq->length, dwrq->length);
2831 	} else
2832 		dwrq->length = 0;
2833 
2834 	if (bss_info.scan_table_idx)
2835 		dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
2836 	else
2837 		dwrq->flags = 1;
2838 
2839 done:
2840 	LEAVE();
2841 	return ret;
2842 }
2843 
2844 /**
2845  *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
2846  *
2847  *  @param dev          A pointer to net_device structure
2848  *  @param info         A pointer to iw_request_info structure
2849  *  @param dwrq         A pointer to iw_point structure
2850  *  @param extra        A pointer to extra data buf
2851  *
2852  *  @return             0--success, otherwise fail
2853  */
woal_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2854 static int woal_get_scan(struct net_device *dev, struct iw_request_info *info,
2855 			 struct iw_point *dwrq, char *extra)
2856 {
2857 	moal_private *priv = (moal_private *)netdev_priv(dev);
2858 	int ret = 0;
2859 	char *current_ev = extra;
2860 	char *end_buf = extra + IW_SCAN_MAX_DATA;
2861 	char *current_val; /* For rates */
2862 	struct iw_event iwe; /* Temporary buffer */
2863 	unsigned int i;
2864 	unsigned int j;
2865 	mlan_scan_resp scan_resp;
2866 	mlan_bss_info bss_info;
2867 	BSSDescriptor_t *scan_table;
2868 	mlan_ds_get_signal rssi;
2869 	t_u16 buf_size = 16 + 256 * 2;
2870 	char *buf = NULL;
2871 	char *ptr;
2872 #if WIRELESS_EXT >= 18
2873 	t_u8 *praw_data;
2874 #endif
2875 	int beacon_size;
2876 	t_u8 *pbeacon;
2877 	IEEEtypes_ElementId_e element_id;
2878 	t_u8 element_len;
2879 	gfp_t flag;
2880 
2881 	ENTER();
2882 
2883 	if (priv->phandle->scan_pending_on_block == MTRUE) {
2884 		LEAVE();
2885 		return -EAGAIN;
2886 	}
2887 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
2888 	buf = kzalloc((buf_size), flag);
2889 	if (!buf) {
2890 		PRINTM(MERROR, "Cannot allocate buffer!\n");
2891 		ret = -EFAULT;
2892 		goto done;
2893 	}
2894 
2895 	memset(&bss_info, 0, sizeof(bss_info));
2896 	if (MLAN_STATUS_SUCCESS !=
2897 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2898 		ret = -EFAULT;
2899 		goto done;
2900 	}
2901 	memset(&scan_resp, 0, sizeof(scan_resp));
2902 	if (MLAN_STATUS_SUCCESS !=
2903 	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
2904 		ret = -EFAULT;
2905 		goto done;
2906 	}
2907 	scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
2908 	if (dwrq->length)
2909 		end_buf = extra + dwrq->length;
2910 	if (priv->media_connected == MTRUE)
2911 		PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
2912 	PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
2913 	       (int)scan_resp.num_in_scan_table);
2914 
2915 #if WIRELESS_EXT > 13
2916 	/* The old API using SIOCGIWAPLIST had a hard limit of
2917 	 * IW_MAX_AP. The new API using SIOCGIWSCAN is only
2918 	 * limited by buffer size WE-14 -> WE-16 the buffer is
2919 	 * limited to IW_SCAN_MAX_DATA bytes which is 4096.
2920 	 */
2921 	for (i = 0; i < MIN(scan_resp.num_in_scan_table, 64); i++) {
2922 		if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
2923 			PRINTM(MINFO,
2924 			       "i=%d break out: current_ev=%p end_buf=%p "
2925 			       "MAX_SCAN_CELL_SIZE=%d\n",
2926 			       i, current_ev, end_buf,
2927 			       (t_u32)MAX_SCAN_CELL_SIZE);
2928 			ret = -E2BIG;
2929 			break;
2930 		}
2931 		if (!scan_table[i].freq) {
2932 			PRINTM(MWARN, "Invalid channel number %d\n",
2933 			       (int)scan_table[i].channel);
2934 			continue;
2935 		}
2936 		PRINTM(MINFO, "i=%d  Ssid: %-32s\n", i,
2937 		       scan_table[i].ssid.ssid);
2938 
2939 		/* check ssid is valid or not, ex. hidden ssid will be filter
2940 		 * out */
2941 		if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE)
2942 			continue;
2943 
2944 		/* First entry *MUST* be the AP MAC address */
2945 		iwe.cmd = SIOCGIWAP;
2946 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
2947 		moal_memcpy_ext(priv->phandle, iwe.u.ap_addr.sa_data,
2948 				&scan_table[i].mac_address, ETH_ALEN,
2949 				sizeof(iwe.u.ap_addr.sa_data));
2950 
2951 		iwe.len = IW_EV_ADDR_LEN;
2952 		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
2953 						  &iwe, iwe.len);
2954 
2955 		/* Add the ESSID */
2956 		iwe.u.data.length = scan_table[i].ssid.ssid_len;
2957 
2958 		if (iwe.u.data.length > 32)
2959 			iwe.u.data.length = 32;
2960 
2961 		iwe.cmd = SIOCGIWESSID;
2962 		iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
2963 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2964 		current_ev =
2965 			IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2966 					     (char *)scan_table[i].ssid.ssid);
2967 
2968 		/* Add mode */
2969 		iwe.cmd = SIOCGIWMODE;
2970 		if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
2971 			iwe.u.mode = IW_MODE_ADHOC;
2972 		else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
2973 			iwe.u.mode = IW_MODE_MASTER;
2974 		else
2975 			iwe.u.mode = IW_MODE_AUTO;
2976 
2977 		iwe.len = IW_EV_UINT_LEN;
2978 		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
2979 						  &iwe, iwe.len);
2980 
2981 		/* Frequency */
2982 		iwe.cmd = SIOCGIWFREQ;
2983 		iwe.u.freq.m = (long)scan_table[i].freq;
2984 		iwe.u.freq.e = 6;
2985 		iwe.u.freq.flags = IW_FREQ_FIXED;
2986 		iwe.len = IW_EV_FREQ_LEN;
2987 		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
2988 						  &iwe, iwe.len);
2989 
2990 		memset(&iwe, 0, sizeof(iwe));
2991 		/* Add quality statistics */
2992 		iwe.cmd = IWEVQUAL;
2993 		iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
2994 		if (!bss_info.bcn_nf_last)
2995 			iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
2996 		else
2997 			iwe.u.qual.noise = bss_info.bcn_nf_last;
2998 
2999 		if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
3000 		    !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid) &&
3001 		    bss_info.adhoc_state == ADHOC_STARTED) {
3002 			memset(&rssi, 0, sizeof(mlan_ds_get_signal));
3003 			if (MLAN_STATUS_SUCCESS !=
3004 			    woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
3005 						 &rssi)) {
3006 				ret = -EFAULT;
3007 				break;
3008 			}
3009 			iwe.u.qual.level = rssi.data_rssi_avg;
3010 		}
3011 		iwe.u.qual.qual =
3012 			woal_rssi_to_quality((t_s16)(iwe.u.qual.level - 0x100));
3013 		iwe.len = IW_EV_QUAL_LEN;
3014 		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf,
3015 						  &iwe, iwe.len);
3016 
3017 		/* Add encryption capability */
3018 		iwe.cmd = SIOCGIWENCODE;
3019 		if (scan_table[i].privacy)
3020 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
3021 		else
3022 			iwe.u.data.flags = IW_ENCODE_DISABLED;
3023 
3024 		iwe.u.data.length = 0;
3025 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
3026 		current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,
3027 						  &iwe, NULL);
3028 
3029 		current_val = current_ev + IW_EV_LCP_LEN;
3030 
3031 		iwe.cmd = SIOCGIWRATE;
3032 
3033 		iwe.u.bitrate.fixed = 0;
3034 		iwe.u.bitrate.disabled = 0;
3035 		iwe.u.bitrate.value = 0;
3036 
3037 		/* Bit rate given in 500 kb/s units (+ 0x80) */
3038 		for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
3039 			if (!scan_table[i].supported_rates[j])
3040 				break;
3041 
3042 			iwe.u.bitrate.value =
3043 				(scan_table[i].supported_rates[j] & 0x7f) *
3044 				500000;
3045 			iwe.len = IW_EV_PARAM_LEN;
3046 			current_val = IWE_STREAM_ADD_VALUE(info, current_ev,
3047 							   current_val, end_buf,
3048 							   &iwe, iwe.len);
3049 		}
3050 		if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
3051 		    !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid) &&
3052 		    bss_info.adhoc_state == ADHOC_STARTED) {
3053 			iwe.u.bitrate.value = 22 * 500000;
3054 			iwe.len = IW_EV_PARAM_LEN;
3055 			current_val = IWE_STREAM_ADD_VALUE(info, current_ev,
3056 							   current_val, end_buf,
3057 							   &iwe, iwe.len);
3058 		}
3059 
3060 		/* Check if an event is added */
3061 		if ((unsigned int)(current_val - current_ev) >= IW_EV_PARAM_LEN)
3062 			current_ev = current_val;
3063 
3064 		/* Beacon Interval */
3065 		memset(&iwe, 0, sizeof(iwe));
3066 		ptr = buf;
3067 		ptr += sprintf(ptr, "Beacon interval=%d",
3068 			       scan_table[i].beacon_period);
3069 
3070 		iwe.u.data.length = strlen(buf);
3071 		iwe.cmd = IWEVCUSTOM;
3072 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
3073 		current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,
3074 						  &iwe, buf);
3075 		current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
3076 
3077 		/* Parse and send the IEs */
3078 		pbeacon = scan_table[i].pbeacon_buf;
3079 		beacon_size = scan_table[i].beacon_buf_size;
3080 
3081 		/* Skip time stamp, beacon interval and capability */
3082 		if (pbeacon) {
3083 			pbeacon += sizeof(scan_table[i].beacon_period) +
3084 				   sizeof(scan_table[i].time_stamp) +
3085 				   sizeof(scan_table[i].cap_info);
3086 			beacon_size -= sizeof(scan_table[i].beacon_period) +
3087 				       sizeof(scan_table[i].time_stamp) +
3088 				       sizeof(scan_table[i].cap_info);
3089 
3090 			while ((unsigned int)beacon_size >=
3091 			       sizeof(IEEEtypes_Header_t)) {
3092 				element_id = (IEEEtypes_ElementId_e)(
3093 					*(t_u8 *)pbeacon);
3094 				element_len = *((t_u8 *)pbeacon + 1);
3095 				if ((unsigned int)beacon_size <
3096 				    (unsigned int)element_len +
3097 					    sizeof(IEEEtypes_Header_t)) {
3098 					PRINTM(MERROR,
3099 					       "Get scan: Error in processing IE, "
3100 					       "bytes left < IE length\n");
3101 					break;
3102 				}
3103 
3104 				switch (element_id) {
3105 #if WIRELESS_EXT >= 18
3106 				case VENDOR_SPECIFIC_221:
3107 				case RSN_IE:
3108 				case WAPI_IE:
3109 					praw_data = (t_u8 *)pbeacon;
3110 					memset(&iwe, 0, sizeof(iwe));
3111 					memset(buf, 0, buf_size);
3112 					ptr = buf;
3113 					moal_memcpy_ext(
3114 						priv->phandle, buf, praw_data,
3115 						element_len +
3116 							sizeof(IEEEtypes_Header_t),
3117 						buf_size);
3118 					iwe.cmd = IWEVGENIE;
3119 					iwe.u.data.length =
3120 						element_len +
3121 						sizeof(IEEEtypes_Header_t);
3122 					iwe.len = IW_EV_POINT_LEN +
3123 						  iwe.u.data.length;
3124 					current_ev = IWE_STREAM_ADD_POINT(
3125 						info, current_ev, end_buf, &iwe,
3126 						buf);
3127 					break;
3128 #endif
3129 				default:
3130 					break;
3131 				}
3132 				pbeacon += element_len +
3133 					   sizeof(IEEEtypes_Header_t);
3134 				beacon_size -= element_len +
3135 					       sizeof(IEEEtypes_Header_t);
3136 			}
3137 		}
3138 
3139 #if WIRELESS_EXT > 14
3140 		memset(&iwe, 0, sizeof(iwe));
3141 		memset(buf, 0, buf_size);
3142 		ptr = buf;
3143 		ptr += sprintf(ptr, "band=");
3144 		memset(&iwe, 0, sizeof(iwe));
3145 		if (scan_table[i].bss_band == BAND_A)
3146 			sprintf(ptr, "a");
3147 		else
3148 			sprintf(ptr, "bg");
3149 		iwe.u.data.length = strlen(buf);
3150 		PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
3151 		PRINTM(MINFO, "BUF: %s\n", buf);
3152 		iwe.cmd = IWEVCUSTOM;
3153 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
3154 		current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,
3155 						  &iwe, buf);
3156 #endif
3157 		current_val = current_ev + IW_EV_LCP_LEN;
3158 
3159 		/*
3160 		 * Check if we added any event
3161 		 */
3162 		if ((unsigned int)(current_val - current_ev) > IW_EV_LCP_LEN)
3163 			current_ev = current_val;
3164 	}
3165 
3166 	dwrq->length = (current_ev - extra);
3167 	dwrq->flags = 0;
3168 #endif
3169 
3170 done:
3171 	kfree(buf);
3172 	LEAVE();
3173 	return ret;
3174 }
3175 
3176 /**
3177  * iwconfig settable callbacks
3178  */
3179 static const iw_handler woal_handler[] = {
3180 	(iw_handler)woal_config_commit, /* SIOCSIWCOMMIT */
3181 	(iw_handler)woal_get_name, /* SIOCGIWNAME */
3182 	(iw_handler)NULL, /* SIOCSIWNWID */
3183 	(iw_handler)NULL, /* SIOCGIWNWID */
3184 	(iw_handler)woal_set_freq, /* SIOCSIWFREQ */
3185 	(iw_handler)woal_get_freq, /* SIOCGIWFREQ */
3186 	(iw_handler)woal_set_bss_mode, /* SIOCSIWMODE */
3187 	(iw_handler)woal_get_bss_mode, /* SIOCGIWMODE */
3188 	(iw_handler)woal_set_sens, /* SIOCSIWSENS */
3189 	(iw_handler)woal_get_sens, /* SIOCGIWSENS */
3190 	(iw_handler)NULL, /* SIOCSIWRANGE */
3191 	(iw_handler)woal_get_range, /* SIOCGIWRANGE */
3192 	(iw_handler)woal_set_priv, /* SIOCSIWPRIV */
3193 	(iw_handler)NULL, /* SIOCGIWPRIV */
3194 	(iw_handler)NULL, /* SIOCSIWSTATS */
3195 	(iw_handler)NULL, /* SIOCGIWSTATS */
3196 #if WIRELESS_EXT > 15
3197 #ifdef CONFIG_WEXT_SPY
3198 	iw_handler_set_spy, /* SIOCSIWSPY */
3199 	iw_handler_get_spy, /* SIOCGIWSPY */
3200 	iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
3201 	iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
3202 #else
3203 	(iw_handler)NULL, /* -- hole -- */
3204 	(iw_handler)NULL, /* -- hole -- */
3205 	(iw_handler)NULL, /* -- hole -- */
3206 	(iw_handler)NULL, /* -- hole -- */
3207 #endif
3208 #else /* WIRELESS_EXT > 15 */
3209 	(iw_handler)NULL, /* -- hole -- */
3210 	(iw_handler)NULL, /* -- hole -- */
3211 	(iw_handler)NULL, /* -- hole -- */
3212 	(iw_handler)NULL, /* -- hole -- */
3213 #endif /* WIRELESS_EXT > 15 */
3214 	(iw_handler)woal_set_wap, /* SIOCSIWAP */
3215 	(iw_handler)woal_get_wap, /* SIOCGIWAP */
3216 #if WIRELESS_EXT >= 18
3217 	(iw_handler)woal_set_mlme, /* SIOCSIWMLME  */
3218 #else
3219 	(iw_handler)NULL, /* -- hole -- */
3220 #endif
3221 	/* (iw_handler) wlan_get_aplist, */ /* SIOCGIWAPLIST */
3222 	NULL, /* SIOCGIWAPLIST */
3223 #if WIRELESS_EXT > 13
3224 	(iw_handler)woal_set_scan, /* SIOCSIWSCAN */
3225 	(iw_handler)woal_get_scan, /* SIOCGIWSCAN */
3226 #else /* WIRELESS_EXT > 13 */
3227 	(iw_handler)NULL, /* SIOCSIWSCAN */
3228 	(iw_handler)NULL, /* SIOCGIWSCAN */
3229 #endif /* WIRELESS_EXT > 13 */
3230 	(iw_handler)woal_set_essid, /* SIOCSIWESSID */
3231 	(iw_handler)woal_get_essid, /* SIOCGIWESSID */
3232 	(iw_handler)woal_set_nick, /* SIOCSIWNICKN */
3233 	(iw_handler)woal_get_nick, /* SIOCGIWNICKN */
3234 	(iw_handler)NULL, /* -- hole -- */
3235 	(iw_handler)NULL, /* -- hole -- */
3236 	(iw_handler)woal_set_rate, /* SIOCSIWRATE */
3237 	(iw_handler)woal_get_rate, /* SIOCGIWRATE */
3238 	(iw_handler)woal_set_rts, /* SIOCSIWRTS */
3239 	(iw_handler)woal_get_rts, /* SIOCGIWRTS */
3240 	(iw_handler)woal_set_frag, /* SIOCSIWFRAG */
3241 	(iw_handler)woal_get_frag, /* SIOCGIWFRAG */
3242 	(iw_handler)woal_set_txpow, /* SIOCSIWTXPOW */
3243 	(iw_handler)woal_get_txpow, /* SIOCGIWTXPOW */
3244 	(iw_handler)woal_set_retry, /* SIOCSIWRETRY */
3245 	(iw_handler)woal_get_retry, /* SIOCGIWRETRY */
3246 	(iw_handler)woal_set_encode, /* SIOCSIWENCODE */
3247 	(iw_handler)woal_get_encode, /* SIOCGIWENCODE */
3248 	(iw_handler)woal_set_power, /* SIOCSIWPOWER */
3249 	(iw_handler)woal_get_power, /* SIOCGIWPOWER */
3250 #if (WIRELESS_EXT >= 18)
3251 	(iw_handler)NULL, /* -- hole -- */
3252 	(iw_handler)NULL, /* -- hole -- */
3253 	(iw_handler)woal_set_gen_ie, /* SIOCSIWGENIE */
3254 	(iw_handler)woal_get_gen_ie, /* SIOCGIWGENIE */
3255 	(iw_handler)woal_set_auth, /* SIOCSIWAUTH  */
3256 	(iw_handler)woal_get_auth, /* SIOCGIWAUTH  */
3257 	(iw_handler)woal_set_encode_ext, /* SIOCSIWENCODEEXT */
3258 	(iw_handler)woal_get_encode_ext, /* SIOCGIWENCODEEXT */
3259 	(iw_handler)woal_set_pmksa, /* SIOCSIWPMKSA */
3260 #endif /* WIRELESSS_EXT >= 18 */
3261 };
3262 
3263 /**
3264  * iwpriv settable callbacks
3265  */
3266 static const iw_handler woal_private_handler[] = {
3267 	NULL, /* SIOCIWFIRSTPRIV */
3268 };
3269 #endif /* STA_SUPPORT */
3270 
3271 /********************************************************
3272 			Global Functions
3273 ********************************************************/
3274 
3275 #if WIRELESS_EXT > 14
3276 
3277 /**
3278  *  @brief This function sends customized event to application.
3279  *
3280  *  @param priv    A pointer to moal_private structure
3281  *  @param str     A pointer to event string
3282  *
3283  *  @return        N/A
3284  */
woal_send_iwevcustom_event(moal_private * priv,char * str)3285 void woal_send_iwevcustom_event(moal_private *priv, char *str)
3286 {
3287 	union iwreq_data iwrq;
3288 	char buf[IW_CUSTOM_MAX];
3289 
3290 	ENTER();
3291 	/* Check register_netdevice is completed before sending*/
3292 	if (priv->netdev->reg_state != NETREG_REGISTERED) {
3293 		LEAVE();
3294 		return;
3295 	}
3296 
3297 	memset(&iwrq, 0, sizeof(union iwreq_data));
3298 	memset(buf, 0, sizeof(buf));
3299 
3300 	snprintf(buf, sizeof(buf) - 1, "%s", str);
3301 
3302 	iwrq.data.pointer = (t_u8 __user *)buf;
3303 	iwrq.data.length = strlen(buf) + 1;
3304 
3305 	/* Send Event to upper layer */
3306 	wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
3307 	PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
3308 
3309 	LEAVE();
3310 	return;
3311 }
3312 #endif
3313 
3314 #if WIRELESS_EXT >= 18
3315 /**
3316  *  @brief This function sends mic error event to application.
3317  *
3318  *  @param priv    A pointer to moal_private structure
3319  *  @param event   MIC MERROR EVENT.
3320  *
3321  *  @return        N/A
3322  */
woal_send_mic_error_event(moal_private * priv,t_u32 event)3323 void woal_send_mic_error_event(moal_private *priv, t_u32 event)
3324 {
3325 	union iwreq_data iwrq;
3326 	struct iw_michaelmicfailure mic;
3327 
3328 	ENTER();
3329 
3330 	memset(&iwrq, 0, sizeof(iwrq));
3331 	memset(&mic, 0, sizeof(mic));
3332 	if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
3333 		mic.flags = IW_MICFAILURE_PAIRWISE;
3334 	else
3335 		mic.flags = IW_MICFAILURE_GROUP;
3336 	iwrq.data.pointer = (t_u8 __user *)&mic;
3337 	iwrq.data.length = sizeof(mic);
3338 
3339 	wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
3340 			    (char *)&mic);
3341 
3342 	LEAVE();
3343 	return;
3344 }
3345 #endif
3346 
3347 // clang-format off
3348 #ifdef STA_SUPPORT
3349 /** wlan_handler_def */
3350 struct iw_handler_def woal_handler_def = {
3351 	.num_standard = ARRAY_SIZE(woal_handler),
3352 	.num_private = ARRAY_SIZE(woal_private_handler),
3353 	.num_private_args = ARRAY_SIZE(woal_private_args),
3354 	.standard = (iw_handler *)woal_handler,
3355 	.private = (iw_handler *)woal_private_handler,
3356 	.private_args = (struct iw_priv_args *)woal_private_args,
3357 #if WIRELESS_EXT > 20
3358 	.get_wireless_stats = woal_get_wireless_stats,
3359 #endif
3360 };
3361 // clang-format on
3362 
3363 /**
3364  *  @brief Get wireless statistics
3365  *
3366  *  @param dev          A pointer to net_device structure
3367  *
3368  *  @return             A pointer to iw_statistics buf
3369  */
woal_get_wireless_stats(struct net_device * dev)3370 struct iw_statistics *woal_get_wireless_stats(struct net_device *dev)
3371 {
3372 	moal_private *priv = (moal_private *)netdev_priv(dev);
3373 	t_u16 wait_option = MOAL_IOCTL_WAIT;
3374 
3375 	ENTER();
3376 
3377 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
3378 	/*
3379 	 * Since schedule() is not allowed from an atomic context
3380 	 * such as when dev_base_lock for netdevices is acquired
3381 	 * for reading/writing in kernel before this call, HostCmd
3382 	 * is issued in non-blocking way in such contexts and
3383 	 * blocking in other cases.
3384 	 */
3385 	if (in_atomic() || !write_can_lock(&dev_base_lock))
3386 		wait_option = MOAL_NO_WAIT;
3387 #endif
3388 
3389 	priv->w_stats.status = woal_get_mode(priv, wait_option);
3390 	priv->w_stats.discard.retries = priv->stats.tx_errors;
3391 	priv->w_stats.qual.qual = 0;
3392 
3393 	/* Send RSSI command to get beacon RSSI/NF, valid only if associated */
3394 	if (priv->media_connected == MTRUE) {
3395 		if (MLAN_STATUS_SUCCESS ==
3396 		    woal_get_signal_info(priv, wait_option, NULL))
3397 			priv->w_stats.qual.qual = woal_rssi_to_quality(
3398 				(t_s16)(priv->w_stats.qual.level - 0x100));
3399 	}
3400 #if WIRELESS_EXT > 18
3401 	priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
3402 #else
3403 	priv->w_stats.qual.updated |= 7;
3404 #endif
3405 	if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
3406 		priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
3407 
3408 	PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual);
3409 	PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
3410 	PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
3411 	priv->w_stats.discard.code = 0;
3412 	if (MLAN_STATUS_SUCCESS != woal_get_stats_info(priv, wait_option, NULL))
3413 		PRINTM(MERROR, "Error getting stats information\n");
3414 
3415 	LEAVE();
3416 	return &priv->w_stats;
3417 }
3418 #endif /* STA_SUPPORT */
3419