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