aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex/sta_ioctl.c
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2011-03-21 21:00:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-03-30 14:15:17 -0400
commit5e6e3a92b9a4c9416b17f468fa5c7fa2233b8b4e (patch)
treede22c4c414412501e62894de65040bf30db28c64 /drivers/net/wireless/mwifiex/sta_ioctl.c
parent903946e6e21ef4dd678acafb8881cabde9182caf (diff)
wireless: mwifiex: initial commit for Marvell mwifiex driver
This driver adds WiFi support for Marvell 802.11n based chipsets with SDIO interface. Currently only SD8787 is supported. More chipsets will be supported later. drivers/net/wireless/mwifiex/ Signed-off-by: Nishant Sarmukadam <nishants@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kiran Divekar <dkiran@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com> Signed-off-by: Marc Yang <yangyang@marvell.com> Signed-off-by: Ramesh Radhakrishnan <rramesh@marvell.com> Signed-off-by: Frank Huang <frankh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex/sta_ioctl.c')
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c2478
1 files changed, 2478 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
new file mode 100644
index 000000000000..665a519b1403
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -0,0 +1,2478 @@
1/*
2 * Marvell Wireless LAN device driver: functions for station ioctl
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27#include "cfg80211.h"
28
29/*
30 * Copies the multicast address list from device to driver.
31 *
32 * This function does not validate the destination memory for
33 * size, and the calling function must ensure enough memory is
34 * available.
35 */
36static int
37mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
38 struct net_device *dev)
39{
40 int i = 0;
41 struct netdev_hw_addr *ha;
42
43 netdev_for_each_mc_addr(ha, dev)
44 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
45
46 return i;
47}
48
49/*
50 * Allocate and fills a wait queue with proper parameters.
51 *
52 * This function needs to be called before an IOCTL request can be made.
53 * It can handle the following wait options:
54 * MWIFIEX_NO_WAIT - Waiting is disabled
55 * MWIFIEX_IOCTL_WAIT - Waiting is done on IOCTL wait queue
56 * MWIFIEX_CMD_WAIT - Waiting is done on command wait queue
57 * MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue
58 */
59struct mwifiex_wait_queue *
60mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv,
61 u8 wait_option)
62{
63 struct mwifiex_wait_queue *wait = NULL;
64
65 wait = (struct mwifiex_wait_queue *)
66 kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC);
67 if (!wait) {
68 dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n",
69 __func__);
70 return wait;
71 }
72
73 wait->bss_index = priv->bss_index;
74
75 switch (wait_option) {
76 case MWIFIEX_NO_WAIT:
77 wait->enabled = 0;
78 break;
79 case MWIFIEX_IOCTL_WAIT:
80 priv->ioctl_wait_q_woken = false;
81 wait->start_time = jiffies;
82 wait->wait = &priv->ioctl_wait_q;
83 wait->condition = &priv->ioctl_wait_q_woken;
84 wait->enabled = 1;
85 break;
86 case MWIFIEX_CMD_WAIT:
87 priv->cmd_wait_q_woken = false;
88 wait->start_time = jiffies;
89 wait->wait = &priv->cmd_wait_q;
90 wait->condition = &priv->cmd_wait_q_woken;
91 wait->enabled = 1;
92 break;
93 case MWIFIEX_WSTATS_WAIT:
94 priv->w_stats_wait_q_woken = false;
95 wait->start_time = jiffies;
96 wait->wait = &priv->w_stats_wait_q;
97 wait->condition = &priv->w_stats_wait_q_woken;
98 wait->enabled = 1;
99 break;
100 }
101
102 return wait;
103}
104
105/*
106 * Wait queue completion handler.
107 *
108 * This function waits on a particular wait queue.
109 * For NO_WAIT option, it returns immediately. It also cancels the
110 * pending IOCTL request after waking up, in case of errors.
111 */
112static void
113mwifiex_wait_ioctl_complete(struct mwifiex_private *priv,
114 struct mwifiex_wait_queue *wait,
115 u8 wait_option)
116{
117 bool cancel_flag = false;
118
119 switch (wait_option) {
120 case MWIFIEX_NO_WAIT:
121 break;
122 case MWIFIEX_IOCTL_WAIT:
123 wait_event_interruptible(priv->ioctl_wait_q,
124 priv->ioctl_wait_q_woken);
125 if (!priv->ioctl_wait_q_woken)
126 cancel_flag = true;
127 break;
128 case MWIFIEX_CMD_WAIT:
129 wait_event_interruptible(priv->cmd_wait_q,
130 priv->cmd_wait_q_woken);
131 if (!priv->cmd_wait_q_woken)
132 cancel_flag = true;
133 break;
134 case MWIFIEX_WSTATS_WAIT:
135 wait_event_interruptible(priv->w_stats_wait_q,
136 priv->w_stats_wait_q_woken);
137 if (!priv->w_stats_wait_q_woken)
138 cancel_flag = true;
139 break;
140 }
141 if (cancel_flag) {
142 mwifiex_cancel_pending_ioctl(priv->adapter, wait);
143 dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n",
144 wait, wait_option);
145 }
146
147 return;
148}
149
150/*
151 * The function waits for the request to complete and issues the
152 * completion handler, if required.
153 */
154int mwifiex_request_ioctl(struct mwifiex_private *priv,
155 struct mwifiex_wait_queue *wait,
156 int status, u8 wait_option)
157{
158 switch (status) {
159 case -EINPROGRESS:
160 dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n",
161 wait, wait_option);
162 atomic_inc(&priv->adapter->ioctl_pending);
163 /* Status pending, wake up main process */
164 queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
165
166 /* Wait for completion */
167 if (wait_option) {
168 mwifiex_wait_ioctl_complete(priv, wait, wait_option);
169 status = wait->status;
170 }
171 break;
172 case 0:
173 case -1:
174 case -EBUSY:
175 default:
176 break;
177 }
178 return status;
179}
180EXPORT_SYMBOL_GPL(mwifiex_request_ioctl);
181
182/*
183 * IOCTL request handler to set/get MAC address.
184 *
185 * This function prepares the correct firmware command and
186 * issues it to get the extended version information.
187 */
188static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv,
189 struct mwifiex_wait_queue *wait,
190 u8 action, u8 *mac)
191{
192 int ret = 0;
193
194 if ((action == HostCmd_ACT_GEN_GET) && mac) {
195 memcpy(mac, priv->curr_addr, ETH_ALEN);
196 return 0;
197 }
198
199 /* Send request to firmware */
200 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
201 action, 0, wait, mac);
202 if (!ret)
203 ret = -EINPROGRESS;
204
205 return ret;
206}
207
208/*
209 * Sends IOCTL request to set MAC address.
210 *
211 * This function allocates the IOCTL request buffer, fills it
212 * with requisite parameters and calls the IOCTL handler.
213 */
214int mwifiex_request_set_mac_address(struct mwifiex_private *priv)
215{
216 struct mwifiex_wait_queue *wait = NULL;
217 int status = 0;
218 u8 wait_option = MWIFIEX_CMD_WAIT;
219
220 /* Allocate wait buffer */
221 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
222 if (!wait)
223 return -ENOMEM;
224
225 status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET,
226 NULL);
227
228 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
229 if (!status)
230 memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
231 else
232 dev_err(priv->adapter->dev, "set mac address failed: status=%d"
233 " error_code=%#x\n", status, wait->status);
234
235 kfree(wait);
236 return status;
237}
238
239/*
240 * IOCTL request handler to set multicast list.
241 *
242 * This function prepares the correct firmware command and
243 * issues it to set the multicast list.
244 *
245 * This function can be used to enable promiscuous mode, or enable all
246 * multicast packets, or to enable selective multicast.
247 */
248static int
249mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv,
250 struct mwifiex_wait_queue *wait,
251 u16 action,
252 struct mwifiex_multicast_list *mcast_list)
253{
254 int ret = 0;
255 u16 old_pkt_filter;
256
257 old_pkt_filter = priv->curr_pkt_filter;
258 if (action == HostCmd_ACT_GEN_GET)
259 return -1;
260
261 if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
262 dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
263 priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
264 priv->curr_pkt_filter &=
265 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
266 } else {
267 /* Multicast */
268 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
269 if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) {
270 dev_dbg(priv->adapter->dev,
271 "info: Enabling All Multicast!\n");
272 priv->curr_pkt_filter |=
273 HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
274 } else {
275 priv->curr_pkt_filter &=
276 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
277 if (mcast_list->num_multicast_addr) {
278 dev_dbg(priv->adapter->dev,
279 "info: Set multicast list=%d\n",
280 mcast_list->num_multicast_addr);
281 /* Set multicast addresses to firmware */
282 if (old_pkt_filter == priv->curr_pkt_filter) {
283 /* Send request to firmware */
284 ret = mwifiex_prepare_cmd(priv,
285 HostCmd_CMD_MAC_MULTICAST_ADR,
286 action, 0, wait, mcast_list);
287 if (!ret)
288 ret = -EINPROGRESS;
289 } else {
290 /* Send request to firmware */
291 ret = mwifiex_prepare_cmd(priv,
292 HostCmd_CMD_MAC_MULTICAST_ADR,
293 action, 0, NULL,
294 mcast_list);
295 }
296 }
297 }
298 }
299 dev_dbg(priv->adapter->dev,
300 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
301 old_pkt_filter, priv->curr_pkt_filter);
302 if (old_pkt_filter != priv->curr_pkt_filter) {
303 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action,
304 0, wait, &priv->curr_pkt_filter);
305 if (!ret)
306 ret = -EINPROGRESS;
307 }
308
309 return ret;
310}
311
312/*
313 * Sends IOCTL request to set multicast list.
314 *
315 * This function allocates the IOCTL request buffer, fills it
316 * with requisite parameters and calls the IOCTL handler.
317 */
318void
319mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
320 struct net_device *dev)
321{
322 struct mwifiex_wait_queue *wait = NULL;
323 struct mwifiex_multicast_list mcast_list;
324 u8 wait_option = MWIFIEX_NO_WAIT;
325 int status = 0;
326
327 /* Allocate wait buffer */
328 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
329 if (!wait)
330 return;
331
332 if (dev->flags & IFF_PROMISC) {
333 mcast_list.mode = MWIFIEX_PROMISC_MODE;
334 } else if (dev->flags & IFF_ALLMULTI ||
335 netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) {
336 mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
337 } else {
338 mcast_list.mode = MWIFIEX_MULTICAST_MODE;
339 if (netdev_mc_count(dev))
340 mcast_list.num_multicast_addr =
341 mwifiex_copy_mcast_addr(&mcast_list, dev);
342 }
343 status = mwifiex_bss_ioctl_multicast_list(priv, wait,
344 HostCmd_ACT_GEN_SET,
345 &mcast_list);
346
347 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
348 if (wait && status != -EINPROGRESS)
349 kfree(wait);
350
351 return;
352}
353
354/*
355 * IOCTL request handler to disconnect from a BSS/IBSS.
356 */
357static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv,
358 struct mwifiex_wait_queue *wait, u8 *mac)
359{
360 return mwifiex_deauthenticate(priv, wait, mac);
361}
362
363/*
364 * Sends IOCTL request to disconnect from a BSS.
365 *
366 * This function allocates the IOCTL request buffer, fills it
367 * with requisite parameters and calls the IOCTL handler.
368 */
369int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac)
370{
371 struct mwifiex_wait_queue *wait = NULL;
372 int status = 0;
373
374 /* Allocate wait buffer */
375 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
376 if (!wait)
377 return -ENOMEM;
378
379 status = mwifiex_bss_ioctl_stop(priv, wait, mac);
380
381 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
382
383 kfree(wait);
384 return status;
385}
386EXPORT_SYMBOL_GPL(mwifiex_disconnect);
387
388/*
389 * IOCTL request handler to join a BSS/IBSS.
390 *
391 * In Ad-Hoc mode, the IBSS is created if not found in scan list.
392 * In both Ad-Hoc and infra mode, an deauthentication is performed
393 * first.
394 */
395static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv,
396 struct mwifiex_wait_queue *wait,
397 struct mwifiex_ssid_bssid *ssid_bssid)
398{
399 int ret = 0;
400 struct mwifiex_adapter *adapter = priv->adapter;
401 s32 i = -1;
402
403 priv->scan_block = false;
404 if (!ssid_bssid)
405 return -1;
406
407 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) {
408 /* Infra mode */
409 ret = mwifiex_deauthenticate(priv, NULL, NULL);
410 if (ret)
411 return ret;
412
413 /* Search for the requested SSID in the scan table */
414 if (ssid_bssid->ssid.ssid_len)
415 i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid,
416 NULL, MWIFIEX_BSS_MODE_INFRA);
417 else
418 i = mwifiex_find_bssid_in_list(priv,
419 (u8 *) &ssid_bssid->bssid,
420 MWIFIEX_BSS_MODE_INFRA);
421 if (i < 0)
422 return -1;
423
424 dev_dbg(adapter->dev,
425 "info: SSID found in scan list ... associating...\n");
426
427 /* Clear any past association response stored for
428 * application retrieval */
429 priv->assoc_rsp_size = 0;
430 ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]);
431 if (ret)
432 return ret;
433 } else {
434 /* Adhoc mode */
435 /* If the requested SSID matches current SSID, return */
436 if (ssid_bssid->ssid.ssid_len &&
437 (!mwifiex_ssid_cmp
438 (&priv->curr_bss_params.bss_descriptor.ssid,
439 &ssid_bssid->ssid)))
440 return 0;
441
442 /* Exit Adhoc mode first */
443 dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
444 ret = mwifiex_deauthenticate(priv, NULL, NULL);
445 if (ret)
446 return ret;
447
448 priv->adhoc_is_link_sensed = false;
449
450 /* Search for the requested network in the scan table */
451 if (ssid_bssid->ssid.ssid_len)
452 i = mwifiex_find_ssid_in_list(priv,
453 &ssid_bssid->ssid, NULL,
454 MWIFIEX_BSS_MODE_IBSS);
455 else
456 i = mwifiex_find_bssid_in_list(priv,
457 (u8 *)&ssid_bssid->bssid,
458 MWIFIEX_BSS_MODE_IBSS);
459
460 if (i >= 0) {
461 dev_dbg(adapter->dev, "info: network found in scan"
462 " list. Joining...\n");
463 ret = mwifiex_adhoc_join(priv, wait,
464 &adapter->scan_table[i]);
465 if (ret)
466 return ret;
467 } else { /* i >= 0 */
468 dev_dbg(adapter->dev, "info: Network not found in "
469 "the list, creating adhoc with ssid = %s\n",
470 ssid_bssid->ssid.ssid);
471 ret = mwifiex_adhoc_start(priv, wait,
472 &ssid_bssid->ssid);
473 if (ret)
474 return ret;
475 }
476 }
477
478 if (!ret)
479 ret = -EINPROGRESS;
480
481 return ret;
482}
483
484/*
485 * Sends IOCTL request to connect with a BSS.
486 *
487 * This function allocates the IOCTL request buffer, fills it
488 * with requisite parameters and calls the IOCTL handler.
489 */
490int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option,
491 struct mwifiex_ssid_bssid *ssid_bssid)
492{
493 struct mwifiex_wait_queue *wait = NULL;
494 struct mwifiex_ssid_bssid tmp_ssid_bssid;
495 int status = 0;
496
497 /* Stop the O.S. TX queue if needed */
498 if (!netif_queue_stopped(priv->netdev))
499 netif_stop_queue(priv->netdev);
500
501 /* Allocate wait buffer */
502 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
503 if (!wait)
504 return -ENOMEM;
505
506 if (ssid_bssid)
507 memcpy(&tmp_ssid_bssid, ssid_bssid,
508 sizeof(struct mwifiex_ssid_bssid));
509 status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid);
510
511 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
512
513 kfree(wait);
514 return status;
515}
516
517/*
518 * IOCTL request handler to set host sleep configuration.
519 *
520 * This function prepares the correct firmware command and
521 * issues it.
522 */
523static int
524mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv,
525 struct mwifiex_wait_queue *wait,
526 u16 action, struct mwifiex_ds_hs_cfg *hs_cfg)
527{
528 struct mwifiex_adapter *adapter = priv->adapter;
529 int status = 0;
530 u32 prev_cond = 0;
531
532 switch (action) {
533 case HostCmd_ACT_GEN_SET:
534 if (adapter->pps_uapsd_mode) {
535 dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
536 " is blocked in UAPSD/PPS mode\n");
537 status = -1;
538 break;
539 }
540 if (hs_cfg->is_invoke_hostcmd) {
541 if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
542 if (!adapter->is_hs_configured)
543 /* Already cancelled */
544 break;
545 /* Save previous condition */
546 prev_cond = le32_to_cpu(adapter->hs_cfg
547 .conditions);
548 adapter->hs_cfg.conditions =
549 cpu_to_le32(hs_cfg->conditions);
550 } else if (hs_cfg->conditions) {
551 adapter->hs_cfg.conditions =
552 cpu_to_le32(hs_cfg->conditions);
553 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
554 if (hs_cfg->gap)
555 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
556 } else if (adapter->hs_cfg.conditions ==
557 cpu_to_le32(
558 HOST_SLEEP_CFG_CANCEL)) {
559 /* Return failure if no parameters for HS
560 enable */
561 status = -1;
562 break;
563 }
564 status = mwifiex_prepare_cmd(priv,
565 HostCmd_CMD_802_11_HS_CFG_ENH,
566 HostCmd_ACT_GEN_SET,
567 0, wait, &adapter->hs_cfg);
568 if (!status)
569 status = -EINPROGRESS;
570 if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
571 /* Restore previous condition */
572 adapter->hs_cfg.conditions =
573 cpu_to_le32(prev_cond);
574 } else {
575 adapter->hs_cfg.conditions =
576 cpu_to_le32(hs_cfg->conditions);
577 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
578 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
579 }
580 break;
581 case HostCmd_ACT_GEN_GET:
582 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
583 hs_cfg->gpio = adapter->hs_cfg.gpio;
584 hs_cfg->gap = adapter->hs_cfg.gap;
585 break;
586 default:
587 status = -1;
588 break;
589 }
590
591 return status;
592}
593
594/*
595 * Sends IOCTL request to set Host Sleep parameters.
596 *
597 * This function allocates the IOCTL request buffer, fills it
598 * with requisite parameters and calls the IOCTL handler.
599 */
600int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
601 u8 wait_option,
602 struct mwifiex_ds_hs_cfg *hscfg)
603{
604 int ret = 0;
605 struct mwifiex_wait_queue *wait = NULL;
606
607 if (!hscfg)
608 return -ENOMEM;
609
610 /* Allocate wait buffer */
611 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
612 if (!wait)
613 return -ENOMEM;
614
615 ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg);
616
617 ret = mwifiex_request_ioctl(priv, wait, ret, wait_option);
618
619 if (wait && (ret != -EINPROGRESS))
620 kfree(wait);
621 return ret;
622}
623
624/*
625 * Sends IOCTL request to cancel the existing Host Sleep configuration.
626 *
627 * This function allocates the IOCTL request buffer, fills it
628 * with requisite parameters and calls the IOCTL handler.
629 */
630int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option)
631{
632 int ret = 0;
633 struct mwifiex_ds_hs_cfg hscfg;
634
635 /* Cancel Host Sleep */
636 hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
637 hscfg.is_invoke_hostcmd = true;
638 ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
639 wait_option, &hscfg);
640
641 return ret;
642}
643EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
644
645/*
646 * Sends IOCTL request to cancel the existing Host Sleep configuration.
647 *
648 * This function allocates the IOCTL request buffer, fills it
649 * with requisite parameters and calls the IOCTL handler.
650 */
651int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
652{
653 struct mwifiex_ds_hs_cfg hscfg;
654
655 if (adapter->hs_activated) {
656 dev_dbg(adapter->dev, "cmd: HS Already actived\n");
657 return true;
658 }
659
660 /* Enable Host Sleep */
661 adapter->hs_activate_wait_q_woken = false;
662
663 memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param));
664 hscfg.is_invoke_hostcmd = true;
665
666 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
667 MWIFIEX_BSS_ROLE_STA),
668 HostCmd_ACT_GEN_SET,
669 MWIFIEX_IOCTL_WAIT, &hscfg)) {
670 dev_err(adapter->dev, "IOCTL request HS enable failed\n");
671 return false;
672 }
673
674 wait_event_interruptible(adapter->hs_activate_wait_q,
675 adapter->hs_activate_wait_q_woken);
676
677 return true;
678}
679EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
680
681/*
682 * IOCTL request handler to get signal information.
683 *
684 * This function prepares the correct firmware command and
685 * issues it to get the signal (RSSI) information.
686 *
687 * This only works in the connected mode.
688 */
689static int mwifiex_get_info_signal(struct mwifiex_private *priv,
690 struct mwifiex_wait_queue *wait,
691 struct mwifiex_ds_get_signal *signal)
692{
693 int ret = 0;
694
695 if (!wait) {
696 dev_err(priv->adapter->dev, "WAIT information is not present\n");
697 return -1;
698 }
699
700 /* Signal info can be obtained only if connected */
701 if (!priv->media_connected) {
702 dev_dbg(priv->adapter->dev,
703 "info: Can not get signal in disconnected state\n");
704 return -1;
705 }
706
707 /* Send request to firmware */
708 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO,
709 HostCmd_ACT_GEN_GET, 0, wait, signal);
710
711 if (!ret)
712 ret = -EINPROGRESS;
713
714 return ret;
715}
716
717/*
718 * IOCTL request handler to get statistics.
719 *
720 * This function prepares the correct firmware command and
721 * issues it to get the statistics (RSSI) information.
722 */
723static int mwifiex_get_info_stats(struct mwifiex_private *priv,
724 struct mwifiex_wait_queue *wait,
725 struct mwifiex_ds_get_stats *log)
726{
727 int ret = 0;
728
729 if (!wait) {
730 dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n");
731 return -1;
732 }
733
734 /* Send request to firmware */
735 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
736 HostCmd_ACT_GEN_GET, 0, wait, log);
737
738 if (!ret)
739 ret = -EINPROGRESS;
740
741 return ret;
742}
743
744/*
745 * IOCTL request handler to get BSS information.
746 *
747 * This function collates the information from different driver structures
748 * to send to the user.
749 */
750int mwifiex_get_bss_info(struct mwifiex_private *priv,
751 struct mwifiex_bss_info *info)
752{
753 struct mwifiex_adapter *adapter = priv->adapter;
754 struct mwifiex_bssdescriptor *bss_desc;
755 s32 tbl_idx = 0;
756
757 if (!info)
758 return -1;
759
760 /* Get current BSS info */
761 bss_desc = &priv->curr_bss_params.bss_descriptor;
762
763 /* BSS mode */
764 info->bss_mode = priv->bss_mode;
765
766 /* SSID */
767 memcpy(&info->ssid, &bss_desc->ssid,
768 sizeof(struct mwifiex_802_11_ssid));
769
770 /* BSSID */
771 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
772
773 /* Channel */
774 info->bss_chan = bss_desc->channel;
775
776 /* Region code */
777 info->region_code = adapter->region_code;
778
779 /* Scan table index if connected */
780 info->scan_table_idx = 0;
781 if (priv->media_connected) {
782 tbl_idx =
783 mwifiex_find_ssid_in_list(priv, &bss_desc->ssid,
784 bss_desc->mac_address,
785 priv->bss_mode);
786 if (tbl_idx >= 0)
787 info->scan_table_idx = tbl_idx;
788 }
789
790 /* Connection status */
791 info->media_connected = priv->media_connected;
792
793 /* Radio status */
794 info->radio_on = adapter->radio_on;
795
796 /* Tx power information */
797 info->max_power_level = priv->max_tx_power_level;
798 info->min_power_level = priv->min_tx_power_level;
799
800 /* AdHoc state */
801 info->adhoc_state = priv->adhoc_state;
802
803 /* Last beacon NF */
804 info->bcn_nf_last = priv->bcn_nf_last;
805
806 /* wep status */
807 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
808 info->wep_status = true;
809 else
810 info->wep_status = false;
811
812 info->is_hs_configured = adapter->is_hs_configured;
813 info->is_deep_sleep = adapter->is_deep_sleep;
814
815 return 0;
816}
817
818/*
819 * IOCTL request handler to get extended version information.
820 *
821 * This function prepares the correct firmware command and
822 * issues it to get the extended version information.
823 */
824static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv,
825 struct mwifiex_wait_queue *wait,
826 struct mwifiex_ver_ext *ver_ext)
827{
828 int ret = 0;
829
830 /* Send request to firmware */
831 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT,
832 HostCmd_ACT_GEN_GET, 0, wait, ver_ext);
833 if (!ret)
834 ret = -EINPROGRESS;
835
836 return ret;
837}
838
839/*
840 * IOCTL request handler to set/get SNMP MIB parameters.
841 *
842 * This function prepares the correct firmware command and
843 * issues it.
844 *
845 * Currently the following parameters are supported -
846 * Set/get RTS Threshold
847 * Set/get fragmentation threshold
848 * Set/get retry count
849 */
850int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv,
851 struct mwifiex_wait_queue *wait,
852 u32 cmd_oid, u16 action, u32 *value)
853{
854 int ret = 0;
855
856 if (!value)
857 return -1;
858
859 /* Send request to firmware */
860 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
861 action, cmd_oid, wait, value);
862
863 if (!ret)
864 ret = -EINPROGRESS;
865
866 return ret;
867}
868
869/*
870 * IOCTL request handler to set/get band configurations.
871 *
872 * For SET operation, it performs extra checks to make sure the Ad-Hoc
873 * band and channel are compatible. Otherwise it returns an error.
874 *
875 * For GET operation, this function retrieves the following information -
876 * - Infra bands
877 * - Ad-hoc band
878 * - Ad-hoc channel
879 * - Secondary channel offset
880 */
881int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv,
882 u16 action,
883 struct mwifiex_ds_band_cfg *radio_cfg)
884{
885 struct mwifiex_adapter *adapter = priv->adapter;
886 u8 infra_band = 0;
887 u8 adhoc_band = 0;
888 u32 adhoc_channel = 0;
889
890 if (action == HostCmd_ACT_GEN_GET) {
891 /* Infra Bands */
892 radio_cfg->config_bands = adapter->config_bands;
893 /* Adhoc Band */
894 radio_cfg->adhoc_start_band = adapter->adhoc_start_band;
895 /* Adhoc channel */
896 radio_cfg->adhoc_channel = priv->adhoc_channel;
897 /* Secondary channel offset */
898 radio_cfg->sec_chan_offset = adapter->chan_offset;
899 return 0;
900 }
901
902 /* For action = SET */
903 infra_band = (u8) radio_cfg->config_bands;
904 adhoc_band = (u8) radio_cfg->adhoc_start_band;
905 adhoc_channel = radio_cfg->adhoc_channel;
906
907 /* SET Infra band */
908 if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands)
909 return -1;
910
911 adapter->config_bands = infra_band;
912
913 /* SET Ad-hoc Band */
914 if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands)
915 return -1;
916
917 if (adhoc_band)
918 adapter->adhoc_start_band = adhoc_band;
919 adapter->chan_offset = (u8) radio_cfg->sec_chan_offset;
920 /*
921 * If no adhoc_channel is supplied verify if the existing adhoc
922 * channel compiles with new adhoc_band
923 */
924 if (!adhoc_channel) {
925 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
926 (priv, adapter->adhoc_start_band,
927 priv->adhoc_channel)) {
928 /* Pass back the default channel */
929 radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
930 if ((adapter->adhoc_start_band & BAND_A)
931 || (adapter->adhoc_start_band & BAND_AN))
932 radio_cfg->adhoc_channel =
933 DEFAULT_AD_HOC_CHANNEL_A;
934 }
935 } else { /* Retrurn error if adhoc_band and
936 adhoc_channel combination is invalid */
937 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
938 (priv, adapter->adhoc_start_band, (u16) adhoc_channel))
939 return -1;
940 priv->adhoc_channel = (u8) adhoc_channel;
941 }
942 if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN))
943 adapter->adhoc_11n_enabled = true;
944 else
945 adapter->adhoc_11n_enabled = false;
946
947 return 0;
948}
949
950/*
951 * IOCTL request handler to set/get active channel.
952 *
953 * This function performs validity checking on channel/frequency
954 * compatibility and returns failure if not valid.
955 */
956int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action,
957 struct mwifiex_chan_freq_power *chan)
958{
959 struct mwifiex_adapter *adapter = priv->adapter;
960 struct mwifiex_chan_freq_power *cfp = NULL;
961
962 if (!chan)
963 return -1;
964
965 if (action == HostCmd_ACT_GEN_GET) {
966 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
967 priv->curr_bss_params.band,
968 (u16) priv->curr_bss_params.bss_descriptor.
969 channel);
970 chan->channel = cfp->channel;
971 chan->freq = cfp->freq;
972
973 return 0;
974 }
975 if (!chan->channel && !chan->freq)
976 return -1;
977 if (adapter->adhoc_start_band & BAND_AN)
978 adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
979 else if (adapter->adhoc_start_band & BAND_A)
980 adapter->adhoc_start_band = BAND_G | BAND_B;
981 if (chan->channel) {
982 if (chan->channel <= MAX_CHANNEL_BAND_BG)
983 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
984 (priv, 0, (u16) chan->channel);
985 if (!cfp) {
986 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
987 (priv, BAND_A, (u16) chan->channel);
988 if (cfp) {
989 if (adapter->adhoc_11n_enabled)
990 adapter->adhoc_start_band = BAND_A
991 | BAND_AN;
992 else
993 adapter->adhoc_start_band = BAND_A;
994 }
995 }
996 } else {
997 if (chan->freq <= MAX_FREQUENCY_BAND_BG)
998 cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
999 priv, 0, chan->freq);
1000 if (!cfp) {
1001 cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211
1002 (priv, BAND_A, chan->freq);
1003 if (cfp) {
1004 if (adapter->adhoc_11n_enabled)
1005 adapter->adhoc_start_band = BAND_A
1006 | BAND_AN;
1007 else
1008 adapter->adhoc_start_band = BAND_A;
1009 }
1010 }
1011 }
1012 if (!cfp || !cfp->channel) {
1013 dev_err(adapter->dev, "invalid channel/freq\n");
1014 return -1;
1015 }
1016 priv->adhoc_channel = (u8) cfp->channel;
1017 chan->channel = cfp->channel;
1018 chan->freq = cfp->freq;
1019
1020 return 0;
1021}
1022
1023/*
1024 * IOCTL request handler to set/get BSS mode.
1025 *
1026 * This function prepares the correct firmware command and
1027 * issues it to set or get the BSS mode.
1028 *
1029 * In case the mode is changed, a deauthentication is performed
1030 * first by the function automatically.
1031 */
1032int mwifiex_bss_ioctl_mode(struct mwifiex_private *priv,
1033 struct mwifiex_wait_queue *wait,
1034 u16 action, int *mode)
1035{
1036 int ret = 0;
1037
1038 if (!mode)
1039 return -1;
1040
1041 if (action == HostCmd_ACT_GEN_GET) {
1042 *mode = priv->bss_mode;
1043 return 0;
1044 }
1045
1046 if ((priv->bss_mode == *mode) || (*mode == MWIFIEX_BSS_MODE_AUTO)) {
1047 dev_dbg(priv->adapter->dev,
1048 "info: Already set to required mode! No change!\n");
1049 priv->bss_mode = *mode;
1050 return 0;
1051 }
1052
1053 ret = mwifiex_deauthenticate(priv, wait, NULL);
1054
1055 priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN;
1056 priv->bss_mode = *mode;
1057 if (priv->bss_mode != MWIFIEX_BSS_MODE_AUTO) {
1058 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
1059 HostCmd_ACT_GEN_SET, 0, wait, NULL);
1060 if (!ret)
1061 ret = -EINPROGRESS;
1062 }
1063
1064 return ret;
1065}
1066
1067/*
1068 * IOCTL request handler to set/get Ad-Hoc channel.
1069 *
1070 * This function prepares the correct firmware command and
1071 * issues it to set or get the ad-hoc channel.
1072 */
1073static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
1074 struct mwifiex_wait_queue *wait,
1075 u16 action, u16 *channel)
1076{
1077 int ret = 0;
1078
1079 if (action == HostCmd_ACT_GEN_GET) {
1080 if (!priv->media_connected) {
1081 *channel = priv->adhoc_channel;
1082 return ret;
1083 }
1084 } else {
1085 priv->adhoc_channel = (u8) *channel;
1086 }
1087
1088 /* Send request to firmware */
1089 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
1090 action, 0, wait, channel);
1091 if (!ret)
1092 ret = -EINPROGRESS;
1093
1094 return ret;
1095}
1096
1097/*
1098 * IOCTL request handler to find a particular BSS.
1099 *
1100 * The BSS can be searched with either a BSSID or a SSID. If none of
1101 * these are provided, just the best BSS (best RSSI) is returned.
1102 */
1103int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv,
1104 struct mwifiex_wait_queue *wait,
1105 struct mwifiex_ssid_bssid *ssid_bssid)
1106{
1107 struct mwifiex_adapter *adapter = priv->adapter;
1108 int ret = 0;
1109 struct mwifiex_bssdescriptor *bss_desc;
1110 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
1111 u8 mac[ETH_ALEN];
1112 int i = 0;
1113
1114 if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
1115 i = mwifiex_find_bssid_in_list(priv,
1116 (u8 *) ssid_bssid->bssid,
1117 priv->bss_mode);
1118 if (i < 0) {
1119 memcpy(mac, ssid_bssid->bssid, sizeof(mac));
1120 dev_err(adapter->dev, "cannot find bssid %pM\n", mac);
1121 return -1;
1122 }
1123 bss_desc = &adapter->scan_table[i];
1124 memcpy(&ssid_bssid->ssid, &bss_desc->ssid,
1125 sizeof(struct mwifiex_802_11_ssid));
1126 } else if (ssid_bssid->ssid.ssid_len) {
1127 i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL,
1128 priv->bss_mode);
1129 if (i < 0) {
1130 dev_err(adapter->dev, "cannot find ssid %s\n",
1131 ssid_bssid->ssid.ssid);
1132 return -1;
1133 }
1134 bss_desc = &adapter->scan_table[i];
1135 memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN);
1136 } else {
1137 ret = mwifiex_find_best_network(priv, ssid_bssid);
1138 }
1139
1140 return ret;
1141}
1142
1143/*
1144 * IOCTL request handler to change Ad-Hoc channel.
1145 *
1146 * This function allocates the IOCTL request buffer, fills it
1147 * with requisite parameters and calls the IOCTL handler.
1148 *
1149 * The function follows the following steps to perform the change -
1150 * - Get current IBSS information
1151 * - Get current channel
1152 * - If no change is required, return
1153 * - If not connected, change channel and return
1154 * - If connected,
1155 * - Disconnect
1156 * - Change channel
1157 * - Perform specific SSID scan with same SSID
1158 * - Start/Join the IBSS
1159 */
1160int
1161mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
1162{
1163 int ret = 0;
1164 int status = 0;
1165 struct mwifiex_bss_info bss_info;
1166 struct mwifiex_wait_queue *wait = NULL;
1167 u8 wait_option = MWIFIEX_IOCTL_WAIT;
1168 struct mwifiex_ssid_bssid ssid_bssid;
1169 u16 curr_chan = 0;
1170
1171 memset(&bss_info, 0, sizeof(bss_info));
1172
1173 /* Get BSS information */
1174 if (mwifiex_get_bss_info(priv, &bss_info))
1175 return -1;
1176
1177 /* Allocate wait buffer */
1178 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1179 if (!wait)
1180 return -ENOMEM;
1181
1182 /* Get current channel */
1183 status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET,
1184 &curr_chan);
1185
1186 if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
1187 ret = -1;
1188 goto done;
1189 }
1190 if (curr_chan == channel) {
1191 ret = 0;
1192 goto done;
1193 }
1194 dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
1195 curr_chan, channel);
1196
1197 if (!bss_info.media_connected) {
1198 ret = 0;
1199 goto done;
1200 }
1201
1202 /* Do disonnect */
1203 memset(&ssid_bssid, 0, ETH_ALEN);
1204 status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid);
1205
1206 if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
1207 ret = -1;
1208 goto done;
1209 }
1210
1211 status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET,
1212 (u16 *) &channel);
1213
1214 if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
1215 ret = -1;
1216 goto done;
1217 }
1218
1219 /* Do specific SSID scanning */
1220 if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) {
1221 ret = -1;
1222 goto done;
1223 }
1224 /* Start/Join Adhoc network */
1225 memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
1226 memcpy(&ssid_bssid.ssid, &bss_info.ssid,
1227 sizeof(struct mwifiex_802_11_ssid));
1228
1229 status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid);
1230
1231 if (mwifiex_request_ioctl(priv, wait, status, wait_option))
1232 ret = -1;
1233
1234done:
1235 kfree(wait);
1236 return ret;
1237}
1238
1239/*
1240 * IOCTL request handler to get current driver mode.
1241 *
1242 * This function allocates the IOCTL request buffer, fills it
1243 * with requisite parameters and calls the IOCTL handler.
1244 */
1245int
1246mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option)
1247{
1248 struct mwifiex_wait_queue *wait = NULL;
1249 int status = 0;
1250 int mode = -1;
1251
1252 /* Allocate wait buffer */
1253 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1254 if (!wait)
1255 return -1;
1256
1257 status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_GET, &mode);
1258
1259 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
1260
1261 if (wait && (status != -EINPROGRESS))
1262 kfree(wait);
1263 return mode;
1264}
1265
1266/*
1267 * IOCTL request handler to get rate.
1268 *
1269 * This function prepares the correct firmware command and
1270 * issues it to get the current rate if it is connected,
1271 * otherwise, the function returns the lowest supported rate
1272 * for the band.
1273 */
1274static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
1275 struct mwifiex_wait_queue *wait,
1276 struct mwifiex_rate_cfg *rate_cfg)
1277{
1278 struct mwifiex_adapter *adapter = priv->adapter;
1279 int ret = 0;
1280
1281 rate_cfg->is_rate_auto = priv->is_data_rate_auto;
1282 if (!priv->media_connected) {
1283 switch (adapter->config_bands) {
1284 case BAND_B:
1285 /* Return the lowest supported rate for B band */
1286 rate_cfg->rate = supported_rates_b[0] & 0x7f;
1287 break;
1288 case BAND_G:
1289 case BAND_G | BAND_GN:
1290 /* Return the lowest supported rate for G band */
1291 rate_cfg->rate = supported_rates_g[0] & 0x7f;
1292 break;
1293 case BAND_B | BAND_G:
1294 case BAND_A | BAND_B | BAND_G:
1295 case BAND_A | BAND_B:
1296 case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
1297 case BAND_B | BAND_G | BAND_GN:
1298 /* Return the lowest supported rate for BG band */
1299 rate_cfg->rate = supported_rates_bg[0] & 0x7f;
1300 break;
1301 case BAND_A:
1302 case BAND_A | BAND_G:
1303 case BAND_A | BAND_G | BAND_AN | BAND_GN:
1304 case BAND_A | BAND_AN:
1305 /* Return the lowest supported rate for A band */
1306 rate_cfg->rate = supported_rates_a[0] & 0x7f;
1307 break;
1308 case BAND_GN:
1309 /* Return the lowest supported rate for N band */
1310 rate_cfg->rate = supported_rates_n[0] & 0x7f;
1311 break;
1312 default:
1313 dev_warn(adapter->dev, "invalid band %#x\n",
1314 adapter->config_bands);
1315 break;
1316 }
1317 } else {
1318 /* Send request to firmware */
1319 ret = mwifiex_prepare_cmd(priv,
1320 HostCmd_CMD_802_11_TX_RATE_QUERY,
1321 HostCmd_ACT_GEN_GET, 0, wait, NULL);
1322 if (!ret)
1323 ret = -EINPROGRESS;
1324 }
1325
1326 return ret;
1327}
1328
1329/*
1330 * IOCTL request handler to set rate.
1331 *
1332 * This function prepares the correct firmware command and
1333 * issues it to set the current rate.
1334 *
1335 * The function also performs validation checking on the supplied value.
1336 */
1337static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv,
1338 struct mwifiex_wait_queue *wait,
1339 struct mwifiex_rate_cfg *rate_cfg)
1340{
1341 u8 rates[MWIFIEX_SUPPORTED_RATES];
1342 u8 *rate = NULL;
1343 int rate_index = 0;
1344 u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
1345 u32 i = 0;
1346 int ret = 0;
1347 struct mwifiex_adapter *adapter = priv->adapter;
1348
1349 if (rate_cfg->is_rate_auto) {
1350 memset(bitmap_rates, 0, sizeof(bitmap_rates));
1351 /* Support all HR/DSSS rates */
1352 bitmap_rates[0] = 0x000F;
1353 /* Support all OFDM rates */
1354 bitmap_rates[1] = 0x00FF;
1355 /* Support all HT-MCSs rate */
1356 for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++)
1357 bitmap_rates[i + 2] = 0xFFFF;
1358 bitmap_rates[9] = 0x3FFF;
1359 } else {
1360 memset(rates, 0, sizeof(rates));
1361 mwifiex_get_active_data_rates(priv, rates);
1362 rate = rates;
1363 for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) {
1364 dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n",
1365 rate[i], rate_cfg->rate);
1366 if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f))
1367 break;
1368 }
1369 if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) {
1370 dev_err(adapter->dev, "fixed data rate %#x is out "
1371 "of range\n", rate_cfg->rate);
1372 return -1;
1373 }
1374 memset(bitmap_rates, 0, sizeof(bitmap_rates));
1375
1376 rate_index =
1377 mwifiex_data_rate_to_index(adapter, rate_cfg->rate);
1378
1379 /* Only allow b/g rates to be set */
1380 if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 &&
1381 rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) {
1382 bitmap_rates[0] = 1 << rate_index;
1383 } else {
1384 rate_index -= 1; /* There is a 0x00 in the table */
1385 if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 &&
1386 rate_index <= MWIFIEX_RATE_INDEX_OFDM7)
1387 bitmap_rates[1] = 1 << (rate_index -
1388 MWIFIEX_RATE_INDEX_OFDM0);
1389 }
1390 }
1391
1392 /* Send request to firmware */
1393 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
1394 HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates);
1395 if (!ret)
1396 ret = -EINPROGRESS;
1397
1398 return ret;
1399}
1400
1401/*
1402 * IOCTL request handler to set/get rate.
1403 *
1404 * This function can be used to set/get either the rate value or the
1405 * rate index.
1406 */
1407static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv,
1408 struct mwifiex_wait_queue *wait,
1409 struct mwifiex_rate_cfg *rate_cfg)
1410{
1411 int status = 0;
1412
1413 if (!rate_cfg)
1414 return -1;
1415
1416 if (rate_cfg->action == HostCmd_ACT_GEN_GET)
1417 status = mwifiex_rate_ioctl_get_rate_value(
1418 priv, wait, rate_cfg);
1419 else
1420 status = mwifiex_rate_ioctl_set_rate_value(
1421 priv, wait, rate_cfg);
1422
1423 return status;
1424}
1425
1426/*
1427 * Sends IOCTL request to get the data rate.
1428 *
1429 * This function allocates the IOCTL request buffer, fills it
1430 * with requisite parameters and calls the IOCTL handler.
1431 */
1432int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
1433 struct mwifiex_rate_cfg *rate)
1434{
1435 int ret = 0;
1436 struct mwifiex_wait_queue *wait = NULL;
1437 u8 wait_option = MWIFIEX_IOCTL_WAIT;
1438
1439 /* Allocate wait buffer */
1440 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1441 if (!wait)
1442 return -ENOMEM;
1443
1444 memset(rate, 0, sizeof(struct mwifiex_rate_cfg));
1445 rate->action = HostCmd_ACT_GEN_GET;
1446 ret = mwifiex_rate_ioctl_cfg(priv, wait, rate);
1447
1448 ret = mwifiex_request_ioctl(priv, wait, ret, wait_option);
1449 if (!ret) {
1450 if (rate && rate->is_rate_auto)
1451 rate->rate = mwifiex_index_to_data_rate(priv->adapter,
1452 priv->tx_rate, priv->tx_htinfo);
1453 else if (rate)
1454 rate->rate = priv->data_rate;
1455 } else {
1456 ret = -1;
1457 }
1458
1459 kfree(wait);
1460 return ret;
1461}
1462
1463/*
1464 * IOCTL request handler to set tx power configuration.
1465 *
1466 * This function prepares the correct firmware command and
1467 * issues it.
1468 *
1469 * For non-auto power mode, all the following power groups are set -
1470 * - Modulation class HR/DSSS
1471 * - Modulation class OFDM
1472 * - Modulation class HTBW20
1473 * - Modulation class HTBW40
1474 */
1475static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv,
1476 struct mwifiex_wait_queue *wait,
1477 struct mwifiex_power_cfg *power_cfg)
1478{
1479 int ret = 0;
1480 struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL;
1481 struct mwifiex_types_power_group *pg_tlv = NULL;
1482 struct mwifiex_power_group *pg = NULL;
1483 u8 *buf = NULL;
1484 u16 dbm = 0;
1485
1486 if (!power_cfg->is_power_auto) {
1487 dbm = (u16) power_cfg->power_level;
1488 if ((dbm < priv->min_tx_power_level) ||
1489 (dbm > priv->max_tx_power_level)) {
1490 dev_err(priv->adapter->dev, "txpower value %d dBm"
1491 " is out of range (%d dBm-%d dBm)\n",
1492 dbm, priv->min_tx_power_level,
1493 priv->max_tx_power_level);
1494 return -1;
1495 }
1496 }
1497 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
1498 if (!buf) {
1499 dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
1500 __func__);
1501 return -1;
1502 }
1503
1504 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
1505 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
1506 if (!power_cfg->is_power_auto) {
1507 txp_cfg->mode = cpu_to_le32(1);
1508 pg_tlv = (struct mwifiex_types_power_group *) (buf +
1509 sizeof(struct host_cmd_ds_txpwr_cfg));
1510 pg_tlv->type = TLV_TYPE_POWER_GROUP;
1511 pg_tlv->length = 4 * sizeof(struct mwifiex_power_group);
1512 pg = (struct mwifiex_power_group *) (buf +
1513 sizeof(struct host_cmd_ds_txpwr_cfg) +
1514 sizeof(struct mwifiex_types_power_group));
1515 /* Power group for modulation class HR/DSSS */
1516 pg->first_rate_code = 0x00;
1517 pg->last_rate_code = 0x03;
1518 pg->modulation_class = MOD_CLASS_HR_DSSS;
1519 pg->power_step = 0;
1520 pg->power_min = (s8) dbm;
1521 pg->power_max = (s8) dbm;
1522 pg++;
1523 /* Power group for modulation class OFDM */
1524 pg->first_rate_code = 0x00;
1525 pg->last_rate_code = 0x07;
1526 pg->modulation_class = MOD_CLASS_OFDM;
1527 pg->power_step = 0;
1528 pg->power_min = (s8) dbm;
1529 pg->power_max = (s8) dbm;
1530 pg++;
1531 /* Power group for modulation class HTBW20 */
1532 pg->first_rate_code = 0x00;
1533 pg->last_rate_code = 0x20;
1534 pg->modulation_class = MOD_CLASS_HT;
1535 pg->power_step = 0;
1536 pg->power_min = (s8) dbm;
1537 pg->power_max = (s8) dbm;
1538 pg->ht_bandwidth = HT_BW_20;
1539 pg++;
1540 /* Power group for modulation class HTBW40 */
1541 pg->first_rate_code = 0x00;
1542 pg->last_rate_code = 0x20;
1543 pg->modulation_class = MOD_CLASS_HT;
1544 pg->power_step = 0;
1545 pg->power_min = (s8) dbm;
1546 pg->power_max = (s8) dbm;
1547 pg->ht_bandwidth = HT_BW_40;
1548 }
1549 /* Send request to firmware */
1550 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG,
1551 HostCmd_ACT_GEN_SET, 0, wait, buf);
1552 if (!ret)
1553 ret = -EINPROGRESS;
1554 kfree(buf);
1555
1556 return ret;
1557}
1558
1559/*
1560 * IOCTL request handler to get power save mode.
1561 *
1562 * This function prepares the correct firmware command and
1563 * issues it.
1564 */
1565static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv,
1566 struct mwifiex_wait_queue *wait,
1567 u32 *ps_mode, u16 action)
1568{
1569 int ret = 0;
1570 struct mwifiex_adapter *adapter = priv->adapter;
1571 u16 sub_cmd;
1572
1573 if (action == HostCmd_ACT_GEN_SET) {
1574 if (*ps_mode)
1575 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1576 else
1577 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
1578 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
1579 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
1580 sub_cmd, BITMAP_STA_PS, wait, NULL);
1581 if ((!ret) && (sub_cmd == DIS_AUTO_PS))
1582 ret = mwifiex_prepare_cmd(priv,
1583 HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
1584 0, NULL, NULL);
1585 } else {
1586 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
1587 GET_PS, 0, wait, NULL);
1588 }
1589
1590 if (!ret)
1591 ret = -EINPROGRESS;
1592
1593 return ret;
1594}
1595
1596/*
1597 * IOCTL request handler to set/reset WPA IE.
1598 *
1599 * The supplied WPA IE is treated as a opaque buffer. Only the first field
1600 * is checked to determine WPA version. If buffer length is zero, the existing
1601 * WPA IE is reset.
1602 */
1603static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
1604 u8 *ie_data_ptr, u16 ie_len)
1605{
1606 if (ie_len) {
1607 if (ie_len > sizeof(priv->wpa_ie)) {
1608 dev_err(priv->adapter->dev,
1609 "failed to copy WPA IE, too big\n");
1610 return -1;
1611 }
1612 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
1613 priv->wpa_ie_len = (u8) ie_len;
1614 dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
1615 priv->wpa_ie_len, priv->wpa_ie[0]);
1616
1617 if (priv->wpa_ie[0] == WLAN_EID_WPA) {
1618 priv->sec_info.wpa_enabled = true;
1619 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
1620 priv->sec_info.wpa2_enabled = true;
1621 } else {
1622 priv->sec_info.wpa_enabled = false;
1623 priv->sec_info.wpa2_enabled = false;
1624 }
1625 } else {
1626 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
1627 priv->wpa_ie_len = 0;
1628 dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
1629 priv->wpa_ie_len, priv->wpa_ie[0]);
1630 priv->sec_info.wpa_enabled = false;
1631 priv->sec_info.wpa2_enabled = false;
1632 }
1633
1634 return 0;
1635}
1636
1637/*
1638 * IOCTL request handler to set/reset WAPI IE.
1639 *
1640 * The supplied WAPI IE is treated as a opaque buffer. Only the first field
1641 * is checked to internally enable WAPI. If buffer length is zero, the existing
1642 * WAPI IE is reset.
1643 */
1644static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
1645 u8 *ie_data_ptr, u16 ie_len)
1646{
1647 if (ie_len) {
1648 if (ie_len > sizeof(priv->wapi_ie)) {
1649 dev_dbg(priv->adapter->dev,
1650 "info: failed to copy WAPI IE, too big\n");
1651 return -1;
1652 }
1653 memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
1654 priv->wapi_ie_len = ie_len;
1655 dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
1656 priv->wapi_ie_len, priv->wapi_ie[0]);
1657
1658 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
1659 priv->sec_info.wapi_enabled = true;
1660 } else {
1661 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
1662 priv->wapi_ie_len = ie_len;
1663 dev_dbg(priv->adapter->dev,
1664 "info: Reset wapi_ie_len=%d IE=%#x\n",
1665 priv->wapi_ie_len, priv->wapi_ie[0]);
1666 priv->sec_info.wapi_enabled = false;
1667 }
1668 return 0;
1669}
1670
1671/*
1672 * IOCTL request handler to set WAPI key.
1673 *
1674 * This function prepares the correct firmware command and
1675 * issues it.
1676 */
1677static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter,
1678 struct mwifiex_wait_queue *wait,
1679 struct mwifiex_ds_encrypt_key *encrypt_key)
1680{
1681 int ret = 0;
1682 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
1683
1684 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1685 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1686 wait, encrypt_key);
1687 if (!ret)
1688 ret = -EINPROGRESS;
1689
1690 return ret;
1691}
1692
1693/*
1694 * IOCTL request handler to set/get authentication mode.
1695 */
1696static int mwifiex_set_auth_mode(struct mwifiex_private *priv, u32 auth_mode)
1697{
1698 int ret = 0;
1699
1700 priv->sec_info.authentication_mode = auth_mode;
1701 if (priv->sec_info.authentication_mode == MWIFIEX_AUTH_MODE_NETWORKEAP)
1702 ret = mwifiex_set_wpa_ie_helper(priv, NULL, 0);
1703
1704 return ret;
1705}
1706
1707/*
1708 * IOCTL request handler to set WEP network key.
1709 *
1710 * This function prepares the correct firmware command and
1711 * issues it, after validation checks.
1712 */
1713static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter,
1714 struct mwifiex_wait_queue *wait,
1715 struct mwifiex_ds_encrypt_key *encrypt_key)
1716{
1717 int ret = 0;
1718 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
1719 struct mwifiex_wep_key *wep_key = NULL;
1720 int index;
1721
1722 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
1723 priv->wep_key_curr_index = 0;
1724 wep_key = &priv->wep_key[priv->wep_key_curr_index];
1725 index = encrypt_key->key_index;
1726 if (encrypt_key->key_disable) {
1727 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
1728 } else if (!encrypt_key->key_len) {
1729 /* Copy the required key as the current key */
1730 wep_key = &priv->wep_key[index];
1731 if (!wep_key->key_length) {
1732 dev_err(adapter->dev,
1733 "key not set, so cannot enable it\n");
1734 return -1;
1735 }
1736 priv->wep_key_curr_index = (u16) index;
1737 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
1738 } else {
1739 wep_key = &priv->wep_key[index];
1740 /* Cleanup */
1741 memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
1742 /* Copy the key in the driver */
1743 memcpy(wep_key->key_material,
1744 encrypt_key->key_material,
1745 encrypt_key->key_len);
1746 wep_key->key_index = index;
1747 wep_key->key_length = encrypt_key->key_len;
1748 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
1749 }
1750 if (wep_key->key_length) {
1751 /* Send request to firmware */
1752 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1753 HostCmd_ACT_GEN_SET, 0, NULL, NULL);
1754 if (ret)
1755 return ret;
1756 }
1757 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
1758 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
1759 else
1760 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
1761
1762 /* Send request to firmware */
1763 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1764 HostCmd_ACT_GEN_SET, 0, wait,
1765 &priv->curr_pkt_filter);
1766 if (!ret)
1767 ret = -EINPROGRESS;
1768
1769 return ret;
1770}
1771
1772/*
1773 * IOCTL request handler to set WPA key.
1774 *
1775 * This function prepares the correct firmware command and
1776 * issues it, after validation checks.
1777 *
1778 * Current driver only supports key length of up to 32 bytes.
1779 *
1780 * This function can also be used to disable a currently set key.
1781 */
1782static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter,
1783 struct mwifiex_wait_queue *wait,
1784 struct mwifiex_ds_encrypt_key *encrypt_key)
1785{
1786 int ret = 0;
1787 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
1788 u8 remove_key = false;
1789 struct host_cmd_ds_802_11_key_material *ibss_key;
1790
1791 /* Current driver only supports key length of up to 32 bytes */
1792 if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) {
1793 dev_err(adapter->dev, "key length too long\n");
1794 return -1;
1795 }
1796
1797 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
1798 /*
1799 * IBSS/WPA-None uses only one key (Group) for both receiving
1800 * and sending unicast and multicast packets.
1801 */
1802 /* Send the key as PTK to firmware */
1803 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1804 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1805 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1806 NULL, encrypt_key);
1807 if (ret)
1808 return ret;
1809
1810 ibss_key = &priv->aes_key;
1811 memset(ibss_key, 0,
1812 sizeof(struct host_cmd_ds_802_11_key_material));
1813 /* Copy the key in the driver */
1814 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
1815 encrypt_key->key_len);
1816 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
1817 sizeof(ibss_key->key_param_set.key_len));
1818 ibss_key->key_param_set.key_type_id
1819 = cpu_to_le16(KEY_TYPE_ID_TKIP);
1820 ibss_key->key_param_set.key_info
1821 = cpu_to_le16(KEY_INFO_TKIP_ENABLED);
1822
1823 /* Send the key as GTK to firmware */
1824 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
1825 }
1826
1827 if (!encrypt_key->key_index)
1828 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1829
1830 if (remove_key)
1831 /* Send request to firmware */
1832 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1833 HostCmd_ACT_GEN_SET,
1834 !(KEY_INFO_ENABLED),
1835 wait, encrypt_key);
1836 else
1837 /* Send request to firmware */
1838 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1839 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1840 wait, encrypt_key);
1841
1842 if (!ret)
1843 ret = -EINPROGRESS;
1844
1845 return ret;
1846}
1847
1848/*
1849 * IOCTL request handler to set/get network keys.
1850 *
1851 * This is a generic key handling function which supports WEP, WPA
1852 * and WAPI.
1853 */
1854static int
1855mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
1856 struct mwifiex_wait_queue *wait,
1857 struct mwifiex_ds_encrypt_key *encrypt_key)
1858{
1859 int status = 0;
1860 struct mwifiex_adapter *adapter = priv->adapter;
1861
1862 if (encrypt_key->is_wapi_key)
1863 status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait,
1864 encrypt_key);
1865 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
1866 status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait,
1867 encrypt_key);
1868 else
1869 status = mwifiex_sec_ioctl_set_wep_key(adapter, wait,
1870 encrypt_key);
1871 return status;
1872}
1873
1874/*
1875 * This function returns the driver version.
1876 */
1877int
1878mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
1879 int max_len)
1880{
1881 union {
1882 u32 l;
1883 u8 c[4];
1884 } ver;
1885 char fw_ver[32];
1886
1887 ver.l = adapter->fw_release_number;
1888 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
1889
1890 snprintf(version, max_len, driver_version, fw_ver);
1891
1892 dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
1893
1894 return 0;
1895}
1896
1897/*
1898 * Sends IOCTL request to set Tx power. It can be set to either auto
1899 * or a fixed value.
1900 *
1901 * This function allocates the IOCTL request buffer, fills it
1902 * with requisite parameters and calls the IOCTL handler.
1903 */
1904int
1905mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm)
1906{
1907 struct mwifiex_power_cfg power_cfg;
1908 struct mwifiex_wait_queue *wait = NULL;
1909 int status = 0;
1910 int ret = 0;
1911
1912 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
1913 if (!wait)
1914 return -ENOMEM;
1915
1916 if (type == NL80211_TX_POWER_FIXED) {
1917 power_cfg.is_power_auto = 0;
1918 power_cfg.power_level = dbm;
1919 } else {
1920 power_cfg.is_power_auto = 1;
1921 }
1922 status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg);
1923
1924 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
1925
1926 kfree(wait);
1927 return ret;
1928}
1929
1930/*
1931 * Sends IOCTL request to get scan table.
1932 *
1933 * This function allocates the IOCTL request buffer, fills it
1934 * with requisite parameters and calls the IOCTL handler.
1935 */
1936int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option,
1937 struct mwifiex_scan_resp *scan_resp)
1938{
1939 struct mwifiex_wait_queue *wait = NULL;
1940 struct mwifiex_scan_resp scan;
1941 int status = 0;
1942
1943 /* Allocate wait buffer */
1944 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1945 if (!wait)
1946 return -ENOMEM;
1947
1948 status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET,
1949 NULL, &scan);
1950
1951 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
1952 if (!status) {
1953 if (scan_resp)
1954 memcpy(scan_resp, &scan,
1955 sizeof(struct mwifiex_scan_resp));
1956 }
1957
1958 if (wait && (status != -EINPROGRESS))
1959 kfree(wait);
1960 return status;
1961}
1962
1963/*
1964 * Sends IOCTL request to get signal information.
1965 *
1966 * This function allocates the IOCTL request buffer, fills it
1967 * with requisite parameters and calls the IOCTL handler.
1968 */
1969int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option,
1970 struct mwifiex_ds_get_signal *signal)
1971{
1972 struct mwifiex_ds_get_signal info;
1973 struct mwifiex_wait_queue *wait = NULL;
1974 int status = 0;
1975
1976 /* Allocate wait buffer */
1977 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1978 if (!wait)
1979 return -ENOMEM;
1980
1981 info.selector = ALL_RSSI_INFO_MASK;
1982
1983 status = mwifiex_get_info_signal(priv, wait, &info);
1984
1985 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
1986 if (!status) {
1987 if (signal)
1988 memcpy(signal, &info,
1989 sizeof(struct mwifiex_ds_get_signal));
1990 if (info.selector & BCN_RSSI_AVG_MASK)
1991 priv->w_stats.qual.level = info.bcn_rssi_avg;
1992 if (info.selector & BCN_NF_AVG_MASK)
1993 priv->w_stats.qual.noise = info.bcn_nf_avg;
1994 }
1995
1996 if (wait && (status != -EINPROGRESS))
1997 kfree(wait);
1998 return status;
1999}
2000
2001/*
2002 * Sends IOCTL request to set encryption mode.
2003 *
2004 * This function allocates the IOCTL request buffer, fills it
2005 * with requisite parameters and calls the IOCTL handler.
2006 */
2007static int mwifiex_set_encrypt_mode(struct mwifiex_private *priv,
2008 u8 wait_option, u32 encrypt_mode)
2009{
2010 priv->sec_info.encryption_mode = encrypt_mode;
2011 return 0;
2012}
2013
2014/*
2015 * This function set the authentication parameters. It sets both encryption
2016 * mode and authentication mode, and also enables WPA if required.
2017 */
2018int
2019mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode,
2020 int auth_mode, int wpa_enabled)
2021{
2022 if (mwifiex_set_encrypt_mode(priv, MWIFIEX_IOCTL_WAIT, encrypt_mode))
2023 return -EFAULT;
2024
2025 if (mwifiex_set_auth_mode(priv, auth_mode))
2026 return -EFAULT;
2027
2028 return 0;
2029}
2030
2031/*
2032 * Sends IOCTL request to set encoding parameters.
2033 *
2034 * This function allocates the IOCTL request buffer, fills it
2035 * with requisite parameters and calls the IOCTL handler.
2036 */
2037int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
2038 int key_len, u8 key_index, int disable)
2039{
2040 struct mwifiex_wait_queue *wait = NULL;
2041 struct mwifiex_ds_encrypt_key encrypt_key;
2042 int status = 0;
2043 int ret = 0;
2044
2045 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2046 if (!wait)
2047 return -ENOMEM;
2048
2049 memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
2050 encrypt_key.key_len = key_len;
2051 if (!disable) {
2052 encrypt_key.key_index = key_index;
2053 if (key_len)
2054 memcpy(encrypt_key.key_material, key, key_len);
2055 } else {
2056 encrypt_key.key_disable = true;
2057 }
2058
2059 status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key);
2060
2061 if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT))
2062 ret = -EFAULT;
2063
2064 kfree(wait);
2065 return ret;
2066}
2067
2068/*
2069 * Sends IOCTL request to set power management parameters.
2070 *
2071 * This function allocates the IOCTL request buffer, fills it
2072 * with requisite parameters and calls the IOCTL handler.
2073 */
2074int
2075mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on)
2076{
2077 int ret = 0;
2078 int status = 0;
2079 struct mwifiex_wait_queue *wait = NULL;
2080 u32 ps_mode;
2081
2082 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2083 if (!wait)
2084 return -ENOMEM;
2085
2086 ps_mode = power_on;
2087 status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode,
2088 HostCmd_ACT_GEN_SET);
2089
2090 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2091
2092 kfree(wait);
2093 return ret;
2094}
2095
2096/*
2097 * Sends IOCTL request to get extended version.
2098 *
2099 * This function allocates the IOCTL request buffer, fills it
2100 * with requisite parameters and calls the IOCTL handler.
2101 */
2102int
2103mwifiex_get_ver_ext(struct mwifiex_private *priv)
2104{
2105 struct mwifiex_ver_ext ver_ext;
2106 struct mwifiex_wait_queue *wait = NULL;
2107 int status = 0;
2108 int ret = 0;
2109 u8 wait_option = MWIFIEX_IOCTL_WAIT;
2110
2111 /* Allocate wait buffer */
2112 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
2113 if (!wait)
2114 return -ENOMEM;
2115
2116 /* get fw version */
2117 memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
2118 status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext);
2119
2120 ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
2121
2122 if (ret)
2123 ret = -1;
2124
2125 kfree(wait);
2126 return ret;
2127}
2128
2129/*
2130 * Sends IOCTL request to get statistics information.
2131 *
2132 * This function allocates the IOCTL request buffer, fills it
2133 * with requisite parameters and calls the IOCTL handler.
2134 */
2135int
2136mwifiex_get_stats_info(struct mwifiex_private *priv,
2137 struct mwifiex_ds_get_stats *log)
2138{
2139 int ret = 0;
2140 int status = 0;
2141 struct mwifiex_wait_queue *wait = NULL;
2142 struct mwifiex_ds_get_stats get_log;
2143 u8 wait_option = MWIFIEX_IOCTL_WAIT;
2144
2145 /* Allocate wait buffer */
2146 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
2147 if (!wait)
2148 return -ENOMEM;
2149
2150 memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats));
2151 status = mwifiex_get_info_stats(priv, wait, &get_log);
2152
2153 /* Send IOCTL request to MWIFIEX */
2154 ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
2155 if (!ret) {
2156 if (log)
2157 memcpy(log, &get_log, sizeof(struct
2158 mwifiex_ds_get_stats));
2159 priv->w_stats.discard.fragment = get_log.fcs_error;
2160 priv->w_stats.discard.retries = get_log.retry;
2161 priv->w_stats.discard.misc = get_log.ack_failure;
2162 }
2163
2164 kfree(wait);
2165 return ret;
2166}
2167
2168/*
2169 * IOCTL request handler to read/write register.
2170 *
2171 * This function prepares the correct firmware command and
2172 * issues it.
2173 *
2174 * Access to the following registers are supported -
2175 * - MAC
2176 * - BBP
2177 * - RF
2178 * - PMIC
2179 * - CAU
2180 */
2181static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
2182 struct mwifiex_wait_queue *wait,
2183 struct mwifiex_ds_reg_rw *reg_rw,
2184 u16 action)
2185{
2186 int ret = 0;
2187 u16 cmd_no;
2188
2189 switch (le32_to_cpu(reg_rw->type)) {
2190 case MWIFIEX_REG_MAC:
2191 cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
2192 break;
2193 case MWIFIEX_REG_BBP:
2194 cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
2195 break;
2196 case MWIFIEX_REG_RF:
2197 cmd_no = HostCmd_CMD_RF_REG_ACCESS;
2198 break;
2199 case MWIFIEX_REG_PMIC:
2200 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
2201 break;
2202 case MWIFIEX_REG_CAU:
2203 cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
2204 break;
2205 default:
2206 return -1;
2207 }
2208
2209 /* Send request to firmware */
2210 ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw);
2211
2212 if (!ret)
2213 ret = -EINPROGRESS;
2214
2215 return ret;
2216}
2217
2218/*
2219 * Sends IOCTL request to write to a register.
2220 *
2221 * This function allocates the IOCTL request buffer, fills it
2222 * with requisite parameters and calls the IOCTL handler.
2223 */
2224int
2225mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
2226 u32 reg_offset, u32 reg_value)
2227{
2228 int ret = 0;
2229 int status = 0;
2230 struct mwifiex_wait_queue *wait = NULL;
2231 struct mwifiex_ds_reg_rw reg_rw;
2232
2233 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2234 if (!wait)
2235 return -ENOMEM;
2236
2237 reg_rw.type = cpu_to_le32(reg_type);
2238 reg_rw.offset = cpu_to_le32(reg_offset);
2239 reg_rw.value = cpu_to_le32(reg_value);
2240 status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, &reg_rw,
2241 HostCmd_ACT_GEN_SET);
2242
2243 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2244
2245 kfree(wait);
2246 return ret;
2247}
2248
2249/*
2250 * Sends IOCTL request to read from a register.
2251 *
2252 * This function allocates the IOCTL request buffer, fills it
2253 * with requisite parameters and calls the IOCTL handler.
2254 */
2255int
2256mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
2257 u32 reg_offset, u32 *value)
2258{
2259 int ret = 0;
2260 int status = 0;
2261 struct mwifiex_wait_queue *wait = NULL;
2262 struct mwifiex_ds_reg_rw reg_rw;
2263
2264 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2265 if (!wait)
2266 return -ENOMEM;
2267
2268 reg_rw.type = cpu_to_le32(reg_type);
2269 reg_rw.offset = cpu_to_le32(reg_offset);
2270 status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, &reg_rw,
2271 HostCmd_ACT_GEN_GET);
2272
2273 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2274 if (ret)
2275 goto done;
2276
2277 *value = le32_to_cpu(reg_rw.value);
2278
2279done:
2280 kfree(wait);
2281 return ret;
2282}
2283
2284/*
2285 * IOCTL request handler to read EEPROM.
2286 *
2287 * This function prepares the correct firmware command and
2288 * issues it.
2289 */
2290static int
2291mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv,
2292 struct mwifiex_wait_queue *wait,
2293 struct mwifiex_ds_read_eeprom *rd_eeprom)
2294{
2295 int ret = 0;
2296
2297 /* Send request to firmware */
2298 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
2299 HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom);
2300
2301 if (!ret)
2302 ret = -EINPROGRESS;
2303
2304 return ret;
2305}
2306
2307/*
2308 * Sends IOCTL request to read from EEPROM.
2309 *
2310 * This function allocates the IOCTL request buffer, fills it
2311 * with requisite parameters and calls the IOCTL handler.
2312 */
2313int
2314mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
2315 u8 *value)
2316{
2317 int ret = 0;
2318 int status = 0;
2319 struct mwifiex_wait_queue *wait = NULL;
2320 struct mwifiex_ds_read_eeprom rd_eeprom;
2321
2322 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2323 if (!wait)
2324 return -ENOMEM;
2325
2326 rd_eeprom.offset = cpu_to_le16((u16) offset);
2327 rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
2328 status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom);
2329
2330 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2331 if (ret)
2332 goto done;
2333
2334 memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
2335done:
2336 kfree(wait);
2337 return ret;
2338}
2339
2340/*
2341 * This function sets a generic IE. In addition to generic IE, it can
2342 * also handle WPA, WPA2 and WAPI IEs.
2343 */
2344static int
2345mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
2346 u16 ie_len)
2347{
2348 int ret = 0;
2349 struct ieee_types_vendor_header *pvendor_ie;
2350 const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
2351 const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
2352
2353 /* If the passed length is zero, reset the buffer */
2354 if (!ie_len) {
2355 priv->gen_ie_buf_len = 0;
2356 priv->wps.session_enable = false;
2357
2358 return 0;
2359 } else if (!ie_data_ptr) {
2360 return -1;
2361 }
2362 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
2363 /* Test to see if it is a WPA IE, if not, then it is a gen IE */
2364 if (((pvendor_ie->element_id == WLAN_EID_WPA)
2365 && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
2366 || (pvendor_ie->element_id == WLAN_EID_RSN)) {
2367
2368 /* IE is a WPA/WPA2 IE so call set_wpa function */
2369 ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
2370 priv->wps.session_enable = false;
2371
2372 return ret;
2373 } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
2374 /* IE is a WAPI IE so call set_wapi function */
2375 ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len);
2376
2377 return ret;
2378 }
2379 /*
2380 * Verify that the passed length is not larger than the
2381 * available space remaining in the buffer
2382 */
2383 if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
2384
2385 /* Test to see if it is a WPS IE, if so, enable
2386 * wps session flag
2387 */
2388 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
2389 if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC)
2390 && (!memcmp(pvendor_ie->oui, wps_oui,
2391 sizeof(wps_oui)))) {
2392 priv->wps.session_enable = true;
2393 dev_dbg(priv->adapter->dev,
2394 "info: WPS Session Enabled.\n");
2395 }
2396
2397 /* Append the passed data to the end of the
2398 genIeBuffer */
2399 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
2400 ie_len);
2401 /* Increment the stored buffer length by the
2402 size passed */
2403 priv->gen_ie_buf_len += ie_len;
2404 } else {
2405 /* Passed data does not fit in the remaining
2406 buffer space */
2407 ret = -1;
2408 }
2409
2410 /* Return 0, or -1 for error case */
2411 return ret;
2412}
2413
2414/*
2415 * IOCTL request handler to set/get generic IE.
2416 *
2417 * In addition to various generic IEs, this function can also be
2418 * used to set the ARP filter.
2419 */
2420static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
2421 struct mwifiex_ds_misc_gen_ie *gen_ie,
2422 u16 action)
2423{
2424 struct mwifiex_adapter *adapter = priv->adapter;
2425
2426 switch (gen_ie->type) {
2427 case MWIFIEX_IE_TYPE_GEN_IE:
2428 if (action == HostCmd_ACT_GEN_GET) {
2429 gen_ie->len = priv->wpa_ie_len;
2430 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
2431 } else {
2432 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
2433 (u16) gen_ie->len);
2434 }
2435 break;
2436 case MWIFIEX_IE_TYPE_ARP_FILTER:
2437 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
2438 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
2439 adapter->arp_filter_size = 0;
2440 dev_err(adapter->dev, "invalid ARP filter size\n");
2441 return -1;
2442 } else {
2443 memcpy(adapter->arp_filter, gen_ie->ie_data,
2444 gen_ie->len);
2445 adapter->arp_filter_size = gen_ie->len;
2446 }
2447 break;
2448 default:
2449 dev_err(adapter->dev, "invalid IE type\n");
2450 return -1;
2451 }
2452 return 0;
2453}
2454
2455/*
2456 * Sends IOCTL request to set a generic IE.
2457 *
2458 * This function allocates the IOCTL request buffer, fills it
2459 * with requisite parameters and calls the IOCTL handler.
2460 */
2461int
2462mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
2463{
2464 struct mwifiex_ds_misc_gen_ie gen_ie;
2465 int status = 0;
2466
2467 if (ie_len > IW_CUSTOM_MAX)
2468 return -EFAULT;
2469
2470 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
2471 gen_ie.len = ie_len;
2472 memcpy(gen_ie.ie_data, ie, ie_len);
2473 status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET);
2474 if (status)
2475 return -EFAULT;
2476
2477 return 0;
2478}