1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * nxpwifi: functions for station ioctl
4 *
5 * Copyright 2011-2024 NXP
6 */
7
8 #include "cfg.h"
9 #include "util.h"
10 #include "fw.h"
11 #include "main.h"
12 #include "cmdevt.h"
13 #include "wmm.h"
14 #include "11n.h"
15 #include "cfg80211.h"
16
17 static int disconnect_on_suspend;
18
19 /* Copies the multicast address list from device to driver */
nxpwifi_copy_mcast_addr(struct nxpwifi_multicast_list * mlist,struct net_device * dev)20 int nxpwifi_copy_mcast_addr(struct nxpwifi_multicast_list *mlist,
21 struct net_device *dev)
22 {
23 int i = 0;
24 struct netdev_hw_addr *ha;
25
26 netdev_for_each_mc_addr(ha, dev)
27 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
28
29 return i;
30 }
31
32 /* Wait queue completion handler */
nxpwifi_wait_queue_complete(struct nxpwifi_adapter * adapter,struct cmd_ctrl_node * cmd_queued)33 int nxpwifi_wait_queue_complete(struct nxpwifi_adapter *adapter,
34 struct cmd_ctrl_node *cmd_queued)
35 {
36 int status;
37
38 /* Wait for completion */
39 status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait,
40 *cmd_queued->condition,
41 (12 * HZ));
42 if (status <= 0) {
43 if (status == 0)
44 status = -ETIMEDOUT;
45 nxpwifi_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",
46 status);
47 nxpwifi_cancel_all_pending_cmd(adapter);
48
49 /*
50 * The response path writes through cmd_node->data_buf. The
51 * caller can release a stack-allocated data_buf after an
52 * interrupted wait while a late response is still pending.
53 * Detach it from the current command before returning.
54 */
55 spin_lock_bh(&adapter->nxpwifi_cmd_lock);
56 if (adapter->curr_cmd == cmd_queued)
57 adapter->curr_cmd->data_buf = NULL;
58 spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
59
60 return status;
61 }
62
63 status = adapter->cmd_wait_q.status;
64 adapter->cmd_wait_q.status = 0;
65
66 return status;
67 }
68
69 /* Set multicast list by issuing the proper firmware command */
70 int
nxpwifi_request_set_multicast_list(struct nxpwifi_private * priv,struct nxpwifi_multicast_list * mcast_list)71 nxpwifi_request_set_multicast_list(struct nxpwifi_private *priv,
72 struct nxpwifi_multicast_list *mcast_list)
73 {
74 int ret = 0;
75 u16 old_pkt_filter;
76
77 old_pkt_filter = priv->curr_pkt_filter;
78
79 if (mcast_list->mode == NXPWIFI_PROMISC_MODE) {
80 nxpwifi_dbg(priv->adapter, INFO,
81 "info: Enable Promiscuous mode\n");
82 priv->curr_pkt_filter |= HOST_ACT_MAC_PROMISCUOUS_ENABLE;
83 priv->curr_pkt_filter &=
84 ~HOST_ACT_MAC_ALL_MULTICAST_ENABLE;
85 } else {
86 /* Multicast */
87 priv->curr_pkt_filter &= ~HOST_ACT_MAC_PROMISCUOUS_ENABLE;
88 if (mcast_list->mode == NXPWIFI_ALL_MULTI_MODE) {
89 nxpwifi_dbg(priv->adapter, INFO,
90 "info: Enabling All Multicast!\n");
91 priv->curr_pkt_filter |=
92 HOST_ACT_MAC_ALL_MULTICAST_ENABLE;
93 } else {
94 priv->curr_pkt_filter &=
95 ~HOST_ACT_MAC_ALL_MULTICAST_ENABLE;
96 nxpwifi_dbg(priv->adapter, INFO,
97 "info: Set multicast list=%d\n",
98 mcast_list->num_multicast_addr);
99 /* Send multicast addresses to firmware */
100 ret = nxpwifi_send_cmd(priv,
101 HOST_CMD_MAC_MULTICAST_ADR,
102 HOST_ACT_GEN_SET, 0,
103 mcast_list, false);
104 }
105 }
106 nxpwifi_dbg(priv->adapter, INFO,
107 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
108 old_pkt_filter, priv->curr_pkt_filter);
109 if (old_pkt_filter != priv->curr_pkt_filter) {
110 ret = nxpwifi_send_cmd(priv, HOST_CMD_MAC_CONTROL,
111 HOST_ACT_GEN_SET,
112 0, &priv->curr_pkt_filter, false);
113 }
114
115 return ret;
116 }
117
118 /* Fill BSS descriptor from cfg80211_bss */
nxpwifi_fill_new_bss_desc(struct nxpwifi_private * priv,struct cfg80211_bss * bss,struct nxpwifi_bssdescriptor * bss_desc)119 int nxpwifi_fill_new_bss_desc(struct nxpwifi_private *priv,
120 struct cfg80211_bss *bss,
121 struct nxpwifi_bssdescriptor *bss_desc)
122 {
123 u8 *beacon_ie;
124 size_t beacon_ie_len;
125 struct nxpwifi_bss_priv *bss_priv = (void *)bss->priv;
126 const struct cfg80211_bss_ies *ies;
127
128 rcu_read_lock();
129 ies = rcu_dereference(bss->ies);
130 beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
131 beacon_ie_len = ies->len;
132 bss_desc->timestamp = ies->tsf;
133 rcu_read_unlock();
134
135 if (!beacon_ie) {
136 nxpwifi_dbg(priv->adapter, ERROR,
137 " failed to alloc beacon_ie\n");
138 return -ENOMEM;
139 }
140
141 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
142 bss_desc->rssi = bss->signal;
143 /* The caller of this function will free beacon_ie */
144 bss_desc->beacon_buf = beacon_ie;
145 bss_desc->beacon_buf_size = beacon_ie_len;
146 bss_desc->beacon_period = bss->beacon_interval;
147 bss_desc->cap_info_bitmap = bss->capability;
148 bss_desc->bss_band = bss_priv->band;
149 bss_desc->fw_tsf = bss_priv->fw_tsf;
150 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
151 nxpwifi_dbg(priv->adapter, INFO,
152 "info: InterpretIE: AP WEP enabled\n");
153 bss_desc->privacy = NXPWIFI_802_11_PRIV_FILTER_8021X_WEP;
154 } else {
155 bss_desc->privacy = NXPWIFI_802_11_PRIV_FILTER_ACCEPT_ALL;
156 }
157 bss_desc->bss_mode = NL80211_IFTYPE_STATION;
158
159 /* Disable 11ac by default */
160 bss_desc->disable_11ac = true;
161 /* Disable 11ax by default */
162 bss_desc->disable_11ax = true;
163
164 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
165 bss_desc->sensed_11h = true;
166
167 return nxpwifi_update_bss_desc_with_ie(priv->adapter, bss_desc);
168 }
169
nxpwifi_process_country_ie(struct nxpwifi_private * priv,struct cfg80211_bss * bss)170 static int nxpwifi_process_country_ie(struct nxpwifi_private *priv,
171 struct cfg80211_bss *bss)
172 {
173 const u8 *country_ie;
174 u8 country_ie_len;
175 struct nxpwifi_802_11d_domain_reg *domain_info =
176 &priv->adapter->domain_reg;
177 int ret;
178
179 rcu_read_lock();
180 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
181 if (!country_ie) {
182 rcu_read_unlock();
183 return 0;
184 }
185
186 country_ie_len = country_ie[1];
187 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
188 rcu_read_unlock();
189 return 0;
190 }
191
192 if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
193 rcu_read_unlock();
194 nxpwifi_dbg(priv->adapter, INFO,
195 "11D: skip setting domain info in FW\n");
196 return 0;
197 }
198
199 if (country_ie_len >
200 (IEEE80211_COUNTRY_STRING_LEN + NXPWIFI_MAX_TRIPLET_802_11D)) {
201 rcu_read_unlock();
202 nxpwifi_dbg(priv->adapter, ERROR,
203 "11D: country_ie_len overflow!, deauth AP\n");
204 return -EINVAL;
205 }
206
207 memcpy(priv->adapter->country_code, &country_ie[2], 2);
208
209 domain_info->country_code[0] = country_ie[2];
210 domain_info->country_code[1] = country_ie[3];
211 domain_info->country_code[2] = ' ';
212
213 country_ie_len -= IEEE80211_COUNTRY_STRING_LEN;
214
215 domain_info->no_of_triplet =
216 country_ie_len / sizeof(struct ieee80211_country_ie_triplet);
217
218 memcpy((u8 *)domain_info->triplet,
219 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);
220
221 rcu_read_unlock();
222
223 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11D_DOMAIN_INFO,
224 HOST_ACT_GEN_SET, 0, NULL, false);
225 if (ret)
226 nxpwifi_dbg(priv->adapter, ERROR,
227 "11D: setting domain info in FW fail\n");
228
229 return ret;
230 }
231
232 /* In infra mode, an deauthentication is performed first */
nxpwifi_bss_start(struct nxpwifi_private * priv,struct cfg80211_bss * bss,struct cfg80211_ssid * req_ssid)233 int nxpwifi_bss_start(struct nxpwifi_private *priv, struct cfg80211_bss *bss,
234 struct cfg80211_ssid *req_ssid)
235 {
236 int ret;
237 struct nxpwifi_adapter *adapter = priv->adapter;
238 struct nxpwifi_bssdescriptor *bss_desc = NULL;
239 u16 config_bands;
240
241 priv->scan_block = false;
242
243 if (adapter->region_code == 0x00 &&
244 nxpwifi_process_country_ie(priv, bss))
245 return -EINVAL;
246
247 /* Allocate and fill new bss descriptor */
248 bss_desc = kzalloc_obj(*bss_desc, GFP_KERNEL);
249 if (!bss_desc)
250 return -ENOMEM;
251
252 ret = nxpwifi_fill_new_bss_desc(priv, bss, bss_desc);
253 if (ret)
254 goto done;
255
256 if (nxpwifi_band_to_radio_type(bss_desc->bss_band) ==
257 HOST_SCAN_RADIO_TYPE_BG) {
258 config_bands = BAND_B | BAND_G | BAND_GN;
259 if (adapter->fw_bands & BAND_GAC)
260 config_bands |= BAND_GAC;
261 if (adapter->fw_bands & BAND_GAX)
262 config_bands |= BAND_GAX;
263 } else {
264 config_bands = BAND_A | BAND_AN;
265 if (adapter->fw_bands & BAND_AAC)
266 config_bands |= BAND_AAC;
267 if (adapter->fw_bands & BAND_AAX)
268 config_bands |= BAND_AAX;
269 }
270
271 if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
272 priv->config_bands = config_bands;
273
274 ret = nxpwifi_check_network_compatibility(priv, bss_desc);
275 if (ret)
276 goto done;
277
278 if (nxpwifi_11h_get_csa_closed_channel(priv) == (u8)bss_desc->channel) {
279 nxpwifi_dbg(adapter, ERROR,
280 "Attempt to reconnect on csa closed chan(%d)\n",
281 bss_desc->channel);
282 ret = -EINVAL;
283 goto done;
284 }
285
286 nxpwifi_stop_net_dev_queue(priv->netdev, adapter);
287 netif_carrier_off(priv->netdev);
288
289 /* Clear any past association response stored for application retrieval */
290 priv->assoc_rsp_size = 0;
291 ret = nxpwifi_associate(priv, bss_desc);
292
293 /*
294 * If auth type is auto and association fails using open mode, try to connect
295 * using shared mode
296 */
297 if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
298 priv->sec_info.is_authtype_auto &&
299 priv->sec_info.wep_enabled) {
300 priv->sec_info.authentication_mode =
301 NL80211_AUTHTYPE_SHARED_KEY;
302 ret = nxpwifi_associate(priv, bss_desc);
303 }
304
305 done:
306 /* beacon_ie buffer was allocated in function nxpwifi_fill_new_bss_desc() */
307 if (bss_desc)
308 kfree(bss_desc->beacon_buf);
309 kfree(bss_desc);
310
311 if (ret < 0)
312 priv->attempted_bss_desc = NULL;
313
314 return ret;
315 }
316
317 /* IOCTL request handler to set host sleep configuration */
nxpwifi_set_hs_params(struct nxpwifi_private * priv,u16 action,int cmd_type,struct nxpwifi_ds_hs_cfg * hs_cfg)318 int nxpwifi_set_hs_params(struct nxpwifi_private *priv, u16 action,
319 int cmd_type, struct nxpwifi_ds_hs_cfg *hs_cfg)
320
321 {
322 struct nxpwifi_adapter *adapter = priv->adapter;
323 int status = 0;
324 u32 prev_cond = 0;
325
326 if (!hs_cfg)
327 return -ENOMEM;
328
329 switch (action) {
330 case HOST_ACT_GEN_SET:
331 if (adapter->pps_uapsd_mode) {
332 nxpwifi_dbg(adapter, INFO,
333 "info: Host Sleep IOCTL\t"
334 "is blocked in UAPSD/PPS mode\n");
335 status = -EPERM;
336 break;
337 }
338 if (hs_cfg->is_invoke_hostcmd) {
339 if (hs_cfg->conditions == HS_CFG_CANCEL) {
340 if (!test_bit(NXPWIFI_IS_HS_CONFIGURED,
341 &adapter->work_flags))
342 /* Already cancelled */
343 break;
344 /* Save previous condition */
345 prev_cond = le32_to_cpu(adapter->hs_cfg
346 .conditions);
347 adapter->hs_cfg.conditions =
348 cpu_to_le32(hs_cfg->conditions);
349 } else if (hs_cfg->conditions) {
350 adapter->hs_cfg.conditions =
351 cpu_to_le32(hs_cfg->conditions);
352 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
353 if (hs_cfg->gap)
354 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
355 } else if (adapter->hs_cfg.conditions ==
356 cpu_to_le32(HS_CFG_CANCEL)) {
357 status = -EINVAL;
358 break;
359 }
360
361 status = nxpwifi_send_cmd(priv,
362 HOST_CMD_802_11_HS_CFG_ENH,
363 HOST_ACT_GEN_SET, 0,
364 &adapter->hs_cfg,
365 cmd_type == NXPWIFI_SYNC_CMD);
366
367 if (hs_cfg->conditions == HS_CFG_CANCEL)
368 /* Restore previous condition */
369 adapter->hs_cfg.conditions =
370 cpu_to_le32(prev_cond);
371 } else {
372 adapter->hs_cfg.conditions =
373 cpu_to_le32(hs_cfg->conditions);
374 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
375 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
376 }
377 break;
378 case HOST_ACT_GEN_GET:
379 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
380 hs_cfg->gpio = adapter->hs_cfg.gpio;
381 hs_cfg->gap = adapter->hs_cfg.gap;
382 break;
383 default:
384 status = -EINVAL;
385 break;
386 }
387
388 return status;
389 }
390
391 /* Sends IOCTL request to cancel the existing Host Sleep configuration */
nxpwifi_cancel_hs(struct nxpwifi_private * priv,int cmd_type)392 int nxpwifi_cancel_hs(struct nxpwifi_private *priv, int cmd_type)
393 {
394 struct nxpwifi_ds_hs_cfg hscfg;
395
396 hscfg.conditions = HS_CFG_CANCEL;
397 hscfg.is_invoke_hostcmd = true;
398
399 return nxpwifi_set_hs_params(priv, HOST_ACT_GEN_SET,
400 cmd_type, &hscfg);
401 }
402 EXPORT_SYMBOL_GPL(nxpwifi_cancel_hs);
403
404 /* Sends IOCTL request to cancel the existing Host Sleep configuration */
nxpwifi_enable_hs(struct nxpwifi_adapter * adapter)405 bool nxpwifi_enable_hs(struct nxpwifi_adapter *adapter)
406 {
407 struct nxpwifi_ds_hs_cfg hscfg;
408 struct nxpwifi_private *priv;
409 int i;
410
411 if (disconnect_on_suspend) {
412 for (i = 0; i < adapter->priv_num; i++) {
413 priv = adapter->priv[i];
414 nxpwifi_deauthenticate(priv, NULL);
415 }
416 }
417
418 priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA);
419
420 if (priv && priv->sched_scanning) {
421 #ifdef CONFIG_PM
422 if (priv->wdev.wiphy->wowlan_config &&
423 !priv->wdev.wiphy->wowlan_config->nd_config) {
424 #endif
425 nxpwifi_dbg(adapter, CMD, "aborting bgscan!\n");
426 nxpwifi_stop_bg_scan(priv);
427 cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0);
428 #ifdef CONFIG_PM
429 }
430 #endif
431 }
432
433 if (adapter->hs_activated) {
434 nxpwifi_dbg(adapter, CMD,
435 "cmd: HS Already activated\n");
436 return true;
437 }
438
439 adapter->hs_activate_wait_q_woken = false;
440
441 memset(&hscfg, 0, sizeof(hscfg));
442 hscfg.is_invoke_hostcmd = true;
443
444 set_bit(NXPWIFI_IS_HS_ENABLING, &adapter->work_flags);
445 nxpwifi_cancel_all_pending_cmd(adapter);
446
447 if (nxpwifi_set_hs_params(nxpwifi_get_priv(adapter,
448 NXPWIFI_BSS_ROLE_STA),
449 HOST_ACT_GEN_SET, NXPWIFI_SYNC_CMD,
450 &hscfg)) {
451 nxpwifi_dbg(adapter, ERROR,
452 "IOCTL request HS enable failed\n");
453 return false;
454 }
455
456 if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
457 adapter->hs_activate_wait_q_woken,
458 (10 * HZ)) <= 0) {
459 nxpwifi_dbg(adapter, ERROR,
460 "hs_activate_wait_q terminated\n");
461 return false;
462 }
463
464 return true;
465 }
466 EXPORT_SYMBOL_GPL(nxpwifi_enable_hs);
467
468 /* IOCTL request handler to get BSS information */
nxpwifi_get_bss_info(struct nxpwifi_private * priv,struct nxpwifi_bss_info * info)469 int nxpwifi_get_bss_info(struct nxpwifi_private *priv,
470 struct nxpwifi_bss_info *info)
471 {
472 struct nxpwifi_adapter *adapter = priv->adapter;
473 struct nxpwifi_bssdescriptor *bss_desc;
474
475 if (!info)
476 return -EINVAL;
477
478 bss_desc = &priv->curr_bss_params.bss_descriptor;
479
480 info->bss_mode = priv->bss_mode;
481
482 memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));
483
484 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
485
486 info->bss_chan = bss_desc->channel;
487
488 memcpy(info->country_code, adapter->country_code,
489 IEEE80211_COUNTRY_STRING_LEN);
490
491 info->media_connected = priv->media_connected;
492
493 info->max_power_level = priv->max_tx_power_level;
494 info->min_power_level = priv->min_tx_power_level;
495
496 info->bcn_nf_last = priv->bcn_nf_last;
497
498 if (priv->sec_info.wep_enabled)
499 info->wep_status = true;
500 else
501 info->wep_status = false;
502
503 info->is_hs_configured = test_bit(NXPWIFI_IS_HS_CONFIGURED,
504 &adapter->work_flags);
505 info->is_deep_sleep = adapter->is_deep_sleep;
506
507 return 0;
508 }
509
510 /* The function disables auto deep sleep mode */
nxpwifi_disable_auto_ds(struct nxpwifi_private * priv)511 int nxpwifi_disable_auto_ds(struct nxpwifi_private *priv)
512 {
513 struct nxpwifi_ds_auto_ds auto_ds = {
514 .auto_ds = DEEP_SLEEP_OFF,
515 };
516
517 return nxpwifi_send_cmd(priv, HOST_CMD_802_11_PS_MODE_ENH,
518 DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);
519 }
520 EXPORT_SYMBOL_GPL(nxpwifi_disable_auto_ds);
521
522 /* Sends IOCTL request to get the data rate */
nxpwifi_drv_get_data_rate(struct nxpwifi_private * priv,u32 * rate)523 int nxpwifi_drv_get_data_rate(struct nxpwifi_private *priv, u32 *rate)
524 {
525 int ret;
526
527 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_TX_RATE_QUERY,
528 HOST_ACT_GEN_GET, 0, NULL, true);
529
530 if (!ret) {
531 if (priv->is_data_rate_auto)
532 *rate = nxpwifi_index_to_data_rate(priv, priv->tx_rate,
533 priv->tx_htinfo);
534 else
535 *rate = priv->data_rate;
536 }
537
538 return ret;
539 }
540
541 /* IOCTL request handler to set tx power configuration */
nxpwifi_set_tx_power(struct nxpwifi_private * priv,struct nxpwifi_power_cfg * power_cfg)542 int nxpwifi_set_tx_power(struct nxpwifi_private *priv,
543 struct nxpwifi_power_cfg *power_cfg)
544 {
545 int ret;
546 struct host_cmd_ds_txpwr_cfg *txp_cfg;
547 struct nxpwifi_types_power_group *pg_tlv;
548 struct nxpwifi_power_group *pg;
549 u8 *buf;
550 u16 dbm = 0;
551
552 if (!power_cfg->is_power_auto) {
553 dbm = (u16)power_cfg->power_level;
554 if (dbm < priv->min_tx_power_level ||
555 dbm > priv->max_tx_power_level) {
556 nxpwifi_dbg(priv->adapter, ERROR,
557 "txpower value %d dBm\t"
558 "is out of range (%d dBm-%d dBm)\n",
559 dbm, priv->min_tx_power_level,
560 priv->max_tx_power_level);
561 return -EINVAL;
562 }
563 }
564 buf = kzalloc(NXPWIFI_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
565 if (!buf)
566 return -ENOMEM;
567
568 txp_cfg = (struct host_cmd_ds_txpwr_cfg *)buf;
569 txp_cfg->action = cpu_to_le16(HOST_ACT_GEN_SET);
570 if (!power_cfg->is_power_auto) {
571 u16 dbm_min = power_cfg->is_power_fixed ?
572 dbm : priv->min_tx_power_level;
573
574 txp_cfg->mode = cpu_to_le32(1);
575 pg_tlv = (struct nxpwifi_types_power_group *)
576 (buf + sizeof(struct host_cmd_ds_txpwr_cfg));
577 pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);
578 pg_tlv->length =
579 cpu_to_le16(4 * sizeof(struct nxpwifi_power_group));
580 pg = (struct nxpwifi_power_group *)
581 (buf + sizeof(struct host_cmd_ds_txpwr_cfg)
582 + sizeof(struct nxpwifi_types_power_group));
583 /* Power group for modulation class HR/DSSS */
584 pg->first_rate_code = 0x00;
585 pg->last_rate_code = 0x03;
586 pg->modulation_class = MOD_CLASS_HR_DSSS;
587 pg->power_step = 0;
588 pg->power_min = (s8)dbm_min;
589 pg->power_max = (s8)dbm;
590 pg++;
591 /* Power group for modulation class OFDM */
592 pg->first_rate_code = 0x00;
593 pg->last_rate_code = 0x07;
594 pg->modulation_class = MOD_CLASS_OFDM;
595 pg->power_step = 0;
596 pg->power_min = (s8)dbm_min;
597 pg->power_max = (s8)dbm;
598 pg++;
599 /* Power group for modulation class HTBW20 */
600 pg->first_rate_code = 0x00;
601 pg->last_rate_code = 0x20;
602 pg->modulation_class = MOD_CLASS_HT;
603 pg->power_step = 0;
604 pg->power_min = (s8)dbm_min;
605 pg->power_max = (s8)dbm;
606 pg->ht_bandwidth = HT_BW_20;
607 pg++;
608 /* Power group for modulation class HTBW40 */
609 pg->first_rate_code = 0x00;
610 pg->last_rate_code = 0x20;
611 pg->modulation_class = MOD_CLASS_HT;
612 pg->power_step = 0;
613 pg->power_min = (s8)dbm_min;
614 pg->power_max = (s8)dbm;
615 pg->ht_bandwidth = HT_BW_40;
616 }
617 ret = nxpwifi_send_cmd(priv, HOST_CMD_TXPWR_CFG,
618 HOST_ACT_GEN_SET, 0, buf, true);
619
620 kfree(buf);
621 return ret;
622 }
623
624 /* IOCTL request handler to get power save mode */
nxpwifi_drv_set_power(struct nxpwifi_private * priv,u32 * ps_mode)625 int nxpwifi_drv_set_power(struct nxpwifi_private *priv, u32 *ps_mode)
626 {
627 int ret;
628 struct nxpwifi_adapter *adapter = priv->adapter;
629 u16 sub_cmd;
630
631 if (*ps_mode)
632 adapter->ps_mode = NXPWIFI_802_11_POWER_MODE_PSP;
633 else
634 adapter->ps_mode = NXPWIFI_802_11_POWER_MODE_CAM;
635 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
636 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_PS_MODE_ENH,
637 sub_cmd, BITMAP_STA_PS, NULL, true);
638 if (!ret && sub_cmd == DIS_AUTO_PS)
639 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_PS_MODE_ENH,
640 GET_PS, 0, NULL, false);
641
642 return ret;
643 }
644
645 /* IOCTL request handler to set/reset WPA element */
nxpwifi_set_wpa_ie(struct nxpwifi_private * priv,u8 * ie_data_ptr,u16 ie_len)646 static int nxpwifi_set_wpa_ie(struct nxpwifi_private *priv,
647 u8 *ie_data_ptr, u16 ie_len)
648 {
649 if (ie_len) {
650 if (ie_len > sizeof(priv->wpa_ie)) {
651 nxpwifi_dbg(priv->adapter, ERROR,
652 "failed to copy WPA element, too big\n");
653 return -EINVAL;
654 }
655 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
656 priv->wpa_ie_len = ie_len;
657 nxpwifi_dbg(priv->adapter, CMD,
658 "cmd: Set WPA element len=%d element=%#x\n",
659 priv->wpa_ie_len, priv->wpa_ie[0]);
660
661 if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
662 priv->sec_info.wpa_enabled = true;
663 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
664 priv->sec_info.wpa2_enabled = true;
665 } else {
666 priv->sec_info.wpa_enabled = false;
667 priv->sec_info.wpa2_enabled = false;
668 }
669 } else {
670 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
671 priv->wpa_ie_len = 0;
672 nxpwifi_dbg(priv->adapter, INFO,
673 "info: reset WPA element len=%d element=%#x\n",
674 priv->wpa_ie_len, priv->wpa_ie[0]);
675 priv->sec_info.wpa_enabled = false;
676 priv->sec_info.wpa2_enabled = false;
677 }
678
679 return 0;
680 }
681
682 /* IOCTL request handler to set/reset WPS element */
nxpwifi_set_wps_ie(struct nxpwifi_private * priv,u8 * ie_data_ptr,u16 ie_len)683 static int nxpwifi_set_wps_ie(struct nxpwifi_private *priv,
684 u8 *ie_data_ptr, u16 ie_len)
685 {
686 if (ie_len) {
687 if (ie_len > NXPWIFI_MAX_VSIE_LEN) {
688 nxpwifi_dbg(priv->adapter, ERROR,
689 "info: failed to copy WPS element, too big\n");
690 return -EINVAL;
691 }
692
693 priv->wps_ie = kzalloc(NXPWIFI_MAX_VSIE_LEN, GFP_KERNEL);
694 if (!priv->wps_ie)
695 return -ENOMEM;
696
697 memcpy(priv->wps_ie, ie_data_ptr, ie_len);
698 priv->wps_ie_len = ie_len;
699 nxpwifi_dbg(priv->adapter, CMD,
700 "cmd: Set WPS element len=%d element=%#x\n",
701 priv->wps_ie_len, priv->wps_ie[0]);
702 } else {
703 kfree(priv->wps_ie);
704 priv->wps_ie_len = ie_len;
705 nxpwifi_dbg(priv->adapter, INFO,
706 "info: Reset WPS element len=%d\n", priv->wps_ie_len);
707 }
708 return 0;
709 }
710
711 /* IOCTL request handler to set WEP network key */
712 static int
nxpwifi_sec_ioctl_set_wep_key(struct nxpwifi_private * priv,struct nxpwifi_ds_encrypt_key * encrypt_key)713 nxpwifi_sec_ioctl_set_wep_key(struct nxpwifi_private *priv,
714 struct nxpwifi_ds_encrypt_key *encrypt_key)
715 {
716 struct nxpwifi_adapter *adapter = priv->adapter;
717 int ret;
718 struct nxpwifi_wep_key *wep_key;
719 int index;
720
721 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
722 priv->wep_key_curr_index = 0;
723 wep_key = &priv->wep_key[priv->wep_key_curr_index];
724 index = encrypt_key->key_index;
725 if (encrypt_key->key_disable) {
726 priv->sec_info.wep_enabled = 0;
727 } else if (!encrypt_key->key_len) {
728 /* Copy the required key as the current key */
729 wep_key = &priv->wep_key[index];
730 if (!wep_key->key_length) {
731 nxpwifi_dbg(adapter, ERROR,
732 "key not set, so cannot enable it\n");
733 return -EINVAL;
734 }
735
736 memcpy(encrypt_key->key_material,
737 wep_key->key_material, wep_key->key_length);
738 encrypt_key->key_len = wep_key->key_length;
739
740 priv->wep_key_curr_index = (u16)index;
741 priv->sec_info.wep_enabled = 1;
742 } else {
743 wep_key = &priv->wep_key[index];
744 memset(wep_key, 0, sizeof(struct nxpwifi_wep_key));
745 /* Copy the key in the driver */
746 memcpy(wep_key->key_material,
747 encrypt_key->key_material,
748 encrypt_key->key_len);
749 wep_key->key_index = index;
750 wep_key->key_length = encrypt_key->key_len;
751 priv->sec_info.wep_enabled = 1;
752 }
753 if (wep_key->key_length) {
754 void *enc_key;
755
756 if (encrypt_key->key_disable) {
757 memset(&priv->wep_key[index], 0,
758 sizeof(struct nxpwifi_wep_key));
759 goto done;
760 }
761
762 enc_key = encrypt_key;
763
764 /* Send request to firmware */
765 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_KEY_MATERIAL,
766 HOST_ACT_GEN_SET, 0, enc_key, false);
767 if (ret)
768 return ret;
769 }
770
771 done:
772 if (priv->sec_info.wep_enabled)
773 priv->curr_pkt_filter |= HOST_ACT_MAC_WEP_ENABLE;
774 else
775 priv->curr_pkt_filter &= ~HOST_ACT_MAC_WEP_ENABLE;
776
777 ret = nxpwifi_send_cmd(priv, HOST_CMD_MAC_CONTROL,
778 HOST_ACT_GEN_SET, 0,
779 &priv->curr_pkt_filter, true);
780
781 return ret;
782 }
783
784 /* IOCTL request handler to set WPA key */
785 static int
nxpwifi_sec_ioctl_set_wpa_key(struct nxpwifi_private * priv,struct nxpwifi_ds_encrypt_key * encrypt_key)786 nxpwifi_sec_ioctl_set_wpa_key(struct nxpwifi_private *priv,
787 struct nxpwifi_ds_encrypt_key *encrypt_key)
788 {
789 int ret;
790 u8 remove_key = false;
791
792 /* Current driver only supports key length of up to 32 bytes */
793 if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
794 nxpwifi_dbg(priv->adapter, ERROR,
795 "key length too long\n");
796 return -EINVAL;
797 }
798
799 if (!encrypt_key->key_index)
800 encrypt_key->key_index = NXPWIFI_KEY_INDEX_UNICAST;
801
802 if (remove_key)
803 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_KEY_MATERIAL,
804 HOST_ACT_GEN_SET,
805 !KEY_INFO_ENABLED, encrypt_key, true);
806 else
807 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_KEY_MATERIAL,
808 HOST_ACT_GEN_SET,
809 KEY_INFO_ENABLED, encrypt_key, true);
810
811 return ret;
812 }
813
814 /* IOCTL request handler to set/get network keys */
815 static int
nxpwifi_sec_ioctl_encrypt_key(struct nxpwifi_private * priv,struct nxpwifi_ds_encrypt_key * encrypt_key)816 nxpwifi_sec_ioctl_encrypt_key(struct nxpwifi_private *priv,
817 struct nxpwifi_ds_encrypt_key *encrypt_key)
818 {
819 int status;
820
821 if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
822 status = nxpwifi_sec_ioctl_set_wpa_key(priv, encrypt_key);
823 else
824 status = nxpwifi_sec_ioctl_set_wep_key(priv, encrypt_key);
825
826 return status;
827 }
828
829 /* Return driver version string */
830 int
nxpwifi_drv_get_driver_version(struct nxpwifi_adapter * adapter,char * version,int max_len)831 nxpwifi_drv_get_driver_version(struct nxpwifi_adapter *adapter, char *version,
832 int max_len)
833 {
834 union {
835 __le32 l;
836 u8 c[4];
837 } ver;
838 char fw_ver[32];
839
840 ver.l = cpu_to_le32(adapter->fw_release_number);
841 sprintf(fw_ver, "%u.%u.%u.p%u.%u", ver.c[2], ver.c[1],
842 ver.c[0], ver.c[3], adapter->fw_hotfix_ver);
843
844 snprintf(version, max_len, nxpwifi_driver_version, fw_ver);
845
846 nxpwifi_dbg(adapter, MSG, "info: NXPWIFI VERSION: %s\n", version);
847
848 return 0;
849 }
850
851 /* Sends IOCTL request to set encoding parameters */
nxpwifi_set_encode(struct nxpwifi_private * priv,struct key_params * kp,const u8 * key,int key_len,u8 key_index,const u8 * mac_addr,int disable)852 int nxpwifi_set_encode(struct nxpwifi_private *priv, struct key_params *kp,
853 const u8 *key, int key_len, u8 key_index,
854 const u8 *mac_addr, int disable)
855 {
856 struct nxpwifi_ds_encrypt_key encrypt_key;
857
858 memset(&encrypt_key, 0, sizeof(encrypt_key));
859 encrypt_key.key_len = key_len;
860 encrypt_key.key_index = key_index;
861
862 if (kp) {
863 encrypt_key.key_cipher = kp->cipher;
864 if (kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
865 kp->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
866 encrypt_key.is_igtk_key = true;
867 }
868
869 if (!disable) {
870 if (key_len)
871 memcpy(encrypt_key.key_material, key, key_len);
872 else
873 encrypt_key.is_current_wep_key = true;
874
875 if (mac_addr)
876 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
877 if (kp && kp->seq && kp->seq_len) {
878 memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
879 encrypt_key.pn_len = kp->seq_len;
880 encrypt_key.is_rx_seq_valid = true;
881 }
882 } else {
883 encrypt_key.key_disable = true;
884 if (mac_addr)
885 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
886 }
887
888 return nxpwifi_sec_ioctl_encrypt_key(priv, &encrypt_key);
889 }
890
891 /* Sends IOCTL request to get extended version */
892 int
nxpwifi_get_ver_ext(struct nxpwifi_private * priv,u32 version_str_sel)893 nxpwifi_get_ver_ext(struct nxpwifi_private *priv, u32 version_str_sel)
894 {
895 struct nxpwifi_ver_ext ver_ext;
896
897 memset(&ver_ext, 0, sizeof(ver_ext));
898 ver_ext.version_str_sel = version_str_sel;
899
900 return nxpwifi_send_cmd(priv, HOST_CMD_VERSION_EXT,
901 HOST_ACT_GEN_GET, 0, &ver_ext, true);
902 }
903
904 int
nxpwifi_remain_on_chan_cfg(struct nxpwifi_private * priv,u16 action,struct ieee80211_channel * chan,unsigned int duration)905 nxpwifi_remain_on_chan_cfg(struct nxpwifi_private *priv, u16 action,
906 struct ieee80211_channel *chan,
907 unsigned int duration)
908 {
909 struct host_cmd_ds_remain_on_chan roc_cfg;
910 u8 sc;
911 int ret;
912
913 memset(&roc_cfg, 0, sizeof(roc_cfg));
914 roc_cfg.action = cpu_to_le16(action);
915 if (action == HOST_ACT_GEN_SET) {
916 roc_cfg.band_cfg = chan->band;
917 sc = nxpwifi_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);
918 roc_cfg.band_cfg |= (sc << 2);
919
920 roc_cfg.channel =
921 ieee80211_frequency_to_channel(chan->center_freq);
922 roc_cfg.duration = cpu_to_le32(duration);
923 }
924 ret = nxpwifi_send_cmd(priv, HOST_CMD_REMAIN_ON_CHAN,
925 action, 0, &roc_cfg, true);
926 if (ret) {
927 nxpwifi_dbg(priv->adapter, ERROR,
928 "failed to remain on channel\n");
929 return ret;
930 }
931
932 return roc_cfg.status;
933 }
934
935 /* Sends IOCTL request to get statistics information */
936 int
nxpwifi_get_stats_info(struct nxpwifi_private * priv,struct nxpwifi_ds_get_stats * log)937 nxpwifi_get_stats_info(struct nxpwifi_private *priv,
938 struct nxpwifi_ds_get_stats *log)
939 {
940 return nxpwifi_send_cmd(priv, HOST_CMD_802_11_GET_LOG,
941 HOST_ACT_GEN_GET, 0, log, true);
942 }
943
944 /* IOCTL request handler to read/write register */
nxpwifi_reg_mem_ioctl_reg_rw(struct nxpwifi_private * priv,struct nxpwifi_ds_reg_rw * reg_rw,u16 action)945 static int nxpwifi_reg_mem_ioctl_reg_rw(struct nxpwifi_private *priv,
946 struct nxpwifi_ds_reg_rw *reg_rw,
947 u16 action)
948 {
949 u16 cmd_no;
950
951 switch (reg_rw->type) {
952 case NXPWIFI_REG_MAC:
953 cmd_no = HOST_CMD_MAC_REG_ACCESS;
954 break;
955 case NXPWIFI_REG_BBP:
956 cmd_no = HOST_CMD_BBP_REG_ACCESS;
957 break;
958 case NXPWIFI_REG_RF:
959 cmd_no = HOST_CMD_RF_REG_ACCESS;
960 break;
961 case NXPWIFI_REG_PMIC:
962 cmd_no = HOST_CMD_PMIC_REG_ACCESS;
963 break;
964 case NXPWIFI_REG_CAU:
965 cmd_no = HOST_CMD_CAU_REG_ACCESS;
966 break;
967 default:
968 return -EINVAL;
969 }
970
971 return nxpwifi_send_cmd(priv, cmd_no, action, 0, reg_rw, true);
972 }
973
974 /* Sends IOCTL request to write to a register */
975 int
nxpwifi_reg_write(struct nxpwifi_private * priv,u32 reg_type,u32 reg_offset,u32 reg_value)976 nxpwifi_reg_write(struct nxpwifi_private *priv, u32 reg_type,
977 u32 reg_offset, u32 reg_value)
978 {
979 struct nxpwifi_ds_reg_rw reg_rw;
980
981 reg_rw.type = reg_type;
982 reg_rw.offset = reg_offset;
983 reg_rw.value = reg_value;
984
985 return nxpwifi_reg_mem_ioctl_reg_rw(priv, ®_rw, HOST_ACT_GEN_SET);
986 }
987
988 /* Sends IOCTL request to read from a register */
989 int
nxpwifi_reg_read(struct nxpwifi_private * priv,u32 reg_type,u32 reg_offset,u32 * value)990 nxpwifi_reg_read(struct nxpwifi_private *priv, u32 reg_type,
991 u32 reg_offset, u32 *value)
992 {
993 int ret;
994 struct nxpwifi_ds_reg_rw reg_rw;
995
996 reg_rw.type = reg_type;
997 reg_rw.offset = reg_offset;
998 ret = nxpwifi_reg_mem_ioctl_reg_rw(priv, ®_rw, HOST_ACT_GEN_GET);
999
1000 if (!ret)
1001 *value = reg_rw.value;
1002
1003 return ret;
1004 }
1005
1006 /* Sends IOCTL request to read from EEPROM */
1007 int
nxpwifi_eeprom_read(struct nxpwifi_private * priv,u16 offset,u16 bytes,u8 * value)1008 nxpwifi_eeprom_read(struct nxpwifi_private *priv, u16 offset, u16 bytes,
1009 u8 *value)
1010 {
1011 int ret;
1012 struct nxpwifi_ds_read_eeprom rd_eeprom;
1013
1014 rd_eeprom.offset = offset;
1015 rd_eeprom.byte_count = bytes;
1016
1017 /* Send request to firmware */
1018 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_EEPROM_ACCESS,
1019 HOST_ACT_GEN_GET, 0, &rd_eeprom, true);
1020
1021 if (!ret)
1022 memcpy(value, rd_eeprom.value,
1023 min((u16)MAX_EEPROM_DATA, rd_eeprom.byte_count));
1024 return ret;
1025 }
1026
1027 /* Set generic IE(s); handle WPA/WPS specially */
1028 static int
nxpwifi_set_gen_ie_helper(struct nxpwifi_private * priv,u8 * ie_data_ptr,u16 ie_len)1029 nxpwifi_set_gen_ie_helper(struct nxpwifi_private *priv, u8 *ie_data_ptr,
1030 u16 ie_len)
1031 {
1032 struct ieee80211_vendor_ie *pvendor_ie;
1033 static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
1034 static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
1035 u16 unparsed_len = ie_len, cur_ie_len;
1036
1037 /* If the passed length is zero, reset the buffer */
1038 if (!ie_len) {
1039 priv->gen_ie_buf_len = 0;
1040 priv->wps.session_enable = false;
1041 return 0;
1042 } else if (!ie_data_ptr ||
1043 ie_len <= sizeof(struct element)) {
1044 return -EINVAL;
1045 }
1046 pvendor_ie = (struct ieee80211_vendor_ie *)ie_data_ptr;
1047
1048 while (pvendor_ie) {
1049 cur_ie_len = pvendor_ie->len + sizeof(struct element);
1050
1051 if (pvendor_ie->element_id == WLAN_EID_RSN) {
1052 /* element is a WPA/WPA2 element so call set_wpa function */
1053 nxpwifi_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len);
1054 priv->wps.session_enable = false;
1055 goto next_ie;
1056 }
1057
1058 if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) {
1059 /* Test to see if it is a WPA element, if not, then it is a gen element */
1060 if (!memcmp(&pvendor_ie->oui, wpa_oui,
1061 sizeof(wpa_oui))) {
1062 /* element is a WPA/WPA2 element so call set_wpa function */
1063 nxpwifi_set_wpa_ie(priv, (u8 *)pvendor_ie,
1064 cur_ie_len);
1065 priv->wps.session_enable = false;
1066 goto next_ie;
1067 }
1068
1069 if (!memcmp(&pvendor_ie->oui, wps_oui,
1070 sizeof(wps_oui))) {
1071 /*
1072 * Test to see if it is a WPS element, if so, enable wps session
1073 * flag
1074 */
1075 priv->wps.session_enable = true;
1076 nxpwifi_dbg(priv->adapter, MSG,
1077 "WPS Session Enabled.\n");
1078 nxpwifi_set_wps_ie(priv, (u8 *)pvendor_ie,
1079 cur_ie_len);
1080 goto next_ie;
1081 }
1082 }
1083
1084 /*
1085 * Verify that the passed length is not larger than the available space
1086 * remaining in the buffer
1087 */
1088 if (cur_ie_len <
1089 (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
1090 /* Append the passed data to the end of the genIeBuffer */
1091 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len,
1092 (u8 *)pvendor_ie, cur_ie_len);
1093 /* Increment the stored buffer length by the size passed */
1094 priv->gen_ie_buf_len += cur_ie_len;
1095 }
1096
1097 next_ie:
1098 unparsed_len -= cur_ie_len;
1099
1100 if (unparsed_len <= sizeof(struct element))
1101 pvendor_ie = NULL;
1102 else
1103 pvendor_ie = (struct ieee80211_vendor_ie *)
1104 (((u8 *)pvendor_ie) + cur_ie_len);
1105 }
1106
1107 return 0;
1108 }
1109
1110 /* IOCTL request handler to set/get generic element */
nxpwifi_misc_ioctl_gen_ie(struct nxpwifi_private * priv,struct nxpwifi_ds_misc_gen_ie * gen_ie,u16 action)1111 static int nxpwifi_misc_ioctl_gen_ie(struct nxpwifi_private *priv,
1112 struct nxpwifi_ds_misc_gen_ie *gen_ie,
1113 u16 action)
1114 {
1115 struct nxpwifi_adapter *adapter = priv->adapter;
1116
1117 switch (gen_ie->type) {
1118 case NXPWIFI_IE_TYPE_GEN_IE:
1119 if (action == HOST_ACT_GEN_GET) {
1120 gen_ie->len = priv->wpa_ie_len;
1121 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
1122 } else {
1123 nxpwifi_set_gen_ie_helper(priv, gen_ie->ie_data,
1124 (u16)gen_ie->len);
1125 }
1126 break;
1127 case NXPWIFI_IE_TYPE_ARP_FILTER:
1128 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
1129 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
1130 adapter->arp_filter_size = 0;
1131 nxpwifi_dbg(adapter, ERROR,
1132 "invalid ARP filter size\n");
1133 return -EINVAL;
1134 }
1135 memcpy(adapter->arp_filter, gen_ie->ie_data, gen_ie->len);
1136 adapter->arp_filter_size = gen_ie->len;
1137 break;
1138 default:
1139 nxpwifi_dbg(adapter, ERROR, "invalid element type\n");
1140 return -EINVAL;
1141 }
1142 return 0;
1143 }
1144
1145 /* Sends IOCTL request to set a generic element */
1146 int
nxpwifi_set_gen_ie(struct nxpwifi_private * priv,const u8 * ie,int ie_len)1147 nxpwifi_set_gen_ie(struct nxpwifi_private *priv, const u8 *ie, int ie_len)
1148 {
1149 struct nxpwifi_ds_misc_gen_ie gen_ie;
1150
1151 if (ie_len > IEEE_MAX_IE_SIZE)
1152 return -EFAULT;
1153
1154 gen_ie.type = NXPWIFI_IE_TYPE_GEN_IE;
1155 gen_ie.len = ie_len;
1156 memcpy(gen_ie.ie_data, ie, ie_len);
1157
1158 return nxpwifi_misc_ioctl_gen_ie(priv, &gen_ie, HOST_ACT_GEN_SET);
1159 }
1160
1161 /* Get Host Sleep wakeup reason */
nxpwifi_get_wakeup_reason(struct nxpwifi_private * priv,u16 action,int cmd_type,struct nxpwifi_ds_wakeup_reason * wakeup_reason)1162 int nxpwifi_get_wakeup_reason(struct nxpwifi_private *priv, u16 action,
1163 int cmd_type,
1164 struct nxpwifi_ds_wakeup_reason *wakeup_reason)
1165 {
1166 return nxpwifi_send_cmd(priv, HOST_CMD_HS_WAKEUP_REASON,
1167 HOST_ACT_GEN_GET, 0, wakeup_reason,
1168 cmd_type == NXPWIFI_SYNC_CMD);
1169 }
1170
nxpwifi_get_chan_info(struct nxpwifi_private * priv,struct nxpwifi_channel_band * channel_band)1171 int nxpwifi_get_chan_info(struct nxpwifi_private *priv,
1172 struct nxpwifi_channel_band *channel_band)
1173 {
1174 return nxpwifi_send_cmd(priv, HOST_CMD_STA_CONFIGURE,
1175 HOST_ACT_GEN_GET, 0, channel_band,
1176 NXPWIFI_SYNC_CMD);
1177 }
1178