1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * NXP Wireless LAN device driver: functions for station ioctl
4 *
5 * Copyright 2011-2020 NXP
6 */
7
8 #include "decl.h"
9 #include "ioctl.h"
10 #include "util.h"
11 #include "fw.h"
12 #include "main.h"
13 #include "wmm.h"
14 #include "11n.h"
15 #include "cfg80211.h"
16
17 static int disconnect_on_suspend;
18 module_param(disconnect_on_suspend, int, 0644);
19
20 /*
21 * Copies the multicast address list from device to driver.
22 *
23 * This function does not validate the destination memory for
24 * size, and the calling function must ensure enough memory is
25 * available.
26 */
mwifiex_copy_mcast_addr(struct mwifiex_multicast_list * mlist,struct net_device * dev)27 int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
28 struct net_device *dev)
29 {
30 int i = 0;
31 struct netdev_hw_addr *ha;
32
33 netdev_for_each_mc_addr(ha, dev)
34 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
35
36 return i;
37 }
38
39 /*
40 * Wait queue completion handler.
41 *
42 * This function waits on a cmd wait queue. It also cancels the pending
43 * request after waking up, in case of errors.
44 */
mwifiex_wait_queue_complete(struct mwifiex_adapter * adapter,struct cmd_ctrl_node * cmd_queued)45 int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
46 struct cmd_ctrl_node *cmd_queued)
47 {
48 int status;
49
50 /* Wait for completion */
51 status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait,
52 *(cmd_queued->condition),
53 (12 * HZ));
54 if (status <= 0) {
55 if (status == 0)
56 status = -ETIMEDOUT;
57 mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",
58 status);
59 mwifiex_cancel_all_pending_cmd(adapter);
60
61 /* The command response path writes through cmd_node->data_buf.
62 * On an interrupted wait, the caller can return and release a
63 * stack-allocated data_buf before a late firmware response is
64 * processed. Detach the caller-owned buffer from the current
65 * command so a late response cannot corrupt freed stack memory.
66 */
67 spin_lock_bh(&adapter->mwifiex_cmd_lock);
68 if (adapter->curr_cmd == cmd_queued)
69 adapter->curr_cmd->data_buf = NULL;
70 spin_unlock_bh(&adapter->mwifiex_cmd_lock);
71
72 return status;
73 }
74
75 status = adapter->cmd_wait_q.status;
76 adapter->cmd_wait_q.status = 0;
77
78 return status;
79 }
80
81 /*
82 * This function prepares the correct firmware command and
83 * issues it to set the multicast list.
84 *
85 * This function can be used to enable promiscuous mode, or enable all
86 * multicast packets, or to enable selective multicast.
87 */
mwifiex_request_set_multicast_list(struct mwifiex_private * priv,struct mwifiex_multicast_list * mcast_list)88 int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
89 struct mwifiex_multicast_list *mcast_list)
90 {
91 int ret = 0;
92 u16 old_pkt_filter;
93
94 old_pkt_filter = priv->curr_pkt_filter;
95
96 if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
97 mwifiex_dbg(priv->adapter, INFO,
98 "info: Enable Promiscuous mode\n");
99 priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
100 priv->curr_pkt_filter &=
101 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
102 } else {
103 /* Multicast */
104 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
105 if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {
106 mwifiex_dbg(priv->adapter, INFO,
107 "info: Enabling All Multicast!\n");
108 priv->curr_pkt_filter |=
109 HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
110 } else {
111 priv->curr_pkt_filter &=
112 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
113 mwifiex_dbg(priv->adapter, INFO,
114 "info: Set multicast list=%d\n",
115 mcast_list->num_multicast_addr);
116 /* Send multicast addresses to firmware */
117 ret = mwifiex_send_cmd(priv,
118 HostCmd_CMD_MAC_MULTICAST_ADR,
119 HostCmd_ACT_GEN_SET, 0,
120 mcast_list, false);
121 }
122 }
123 mwifiex_dbg(priv->adapter, INFO,
124 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
125 old_pkt_filter, priv->curr_pkt_filter);
126 if (old_pkt_filter != priv->curr_pkt_filter) {
127 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
128 HostCmd_ACT_GEN_SET,
129 0, &priv->curr_pkt_filter, false);
130 }
131
132 return ret;
133 }
134
135 /*
136 * This function fills bss descriptor structure using provided
137 * information.
138 * beacon_ie buffer is allocated in this function. It is caller's
139 * responsibility to free the memory.
140 */
mwifiex_fill_new_bss_desc(struct mwifiex_private * priv,struct cfg80211_bss * bss,struct mwifiex_bssdescriptor * bss_desc)141 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
142 struct cfg80211_bss *bss,
143 struct mwifiex_bssdescriptor *bss_desc)
144 {
145 u8 *beacon_ie;
146 size_t beacon_ie_len;
147 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
148 const struct cfg80211_bss_ies *ies;
149
150 rcu_read_lock();
151 ies = rcu_dereference(bss->ies);
152 beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
153 beacon_ie_len = ies->len;
154 bss_desc->timestamp = ies->tsf;
155 rcu_read_unlock();
156
157 if (!beacon_ie) {
158 mwifiex_dbg(priv->adapter, ERROR,
159 " failed to alloc beacon_ie\n");
160 return -ENOMEM;
161 }
162
163 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
164 bss_desc->rssi = bss->signal;
165 /* The caller of this function will free beacon_ie */
166 bss_desc->beacon_buf = beacon_ie;
167 bss_desc->beacon_buf_size = beacon_ie_len;
168 bss_desc->beacon_period = bss->beacon_interval;
169 bss_desc->cap_info_bitmap = bss->capability;
170 bss_desc->bss_band = bss_priv->band;
171 bss_desc->fw_tsf = bss_priv->fw_tsf;
172 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
173 mwifiex_dbg(priv->adapter, INFO,
174 "info: InterpretIE: AP WEP enabled\n");
175 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
176 } else {
177 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
178 }
179 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
180 bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
181 else
182 bss_desc->bss_mode = NL80211_IFTYPE_STATION;
183
184 /* Disable 11ac by default. Enable it only where there
185 * exist VHT_CAP IE in AP beacon
186 */
187 bss_desc->disable_11ac = true;
188
189 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
190 bss_desc->sensed_11h = true;
191
192 return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
193 }
194
mwifiex_dnld_dt_txpwr_table(struct mwifiex_private * priv)195 static void mwifiex_dnld_dt_txpwr_table(struct mwifiex_private *priv)
196 {
197 if (priv->adapter->dt_node) {
198 char txpwr[] = {"marvell,00_txpwrlimit"};
199
200 memcpy(&txpwr[8], priv->adapter->country_code, 2);
201 mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
202 }
203 }
204
mwifiex_request_rgpower_table(struct mwifiex_private * priv)205 static int mwifiex_request_rgpower_table(struct mwifiex_private *priv)
206 {
207 struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg;
208 struct mwifiex_adapter *adapter = priv->adapter;
209 char rgpower_table_name[30];
210 char country_code[3];
211 int ret;
212
213 strscpy(country_code, domain_info->country_code, sizeof(country_code));
214
215 /* World regulatory domain "00" has WW as country code */
216 if (strncmp(country_code, "00", 2) == 0)
217 strscpy(country_code, "WW", sizeof(country_code));
218
219 snprintf(rgpower_table_name, sizeof(rgpower_table_name),
220 "nxp/rgpower_%s.bin", country_code);
221
222 mwifiex_dbg(adapter, INFO, "info: %s: requesting regulatory power table %s\n",
223 __func__, rgpower_table_name);
224
225 if (adapter->rgpower_data) {
226 release_firmware(adapter->rgpower_data);
227 adapter->rgpower_data = NULL;
228 }
229
230 ret = request_firmware_direct(&adapter->rgpower_data, rgpower_table_name,
231 adapter->dev);
232
233 if (ret) {
234 mwifiex_dbg(
235 adapter, INFO,
236 "info: %s: failed to request regulatory power table: %d\n",
237 __func__, ret);
238 }
239
240 return ret;
241 }
242
mwifiex_dnld_rgpower_table(struct mwifiex_private * priv)243 static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv)
244 {
245 int ret;
246
247 ret = mwifiex_request_rgpower_table(priv);
248 if (ret)
249 return ret;
250
251 return mwifiex_send_rgpower_table(priv, priv->adapter->rgpower_data->data,
252 priv->adapter->rgpower_data->size);
253 }
254
mwifiex_dnld_txpwr_table(struct mwifiex_private * priv)255 void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
256 {
257 if (mwifiex_dnld_rgpower_table(priv) == 0)
258 return;
259
260 mwifiex_dnld_dt_txpwr_table(priv);
261 }
262
mwifiex_process_country_ie(struct mwifiex_private * priv,struct cfg80211_bss * bss)263 static int mwifiex_process_country_ie(struct mwifiex_private *priv,
264 struct cfg80211_bss *bss)
265 {
266 const u8 *country_ie;
267 u8 country_ie_len;
268 struct mwifiex_802_11d_domain_reg *domain_info =
269 &priv->adapter->domain_reg;
270
271 rcu_read_lock();
272 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
273 if (!country_ie) {
274 rcu_read_unlock();
275 return 0;
276 }
277
278 country_ie_len = country_ie[1];
279 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
280 rcu_read_unlock();
281 return 0;
282 }
283
284 if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
285 rcu_read_unlock();
286 mwifiex_dbg(priv->adapter, INFO,
287 "11D: skip setting domain info in FW\n");
288 return 0;
289 }
290
291 if (country_ie_len >
292 (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) {
293 rcu_read_unlock();
294 mwifiex_dbg(priv->adapter, ERROR,
295 "11D: country_ie_len overflow!, deauth AP\n");
296 return -EINVAL;
297 }
298
299 memcpy(priv->adapter->country_code, &country_ie[2], 2);
300
301 domain_info->country_code[0] = country_ie[2];
302 domain_info->country_code[1] = country_ie[3];
303 domain_info->country_code[2] = ' ';
304
305 country_ie_len -= IEEE80211_COUNTRY_STRING_LEN;
306
307 domain_info->no_of_triplet =
308 country_ie_len / sizeof(struct ieee80211_country_ie_triplet);
309
310 memcpy((u8 *)domain_info->triplet,
311 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);
312
313 rcu_read_unlock();
314
315 if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
316 HostCmd_ACT_GEN_SET, 0, NULL, false)) {
317 mwifiex_dbg(priv->adapter, ERROR,
318 "11D: setting domain info in FW fail\n");
319 return -1;
320 }
321
322 mwifiex_dnld_txpwr_table(priv);
323
324 return 0;
325 }
326
327 /*
328 * In Ad-Hoc mode, the IBSS is created if not found in scan list.
329 * In both Ad-Hoc and infra mode, an deauthentication is performed
330 * first.
331 */
mwifiex_bss_start(struct mwifiex_private * priv,struct cfg80211_bss * bss,struct cfg80211_ssid * req_ssid)332 int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
333 struct cfg80211_ssid *req_ssid)
334 {
335 int ret;
336 struct mwifiex_adapter *adapter = priv->adapter;
337 struct mwifiex_bssdescriptor *bss_desc = NULL;
338
339 priv->scan_block = false;
340
341 if (bss) {
342 if (adapter->region_code == 0x00 &&
343 mwifiex_process_country_ie(priv, bss))
344 return -EINVAL;
345
346 /* Allocate and fill new bss descriptor */
347 bss_desc = kzalloc_obj(struct mwifiex_bssdescriptor);
348 if (!bss_desc)
349 return -ENOMEM;
350
351 ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
352 if (ret)
353 goto done;
354 }
355
356 if (priv->bss_mode == NL80211_IFTYPE_STATION ||
357 priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
358 u8 config_bands;
359
360 if (!bss_desc)
361 return -1;
362
363 if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
364 HostCmd_SCAN_RADIO_TYPE_BG) {
365 config_bands = BAND_B | BAND_G | BAND_GN;
366 } else {
367 config_bands = BAND_A | BAND_AN;
368 if (adapter->fw_bands & BAND_AAC)
369 config_bands |= BAND_AAC;
370 }
371
372 if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
373 adapter->config_bands = config_bands;
374
375 ret = mwifiex_check_network_compatibility(priv, bss_desc);
376 if (ret)
377 goto done;
378
379 if (mwifiex_11h_get_csa_closed_channel(priv) ==
380 (u8)bss_desc->channel) {
381 mwifiex_dbg(adapter, ERROR,
382 "Attempt to reconnect on csa closed chan(%d)\n",
383 bss_desc->channel);
384 ret = -1;
385 goto done;
386 }
387
388 mwifiex_dbg(adapter, INFO,
389 "info: SSID found in scan list ...\t"
390 "associating...\n");
391
392 mwifiex_stop_net_dev_queue(priv->netdev, adapter);
393 if (netif_carrier_ok(priv->netdev))
394 netif_carrier_off(priv->netdev);
395
396 /* Clear any past association response stored for
397 * application retrieval */
398 priv->assoc_rsp_size = 0;
399 ret = mwifiex_associate(priv, bss_desc);
400
401 /* If auth type is auto and association fails using open mode,
402 * try to connect using shared mode */
403 if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
404 priv->sec_info.is_authtype_auto &&
405 priv->sec_info.wep_enabled) {
406 priv->sec_info.authentication_mode =
407 NL80211_AUTHTYPE_SHARED_KEY;
408 ret = mwifiex_associate(priv, bss_desc);
409 }
410
411 if (bss && !priv->adapter->host_mlme_enabled)
412 cfg80211_put_bss(priv->adapter->wiphy, bss);
413 } else {
414 /* Adhoc mode */
415 /* If the requested SSID matches current SSID, return */
416 if (bss_desc && bss_desc->ssid.ssid_len &&
417 cfg80211_ssid_eq(&priv->curr_bss_params.bss_descriptor.ssid,
418 &bss_desc->ssid)) {
419 ret = 0;
420 goto done;
421 }
422
423 ret = mwifiex_check_network_compatibility(priv, bss_desc);
424
425 mwifiex_stop_net_dev_queue(priv->netdev, adapter);
426 if (netif_carrier_ok(priv->netdev))
427 netif_carrier_off(priv->netdev);
428
429 if (!ret) {
430 mwifiex_dbg(adapter, INFO,
431 "info: network found in scan\t"
432 " list. Joining...\n");
433 ret = mwifiex_adhoc_join(priv, bss_desc);
434 if (bss)
435 cfg80211_put_bss(priv->adapter->wiphy, bss);
436 } else {
437 mwifiex_dbg(adapter, INFO,
438 "info: Network not found in\t"
439 "the list, creating adhoc with ssid = %s\n",
440 req_ssid->ssid);
441 ret = mwifiex_adhoc_start(priv, req_ssid);
442 }
443 }
444
445 done:
446 /* beacon_ie buffer was allocated in function
447 * mwifiex_fill_new_bss_desc(). Free it now.
448 */
449 if (bss_desc)
450 kfree(bss_desc->beacon_buf);
451 kfree(bss_desc);
452
453 if (ret < 0)
454 priv->attempted_bss_desc = NULL;
455
456 return ret;
457 }
458
459 /*
460 * IOCTL request handler to set host sleep configuration.
461 *
462 * This function prepares the correct firmware command and
463 * issues it.
464 */
mwifiex_set_hs_params(struct mwifiex_private * priv,u16 action,int cmd_type,struct mwifiex_ds_hs_cfg * hs_cfg)465 int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
466 int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
467
468 {
469 struct mwifiex_adapter *adapter = priv->adapter;
470 int status = 0;
471 u32 prev_cond = 0;
472
473 if (!hs_cfg)
474 return -ENOMEM;
475
476 switch (action) {
477 case HostCmd_ACT_GEN_SET:
478 if (adapter->pps_uapsd_mode) {
479 mwifiex_dbg(adapter, INFO,
480 "info: Host Sleep IOCTL\t"
481 "is blocked in UAPSD/PPS mode\n");
482 status = -1;
483 break;
484 }
485 if (hs_cfg->is_invoke_hostcmd) {
486 if (hs_cfg->conditions == HS_CFG_CANCEL) {
487 if (!test_bit(MWIFIEX_IS_HS_CONFIGURED,
488 &adapter->work_flags))
489 /* Already cancelled */
490 break;
491 /* Save previous condition */
492 prev_cond = le32_to_cpu(adapter->hs_cfg
493 .conditions);
494 adapter->hs_cfg.conditions =
495 cpu_to_le32(hs_cfg->conditions);
496 } else if (hs_cfg->conditions) {
497 adapter->hs_cfg.conditions =
498 cpu_to_le32(hs_cfg->conditions);
499 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
500 if (hs_cfg->gap)
501 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
502 } else if (adapter->hs_cfg.conditions ==
503 cpu_to_le32(HS_CFG_CANCEL)) {
504 /* Return failure if no parameters for HS
505 enable */
506 status = -1;
507 break;
508 }
509
510 status = mwifiex_send_cmd(priv,
511 HostCmd_CMD_802_11_HS_CFG_ENH,
512 HostCmd_ACT_GEN_SET, 0,
513 &adapter->hs_cfg,
514 cmd_type == MWIFIEX_SYNC_CMD);
515
516 if (hs_cfg->conditions == HS_CFG_CANCEL)
517 /* Restore previous condition */
518 adapter->hs_cfg.conditions =
519 cpu_to_le32(prev_cond);
520 } else {
521 adapter->hs_cfg.conditions =
522 cpu_to_le32(hs_cfg->conditions);
523 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
524 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
525 }
526 break;
527 case HostCmd_ACT_GEN_GET:
528 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
529 hs_cfg->gpio = adapter->hs_cfg.gpio;
530 hs_cfg->gap = adapter->hs_cfg.gap;
531 break;
532 default:
533 status = -1;
534 break;
535 }
536
537 return status;
538 }
539
540 /*
541 * Sends IOCTL request to cancel the existing Host Sleep configuration.
542 *
543 * This function allocates the IOCTL request buffer, fills it
544 * with requisite parameters and calls the IOCTL handler.
545 */
mwifiex_cancel_hs(struct mwifiex_private * priv,int cmd_type)546 int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
547 {
548 struct mwifiex_ds_hs_cfg hscfg;
549
550 hscfg.conditions = HS_CFG_CANCEL;
551 hscfg.is_invoke_hostcmd = true;
552
553 return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
554 cmd_type, &hscfg);
555 }
556 EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
557
558 /*
559 * Sends IOCTL request to cancel the existing Host Sleep configuration.
560 *
561 * This function allocates the IOCTL request buffer, fills it
562 * with requisite parameters and calls the IOCTL handler.
563 */
mwifiex_enable_hs(struct mwifiex_adapter * adapter)564 int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
565 {
566 struct mwifiex_ds_hs_cfg hscfg;
567 struct mwifiex_private *priv;
568 int i;
569
570 if (disconnect_on_suspend) {
571 for (i = 0; i < adapter->priv_num; i++) {
572 priv = adapter->priv[i];
573 mwifiex_deauthenticate(priv, NULL);
574 }
575 }
576
577 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
578
579 if (priv && priv->sched_scanning) {
580 #ifdef CONFIG_PM
581 if (priv->wdev.wiphy->wowlan_config &&
582 !priv->wdev.wiphy->wowlan_config->nd_config) {
583 #endif
584 mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");
585 mwifiex_stop_bg_scan(priv);
586 cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0);
587 #ifdef CONFIG_PM
588 }
589 #endif
590 }
591
592 if (adapter->hs_activated) {
593 mwifiex_dbg(adapter, CMD,
594 "cmd: HS Already activated\n");
595 return true;
596 }
597
598 adapter->hs_activate_wait_q_woken = false;
599
600 memset(&hscfg, 0, sizeof(hscfg));
601 hscfg.is_invoke_hostcmd = true;
602
603 set_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
604 mwifiex_cancel_all_pending_cmd(adapter);
605
606 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
607 MWIFIEX_BSS_ROLE_STA),
608 HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
609 &hscfg)) {
610 mwifiex_dbg(adapter, ERROR,
611 "IOCTL request HS enable failed\n");
612 return false;
613 }
614
615 if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
616 adapter->hs_activate_wait_q_woken,
617 (5 * HZ)) <= 0) {
618 mwifiex_dbg(adapter, ERROR,
619 "hs_activate_wait_q terminated\n");
620 return false;
621 }
622
623 return true;
624 }
625 EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
626
627 /*
628 * IOCTL request handler to get BSS information.
629 *
630 * This function collates the information from different driver structures
631 * to send to the user.
632 */
mwifiex_get_bss_info(struct mwifiex_private * priv,struct mwifiex_bss_info * info)633 int mwifiex_get_bss_info(struct mwifiex_private *priv,
634 struct mwifiex_bss_info *info)
635 {
636 struct mwifiex_adapter *adapter = priv->adapter;
637 struct mwifiex_bssdescriptor *bss_desc;
638
639 if (!info)
640 return -1;
641
642 bss_desc = &priv->curr_bss_params.bss_descriptor;
643
644 info->bss_mode = priv->bss_mode;
645
646 memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));
647
648 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
649
650 info->bss_chan = bss_desc->channel;
651
652 memcpy(info->country_code, adapter->country_code,
653 IEEE80211_COUNTRY_STRING_LEN);
654
655 info->media_connected = priv->media_connected;
656
657 info->max_power_level = priv->max_tx_power_level;
658 info->min_power_level = priv->min_tx_power_level;
659
660 info->adhoc_state = priv->adhoc_state;
661
662 info->bcn_nf_last = priv->bcn_nf_last;
663
664 if (priv->sec_info.wep_enabled)
665 info->wep_status = true;
666 else
667 info->wep_status = false;
668
669 info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED,
670 &adapter->work_flags);
671 info->is_deep_sleep = adapter->is_deep_sleep;
672
673 return 0;
674 }
675
676 /*
677 * The function disables auto deep sleep mode.
678 */
mwifiex_disable_auto_ds(struct mwifiex_private * priv)679 int mwifiex_disable_auto_ds(struct mwifiex_private *priv)
680 {
681 struct mwifiex_ds_auto_ds auto_ds = {
682 .auto_ds = DEEP_SLEEP_OFF,
683 };
684
685 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
686 DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);
687 }
688 EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);
689
690 /*
691 * Sends IOCTL request to get the data rate.
692 *
693 * This function allocates the IOCTL request buffer, fills it
694 * with requisite parameters and calls the IOCTL handler.
695 */
mwifiex_drv_get_data_rate(struct mwifiex_private * priv,u32 * rate)696 int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)
697 {
698 int ret;
699
700 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
701 HostCmd_ACT_GEN_GET, 0, NULL, true);
702
703 if (!ret) {
704 if (priv->is_data_rate_auto)
705 *rate = mwifiex_index_to_data_rate(priv, priv->tx_rate,
706 priv->tx_htinfo);
707 else
708 *rate = priv->data_rate;
709 }
710
711 return ret;
712 }
713
714 /*
715 * IOCTL request handler to set tx power configuration.
716 *
717 * This function prepares the correct firmware command and
718 * issues it.
719 *
720 * For non-auto power mode, all the following power groups are set -
721 * - Modulation class HR/DSSS
722 * - Modulation class OFDM
723 * - Modulation class HTBW20
724 * - Modulation class HTBW40
725 */
mwifiex_set_tx_power(struct mwifiex_private * priv,struct mwifiex_power_cfg * power_cfg)726 int mwifiex_set_tx_power(struct mwifiex_private *priv,
727 struct mwifiex_power_cfg *power_cfg)
728 {
729 int ret;
730 struct host_cmd_ds_txpwr_cfg *txp_cfg;
731 struct mwifiex_types_power_group *pg_tlv;
732 struct mwifiex_power_group *pg;
733 u8 *buf;
734 u16 dbm = 0;
735
736 if (!power_cfg->is_power_auto) {
737 dbm = (u16) power_cfg->power_level;
738 if ((dbm < priv->min_tx_power_level) ||
739 (dbm > priv->max_tx_power_level)) {
740 mwifiex_dbg(priv->adapter, ERROR,
741 "txpower value %d dBm\t"
742 "is out of range (%d dBm-%d dBm)\n",
743 dbm, priv->min_tx_power_level,
744 priv->max_tx_power_level);
745 return -1;
746 }
747 }
748 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
749 if (!buf)
750 return -ENOMEM;
751
752 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
753 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
754 if (!power_cfg->is_power_auto) {
755 u16 dbm_min = power_cfg->is_power_fixed ?
756 dbm : priv->min_tx_power_level;
757
758 txp_cfg->mode = cpu_to_le32(1);
759 pg_tlv = (struct mwifiex_types_power_group *)
760 (buf + sizeof(struct host_cmd_ds_txpwr_cfg));
761 pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);
762 pg_tlv->length =
763 cpu_to_le16(4 * sizeof(struct mwifiex_power_group));
764 pg = (struct mwifiex_power_group *)
765 (buf + sizeof(struct host_cmd_ds_txpwr_cfg)
766 + sizeof(struct mwifiex_types_power_group));
767 /* Power group for modulation class HR/DSSS */
768 pg->first_rate_code = 0x00;
769 pg->last_rate_code = 0x03;
770 pg->modulation_class = MOD_CLASS_HR_DSSS;
771 pg->power_step = 0;
772 pg->power_min = (s8) dbm_min;
773 pg->power_max = (s8) dbm;
774 pg++;
775 /* Power group for modulation class OFDM */
776 pg->first_rate_code = 0x00;
777 pg->last_rate_code = 0x07;
778 pg->modulation_class = MOD_CLASS_OFDM;
779 pg->power_step = 0;
780 pg->power_min = (s8) dbm_min;
781 pg->power_max = (s8) dbm;
782 pg++;
783 /* Power group for modulation class HTBW20 */
784 pg->first_rate_code = 0x00;
785 pg->last_rate_code = 0x20;
786 pg->modulation_class = MOD_CLASS_HT;
787 pg->power_step = 0;
788 pg->power_min = (s8) dbm_min;
789 pg->power_max = (s8) dbm;
790 pg->ht_bandwidth = HT_BW_20;
791 pg++;
792 /* Power group for modulation class HTBW40 */
793 pg->first_rate_code = 0x00;
794 pg->last_rate_code = 0x20;
795 pg->modulation_class = MOD_CLASS_HT;
796 pg->power_step = 0;
797 pg->power_min = (s8) dbm_min;
798 pg->power_max = (s8) dbm;
799 pg->ht_bandwidth = HT_BW_40;
800 }
801 ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,
802 HostCmd_ACT_GEN_SET, 0, buf, true);
803
804 kfree(buf);
805 return ret;
806 }
807
808 /*
809 * IOCTL request handler to get power save mode.
810 *
811 * This function prepares the correct firmware command and
812 * issues it.
813 */
mwifiex_drv_set_power(struct mwifiex_private * priv,u32 * ps_mode)814 int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
815 {
816 int ret;
817 struct mwifiex_adapter *adapter = priv->adapter;
818 u16 sub_cmd;
819
820 if (*ps_mode)
821 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
822 else
823 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
824 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
825 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
826 sub_cmd, BITMAP_STA_PS, NULL, true);
827 if ((!ret) && (sub_cmd == DIS_AUTO_PS))
828 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
829 GET_PS, 0, NULL, false);
830
831 return ret;
832 }
833
834 /*
835 * IOCTL request handler to set/reset WPA IE.
836 *
837 * The supplied WPA IE is treated as a opaque buffer. Only the first field
838 * is checked to determine WPA version. If buffer length is zero, the existing
839 * WPA IE is reset.
840 */
mwifiex_set_wpa_ie(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)841 static int mwifiex_set_wpa_ie(struct mwifiex_private *priv,
842 u8 *ie_data_ptr, u16 ie_len)
843 {
844 if (ie_len) {
845 if (ie_len > sizeof(priv->wpa_ie)) {
846 mwifiex_dbg(priv->adapter, ERROR,
847 "failed to copy WPA IE, too big\n");
848 return -1;
849 }
850 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
851 priv->wpa_ie_len = ie_len;
852 mwifiex_dbg(priv->adapter, CMD,
853 "cmd: Set Wpa_ie_len=%d IE=%#x\n",
854 priv->wpa_ie_len, priv->wpa_ie[0]);
855
856 if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
857 priv->sec_info.wpa_enabled = true;
858 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
859 priv->sec_info.wpa2_enabled = true;
860 } else {
861 priv->sec_info.wpa_enabled = false;
862 priv->sec_info.wpa2_enabled = false;
863 }
864 } else {
865 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
866 priv->wpa_ie_len = 0;
867 mwifiex_dbg(priv->adapter, INFO,
868 "info: reset wpa_ie_len=%d IE=%#x\n",
869 priv->wpa_ie_len, priv->wpa_ie[0]);
870 priv->sec_info.wpa_enabled = false;
871 priv->sec_info.wpa2_enabled = false;
872 }
873
874 return 0;
875 }
876
877 /*
878 * IOCTL request handler to set/reset WAPI IE.
879 *
880 * The supplied WAPI IE is treated as a opaque buffer. Only the first field
881 * is checked to internally enable WAPI. If buffer length is zero, the existing
882 * WAPI IE is reset.
883 */
mwifiex_set_wapi_ie(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)884 static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
885 u8 *ie_data_ptr, u16 ie_len)
886 {
887 if (ie_len) {
888 if (ie_len > sizeof(priv->wapi_ie)) {
889 mwifiex_dbg(priv->adapter, ERROR,
890 "info: failed to copy WAPI IE, too big\n");
891 return -1;
892 }
893 memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
894 priv->wapi_ie_len = ie_len;
895 mwifiex_dbg(priv->adapter, CMD,
896 "cmd: Set wapi_ie_len=%d IE=%#x\n",
897 priv->wapi_ie_len, priv->wapi_ie[0]);
898
899 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
900 priv->sec_info.wapi_enabled = true;
901 } else {
902 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
903 priv->wapi_ie_len = ie_len;
904 mwifiex_dbg(priv->adapter, INFO,
905 "info: Reset wapi_ie_len=%d IE=%#x\n",
906 priv->wapi_ie_len, priv->wapi_ie[0]);
907 priv->sec_info.wapi_enabled = false;
908 }
909 return 0;
910 }
911
912 /*
913 * IOCTL request handler to set/reset WPS IE.
914 *
915 * The supplied WPS IE is treated as a opaque buffer. Only the first field
916 * is checked to internally enable WPS. If buffer length is zero, the existing
917 * WPS IE is reset.
918 */
mwifiex_set_wps_ie(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)919 static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
920 u8 *ie_data_ptr, u16 ie_len)
921 {
922 if (ie_len) {
923 if (ie_len > MWIFIEX_MAX_VSIE_LEN) {
924 mwifiex_dbg(priv->adapter, ERROR,
925 "info: failed to copy WPS IE, too big\n");
926 return -1;
927 }
928
929 priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
930 if (!priv->wps_ie)
931 return -ENOMEM;
932
933 memcpy(priv->wps_ie, ie_data_ptr, ie_len);
934 priv->wps_ie_len = ie_len;
935 mwifiex_dbg(priv->adapter, CMD,
936 "cmd: Set wps_ie_len=%d IE=%#x\n",
937 priv->wps_ie_len, priv->wps_ie[0]);
938 } else {
939 kfree(priv->wps_ie);
940 priv->wps_ie_len = ie_len;
941 mwifiex_dbg(priv->adapter, INFO,
942 "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
943 }
944 return 0;
945 }
946
947 /*
948 * IOCTL request handler to set WAPI key.
949 *
950 * This function prepares the correct firmware command and
951 * issues it.
952 */
mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)953 static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
954 struct mwifiex_ds_encrypt_key *encrypt_key)
955 {
956
957 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
958 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
959 encrypt_key, true);
960 }
961
962 /*
963 * IOCTL request handler to set WEP network key.
964 *
965 * This function prepares the correct firmware command and
966 * issues it, after validation checks.
967 */
mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)968 static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
969 struct mwifiex_ds_encrypt_key *encrypt_key)
970 {
971 struct mwifiex_adapter *adapter = priv->adapter;
972 int ret;
973 struct mwifiex_wep_key *wep_key;
974 int index;
975
976 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
977 priv->wep_key_curr_index = 0;
978 wep_key = &priv->wep_key[priv->wep_key_curr_index];
979 index = encrypt_key->key_index;
980 if (encrypt_key->key_disable) {
981 priv->sec_info.wep_enabled = 0;
982 } else if (!encrypt_key->key_len) {
983 /* Copy the required key as the current key */
984 wep_key = &priv->wep_key[index];
985 if (!wep_key->key_length) {
986 mwifiex_dbg(adapter, ERROR,
987 "key not set, so cannot enable it\n");
988 return -1;
989 }
990
991 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
992 memcpy(encrypt_key->key_material,
993 wep_key->key_material, wep_key->key_length);
994 encrypt_key->key_len = wep_key->key_length;
995 }
996
997 priv->wep_key_curr_index = (u16) index;
998 priv->sec_info.wep_enabled = 1;
999 } else {
1000 wep_key = &priv->wep_key[index];
1001 memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
1002 /* Copy the key in the driver */
1003 memcpy(wep_key->key_material,
1004 encrypt_key->key_material,
1005 encrypt_key->key_len);
1006 wep_key->key_index = index;
1007 wep_key->key_length = encrypt_key->key_len;
1008 priv->sec_info.wep_enabled = 1;
1009 }
1010 if (wep_key->key_length) {
1011 void *enc_key;
1012
1013 if (encrypt_key->key_disable) {
1014 memset(&priv->wep_key[index], 0,
1015 sizeof(struct mwifiex_wep_key));
1016 goto done;
1017 }
1018
1019 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
1020 enc_key = encrypt_key;
1021 else
1022 enc_key = NULL;
1023
1024 /* Send request to firmware */
1025 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1026 HostCmd_ACT_GEN_SET, 0, enc_key, false);
1027 if (ret)
1028 return ret;
1029 }
1030
1031 done:
1032 if (priv->sec_info.wep_enabled)
1033 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
1034 else
1035 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
1036
1037 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1038 HostCmd_ACT_GEN_SET, 0,
1039 &priv->curr_pkt_filter, true);
1040
1041 return ret;
1042 }
1043
1044 /*
1045 * IOCTL request handler to set WPA key.
1046 *
1047 * This function prepares the correct firmware command and
1048 * issues it, after validation checks.
1049 *
1050 * Current driver only supports key length of up to 32 bytes.
1051 *
1052 * This function can also be used to disable a currently set key.
1053 */
mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)1054 static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
1055 struct mwifiex_ds_encrypt_key *encrypt_key)
1056 {
1057 int ret;
1058 u8 remove_key = false;
1059 struct host_cmd_ds_802_11_key_material *ibss_key;
1060
1061 /* Current driver only supports key length of up to 32 bytes */
1062 if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
1063 mwifiex_dbg(priv->adapter, ERROR,
1064 "key length too long\n");
1065 return -1;
1066 }
1067
1068 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
1069 /*
1070 * IBSS/WPA-None uses only one key (Group) for both receiving
1071 * and sending unicast and multicast packets.
1072 */
1073 /* Send the key as PTK to firmware */
1074 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1075 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1076 HostCmd_ACT_GEN_SET,
1077 KEY_INFO_ENABLED, encrypt_key, false);
1078 if (ret)
1079 return ret;
1080
1081 ibss_key = &priv->aes_key;
1082 memset(ibss_key, 0,
1083 sizeof(struct host_cmd_ds_802_11_key_material));
1084 /* Copy the key in the driver */
1085 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
1086 encrypt_key->key_len);
1087 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
1088 sizeof(ibss_key->key_param_set.key_len));
1089 ibss_key->key_param_set.key_type_id
1090 = cpu_to_le16(KEY_TYPE_ID_TKIP);
1091 ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);
1092
1093 /* Send the key as GTK to firmware */
1094 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
1095 }
1096
1097 if (!encrypt_key->key_index)
1098 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1099
1100 if (remove_key)
1101 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1102 HostCmd_ACT_GEN_SET,
1103 !KEY_INFO_ENABLED, encrypt_key, true);
1104 else
1105 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1106 HostCmd_ACT_GEN_SET,
1107 KEY_INFO_ENABLED, encrypt_key, true);
1108
1109 return ret;
1110 }
1111
1112 /*
1113 * IOCTL request handler to set/get network keys.
1114 *
1115 * This is a generic key handling function which supports WEP, WPA
1116 * and WAPI.
1117 */
1118 static int
mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)1119 mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
1120 struct mwifiex_ds_encrypt_key *encrypt_key)
1121 {
1122 int status;
1123
1124 if (encrypt_key->is_wapi_key)
1125 status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
1126 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
1127 status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);
1128 else
1129 status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);
1130 return status;
1131 }
1132
1133 /*
1134 * This function returns the driver version.
1135 */
1136 int
mwifiex_drv_get_driver_version(struct mwifiex_adapter * adapter,char * version,int max_len)1137 mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
1138 int max_len)
1139 {
1140 union {
1141 __le32 l;
1142 u8 c[4];
1143 } ver;
1144 char fw_ver[32];
1145
1146 ver.l = cpu_to_le32(adapter->fw_release_number);
1147 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
1148
1149 snprintf(version, max_len, driver_version, fw_ver);
1150
1151 mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);
1152
1153 return 0;
1154 }
1155
1156 /*
1157 * Sends IOCTL request to set encoding parameters.
1158 *
1159 * This function allocates the IOCTL request buffer, fills it
1160 * with requisite parameters and calls the IOCTL handler.
1161 */
mwifiex_set_encode(struct mwifiex_private * priv,struct key_params * kp,const u8 * key,int key_len,u8 key_index,const u8 * mac_addr,int disable)1162 int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
1163 const u8 *key, int key_len, u8 key_index,
1164 const u8 *mac_addr, int disable)
1165 {
1166 struct mwifiex_ds_encrypt_key encrypt_key;
1167
1168 memset(&encrypt_key, 0, sizeof(encrypt_key));
1169 encrypt_key.key_len = key_len;
1170 encrypt_key.key_index = key_index;
1171
1172 if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
1173 encrypt_key.is_igtk_key = true;
1174
1175 if (!disable) {
1176 if (key_len)
1177 memcpy(encrypt_key.key_material, key, key_len);
1178 else
1179 encrypt_key.is_current_wep_key = true;
1180
1181 if (mac_addr)
1182 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
1183 if (kp && kp->seq && kp->seq_len) {
1184 memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
1185 encrypt_key.pn_len = kp->seq_len;
1186 encrypt_key.is_rx_seq_valid = true;
1187 }
1188 } else {
1189 encrypt_key.key_disable = true;
1190 if (mac_addr)
1191 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
1192 }
1193
1194 return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
1195 }
1196
1197 /*
1198 * Sends IOCTL request to get extended version.
1199 *
1200 * This function allocates the IOCTL request buffer, fills it
1201 * with requisite parameters and calls the IOCTL handler.
1202 */
1203 int
mwifiex_get_ver_ext(struct mwifiex_private * priv,u32 version_str_sel)1204 mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)
1205 {
1206 struct mwifiex_ver_ext ver_ext;
1207
1208 memset(&ver_ext, 0, sizeof(ver_ext));
1209 ver_ext.version_str_sel = version_str_sel;
1210 if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
1211 HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
1212 return -1;
1213
1214 return 0;
1215 }
1216
1217 int
mwifiex_remain_on_chan_cfg(struct mwifiex_private * priv,u16 action,struct ieee80211_channel * chan,unsigned int duration)1218 mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
1219 struct ieee80211_channel *chan,
1220 unsigned int duration)
1221 {
1222 struct host_cmd_ds_remain_on_chan roc_cfg;
1223 u8 sc;
1224
1225 memset(&roc_cfg, 0, sizeof(roc_cfg));
1226 roc_cfg.action = cpu_to_le16(action);
1227 if (action == HostCmd_ACT_GEN_SET) {
1228 roc_cfg.band_cfg = chan->band;
1229 sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);
1230 roc_cfg.band_cfg |= (sc << 2);
1231
1232 roc_cfg.channel =
1233 ieee80211_frequency_to_channel(chan->center_freq);
1234 roc_cfg.duration = cpu_to_le32(duration);
1235 }
1236 if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
1237 action, 0, &roc_cfg, true)) {
1238 mwifiex_dbg(priv->adapter, ERROR,
1239 "failed to remain on channel\n");
1240 return -1;
1241 }
1242
1243 return roc_cfg.status;
1244 }
1245
1246 /*
1247 * Sends IOCTL request to get statistics information.
1248 *
1249 * This function allocates the IOCTL request buffer, fills it
1250 * with requisite parameters and calls the IOCTL handler.
1251 */
1252 int
mwifiex_get_stats_info(struct mwifiex_private * priv,struct mwifiex_ds_get_stats * log)1253 mwifiex_get_stats_info(struct mwifiex_private *priv,
1254 struct mwifiex_ds_get_stats *log)
1255 {
1256 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
1257 HostCmd_ACT_GEN_GET, 0, log, true);
1258 }
1259
1260 /*
1261 * IOCTL request handler to read/write register.
1262 *
1263 * This function prepares the correct firmware command and
1264 * issues it.
1265 *
1266 * Access to the following registers are supported -
1267 * - MAC
1268 * - BBP
1269 * - RF
1270 * - PMIC
1271 * - CAU
1272 */
mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private * priv,struct mwifiex_ds_reg_rw * reg_rw,u16 action)1273 static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
1274 struct mwifiex_ds_reg_rw *reg_rw,
1275 u16 action)
1276 {
1277 u16 cmd_no;
1278
1279 switch (reg_rw->type) {
1280 case MWIFIEX_REG_MAC:
1281 cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
1282 break;
1283 case MWIFIEX_REG_BBP:
1284 cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
1285 break;
1286 case MWIFIEX_REG_RF:
1287 cmd_no = HostCmd_CMD_RF_REG_ACCESS;
1288 break;
1289 case MWIFIEX_REG_PMIC:
1290 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
1291 break;
1292 case MWIFIEX_REG_CAU:
1293 cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
1294 break;
1295 default:
1296 return -1;
1297 }
1298
1299 return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);
1300 }
1301
1302 /*
1303 * Sends IOCTL request to write to a register.
1304 *
1305 * This function allocates the IOCTL request buffer, fills it
1306 * with requisite parameters and calls the IOCTL handler.
1307 */
1308 int
mwifiex_reg_write(struct mwifiex_private * priv,u32 reg_type,u32 reg_offset,u32 reg_value)1309 mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
1310 u32 reg_offset, u32 reg_value)
1311 {
1312 struct mwifiex_ds_reg_rw reg_rw;
1313
1314 reg_rw.type = reg_type;
1315 reg_rw.offset = reg_offset;
1316 reg_rw.value = reg_value;
1317
1318 return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET);
1319 }
1320
1321 /*
1322 * Sends IOCTL request to read from a register.
1323 *
1324 * This function allocates the IOCTL request buffer, fills it
1325 * with requisite parameters and calls the IOCTL handler.
1326 */
1327 int
mwifiex_reg_read(struct mwifiex_private * priv,u32 reg_type,u32 reg_offset,u32 * value)1328 mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
1329 u32 reg_offset, u32 *value)
1330 {
1331 int ret;
1332 struct mwifiex_ds_reg_rw reg_rw;
1333
1334 reg_rw.type = reg_type;
1335 reg_rw.offset = reg_offset;
1336 ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET);
1337
1338 if (ret)
1339 goto done;
1340
1341 *value = reg_rw.value;
1342
1343 done:
1344 return ret;
1345 }
1346
1347 /*
1348 * Sends IOCTL request to read from EEPROM.
1349 *
1350 * This function allocates the IOCTL request buffer, fills it
1351 * with requisite parameters and calls the IOCTL handler.
1352 */
1353 int
mwifiex_eeprom_read(struct mwifiex_private * priv,u16 offset,u16 bytes,u8 * value)1354 mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
1355 u8 *value)
1356 {
1357 int ret;
1358 struct mwifiex_ds_read_eeprom rd_eeprom;
1359
1360 rd_eeprom.offset = offset;
1361 rd_eeprom.byte_count = bytes;
1362
1363 /* Send request to firmware */
1364 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
1365 HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);
1366
1367 if (!ret)
1368 memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA,
1369 rd_eeprom.byte_count));
1370 return ret;
1371 }
1372
1373 /*
1374 * This function sets a generic IE. In addition to generic IE, it can
1375 * also handle WPA, WPA2 and WAPI IEs.
1376 */
1377 static int
mwifiex_set_gen_ie_helper(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)1378 mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
1379 u16 ie_len)
1380 {
1381 struct ieee_types_vendor_header *pvendor_ie;
1382 static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
1383 static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
1384 u16 unparsed_len = ie_len, cur_ie_len;
1385
1386 /* If the passed length is zero, reset the buffer */
1387 if (!ie_len) {
1388 priv->gen_ie_buf_len = 0;
1389 priv->wps.session_enable = false;
1390 return 0;
1391 } else if (!ie_data_ptr ||
1392 ie_len <= sizeof(struct ieee_types_header)) {
1393 return -1;
1394 }
1395 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
1396
1397 while (pvendor_ie) {
1398 cur_ie_len = pvendor_ie->len + sizeof(struct ieee_types_header);
1399
1400 if (pvendor_ie->element_id == WLAN_EID_RSN) {
1401 /* IE is a WPA/WPA2 IE so call set_wpa function */
1402 mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len);
1403 priv->wps.session_enable = false;
1404 goto next_ie;
1405 }
1406
1407 if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
1408 /* IE is a WAPI IE so call set_wapi function */
1409 mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie,
1410 cur_ie_len);
1411 goto next_ie;
1412 }
1413
1414 if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) {
1415 /* Test to see if it is a WPA IE, if not, then
1416 * it is a gen IE
1417 */
1418 if (!memcmp(&pvendor_ie->oui, wpa_oui,
1419 sizeof(wpa_oui))) {
1420 /* IE is a WPA/WPA2 IE so call set_wpa function
1421 */
1422 mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie,
1423 cur_ie_len);
1424 priv->wps.session_enable = false;
1425 goto next_ie;
1426 }
1427
1428 if (!memcmp(&pvendor_ie->oui, wps_oui,
1429 sizeof(wps_oui))) {
1430 /* Test to see if it is a WPS IE,
1431 * if so, enable wps session flag
1432 */
1433 priv->wps.session_enable = true;
1434 mwifiex_dbg(priv->adapter, MSG,
1435 "WPS Session Enabled.\n");
1436 mwifiex_set_wps_ie(priv, (u8 *)pvendor_ie,
1437 cur_ie_len);
1438 goto next_ie;
1439 }
1440 }
1441
1442 /* Saved in gen_ie, such as P2P IE.etc.*/
1443
1444 /* Verify that the passed length is not larger than the
1445 * available space remaining in the buffer
1446 */
1447 if (cur_ie_len <
1448 (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
1449 /* Append the passed data to the end
1450 * of the genIeBuffer
1451 */
1452 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len,
1453 (u8 *)pvendor_ie, cur_ie_len);
1454 /* Increment the stored buffer length by the
1455 * size passed
1456 */
1457 priv->gen_ie_buf_len += cur_ie_len;
1458 }
1459
1460 next_ie:
1461 unparsed_len -= cur_ie_len;
1462
1463 if (unparsed_len <= sizeof(struct ieee_types_header))
1464 pvendor_ie = NULL;
1465 else
1466 pvendor_ie = (struct ieee_types_vendor_header *)
1467 (((u8 *)pvendor_ie) + cur_ie_len);
1468 }
1469
1470 return 0;
1471 }
1472
1473 /*
1474 * IOCTL request handler to set/get generic IE.
1475 *
1476 * In addition to various generic IEs, this function can also be
1477 * used to set the ARP filter.
1478 */
mwifiex_misc_ioctl_gen_ie(struct mwifiex_private * priv,struct mwifiex_ds_misc_gen_ie * gen_ie,u16 action)1479 static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
1480 struct mwifiex_ds_misc_gen_ie *gen_ie,
1481 u16 action)
1482 {
1483 struct mwifiex_adapter *adapter = priv->adapter;
1484
1485 switch (gen_ie->type) {
1486 case MWIFIEX_IE_TYPE_GEN_IE:
1487 if (action == HostCmd_ACT_GEN_GET) {
1488 gen_ie->len = priv->wpa_ie_len;
1489 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
1490 } else {
1491 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
1492 (u16) gen_ie->len);
1493 }
1494 break;
1495 case MWIFIEX_IE_TYPE_ARP_FILTER:
1496 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
1497 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
1498 adapter->arp_filter_size = 0;
1499 mwifiex_dbg(adapter, ERROR,
1500 "invalid ARP filter size\n");
1501 return -1;
1502 } else {
1503 memcpy(adapter->arp_filter, gen_ie->ie_data,
1504 gen_ie->len);
1505 adapter->arp_filter_size = gen_ie->len;
1506 }
1507 break;
1508 default:
1509 mwifiex_dbg(adapter, ERROR, "invalid IE type\n");
1510 return -1;
1511 }
1512 return 0;
1513 }
1514
1515 /*
1516 * Sends IOCTL request to set a generic IE.
1517 *
1518 * This function allocates the IOCTL request buffer, fills it
1519 * with requisite parameters and calls the IOCTL handler.
1520 */
1521 int
mwifiex_set_gen_ie(struct mwifiex_private * priv,const u8 * ie,int ie_len)1522 mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
1523 {
1524 struct mwifiex_ds_misc_gen_ie gen_ie;
1525
1526 if (ie_len > IEEE_MAX_IE_SIZE)
1527 return -EFAULT;
1528
1529 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
1530 gen_ie.len = ie_len;
1531 memcpy(gen_ie.ie_data, ie, ie_len);
1532 if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))
1533 return -EFAULT;
1534
1535 return 0;
1536 }
1537
1538 /* This function get Host Sleep wake up reason.
1539 *
1540 */
mwifiex_get_wakeup_reason(struct mwifiex_private * priv,u16 action,int cmd_type,struct mwifiex_ds_wakeup_reason * wakeup_reason)1541 int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
1542 int cmd_type,
1543 struct mwifiex_ds_wakeup_reason *wakeup_reason)
1544 {
1545 int status = 0;
1546
1547 status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,
1548 HostCmd_ACT_GEN_GET, 0, wakeup_reason,
1549 cmd_type == MWIFIEX_SYNC_CMD);
1550
1551 return status;
1552 }
1553
mwifiex_get_chan_info(struct mwifiex_private * priv,struct mwifiex_channel_band * channel_band)1554 int mwifiex_get_chan_info(struct mwifiex_private *priv,
1555 struct mwifiex_channel_band *channel_band)
1556 {
1557 int status = 0;
1558
1559 status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE,
1560 HostCmd_ACT_GEN_GET, 0, channel_band,
1561 MWIFIEX_SYNC_CMD);
1562
1563 return status;
1564 }
1565