1*828c91f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2277b024eSKalle Valo /*
3932183aaSGanapathi Bhat * NXP Wireless LAN device driver: functions for station ioctl
4277b024eSKalle Valo *
5932183aaSGanapathi Bhat * Copyright 2011-2020 NXP
6277b024eSKalle Valo */
7277b024eSKalle Valo
8277b024eSKalle Valo #include "decl.h"
9277b024eSKalle Valo #include "ioctl.h"
10277b024eSKalle Valo #include "util.h"
11277b024eSKalle Valo #include "fw.h"
12277b024eSKalle Valo #include "main.h"
13277b024eSKalle Valo #include "wmm.h"
14277b024eSKalle Valo #include "11n.h"
15277b024eSKalle Valo #include "cfg80211.h"
16277b024eSKalle Valo
17277b024eSKalle Valo static int disconnect_on_suspend;
18277b024eSKalle Valo module_param(disconnect_on_suspend, int, 0644);
19277b024eSKalle Valo
20277b024eSKalle Valo /*
21277b024eSKalle Valo * Copies the multicast address list from device to driver.
22277b024eSKalle Valo *
23277b024eSKalle Valo * This function does not validate the destination memory for
24277b024eSKalle Valo * size, and the calling function must ensure enough memory is
25277b024eSKalle Valo * available.
26277b024eSKalle Valo */
mwifiex_copy_mcast_addr(struct mwifiex_multicast_list * mlist,struct net_device * dev)27277b024eSKalle Valo int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
28277b024eSKalle Valo struct net_device *dev)
29277b024eSKalle Valo {
30277b024eSKalle Valo int i = 0;
31277b024eSKalle Valo struct netdev_hw_addr *ha;
32277b024eSKalle Valo
33277b024eSKalle Valo netdev_for_each_mc_addr(ha, dev)
34277b024eSKalle Valo memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
35277b024eSKalle Valo
36277b024eSKalle Valo return i;
37277b024eSKalle Valo }
38277b024eSKalle Valo
39277b024eSKalle Valo /*
40277b024eSKalle Valo * Wait queue completion handler.
41277b024eSKalle Valo *
42277b024eSKalle Valo * This function waits on a cmd wait queue. It also cancels the pending
43277b024eSKalle Valo * request after waking up, in case of errors.
44277b024eSKalle Valo */
mwifiex_wait_queue_complete(struct mwifiex_adapter * adapter,struct cmd_ctrl_node * cmd_queued)45277b024eSKalle Valo int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
46277b024eSKalle Valo struct cmd_ctrl_node *cmd_queued)
47277b024eSKalle Valo {
48277b024eSKalle Valo int status;
49277b024eSKalle Valo
50277b024eSKalle Valo /* Wait for completion */
51277b024eSKalle Valo status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait,
52277b024eSKalle Valo *(cmd_queued->condition),
53277b024eSKalle Valo (12 * HZ));
54277b024eSKalle Valo if (status <= 0) {
55277b024eSKalle Valo if (status == 0)
56277b024eSKalle Valo status = -ETIMEDOUT;
57277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",
58277b024eSKalle Valo status);
59277b024eSKalle Valo mwifiex_cancel_all_pending_cmd(adapter);
60277b024eSKalle Valo return status;
61277b024eSKalle Valo }
62277b024eSKalle Valo
63277b024eSKalle Valo status = adapter->cmd_wait_q.status;
64277b024eSKalle Valo adapter->cmd_wait_q.status = 0;
65277b024eSKalle Valo
66277b024eSKalle Valo return status;
67277b024eSKalle Valo }
68277b024eSKalle Valo
69277b024eSKalle Valo /*
70277b024eSKalle Valo * This function prepares the correct firmware command and
71277b024eSKalle Valo * issues it to set the multicast list.
72277b024eSKalle Valo *
73277b024eSKalle Valo * This function can be used to enable promiscuous mode, or enable all
74277b024eSKalle Valo * multicast packets, or to enable selective multicast.
75277b024eSKalle Valo */
mwifiex_request_set_multicast_list(struct mwifiex_private * priv,struct mwifiex_multicast_list * mcast_list)76277b024eSKalle Valo int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
77277b024eSKalle Valo struct mwifiex_multicast_list *mcast_list)
78277b024eSKalle Valo {
79277b024eSKalle Valo int ret = 0;
80277b024eSKalle Valo u16 old_pkt_filter;
81277b024eSKalle Valo
82277b024eSKalle Valo old_pkt_filter = priv->curr_pkt_filter;
83277b024eSKalle Valo
84277b024eSKalle Valo if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
85277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
86277b024eSKalle Valo "info: Enable Promiscuous mode\n");
87277b024eSKalle Valo priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
88277b024eSKalle Valo priv->curr_pkt_filter &=
89277b024eSKalle Valo ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
90277b024eSKalle Valo } else {
91277b024eSKalle Valo /* Multicast */
92277b024eSKalle Valo priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
93277b024eSKalle Valo if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {
94277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
95277b024eSKalle Valo "info: Enabling All Multicast!\n");
96277b024eSKalle Valo priv->curr_pkt_filter |=
97277b024eSKalle Valo HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
98277b024eSKalle Valo } else {
99277b024eSKalle Valo priv->curr_pkt_filter &=
100277b024eSKalle Valo ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
101277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
102277b024eSKalle Valo "info: Set multicast list=%d\n",
103277b024eSKalle Valo mcast_list->num_multicast_addr);
104277b024eSKalle Valo /* Send multicast addresses to firmware */
105277b024eSKalle Valo ret = mwifiex_send_cmd(priv,
106277b024eSKalle Valo HostCmd_CMD_MAC_MULTICAST_ADR,
107277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0,
108277b024eSKalle Valo mcast_list, false);
109277b024eSKalle Valo }
110277b024eSKalle Valo }
111277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
112277b024eSKalle Valo "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
113277b024eSKalle Valo old_pkt_filter, priv->curr_pkt_filter);
114277b024eSKalle Valo if (old_pkt_filter != priv->curr_pkt_filter) {
115277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
116277b024eSKalle Valo HostCmd_ACT_GEN_SET,
117277b024eSKalle Valo 0, &priv->curr_pkt_filter, false);
118277b024eSKalle Valo }
119277b024eSKalle Valo
120277b024eSKalle Valo return ret;
121277b024eSKalle Valo }
122277b024eSKalle Valo
123277b024eSKalle Valo /*
124277b024eSKalle Valo * This function fills bss descriptor structure using provided
125277b024eSKalle Valo * information.
126277b024eSKalle Valo * beacon_ie buffer is allocated in this function. It is caller's
127277b024eSKalle Valo * responsibility to free the memory.
128277b024eSKalle Valo */
mwifiex_fill_new_bss_desc(struct mwifiex_private * priv,struct cfg80211_bss * bss,struct mwifiex_bssdescriptor * bss_desc)129277b024eSKalle Valo int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
130277b024eSKalle Valo struct cfg80211_bss *bss,
131277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc)
132277b024eSKalle Valo {
133277b024eSKalle Valo u8 *beacon_ie;
134277b024eSKalle Valo size_t beacon_ie_len;
135277b024eSKalle Valo struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
136277b024eSKalle Valo const struct cfg80211_bss_ies *ies;
137277b024eSKalle Valo
138277b024eSKalle Valo rcu_read_lock();
139277b024eSKalle Valo ies = rcu_dereference(bss->ies);
140277b024eSKalle Valo beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
141277b024eSKalle Valo beacon_ie_len = ies->len;
142277b024eSKalle Valo bss_desc->timestamp = ies->tsf;
143277b024eSKalle Valo rcu_read_unlock();
144277b024eSKalle Valo
145277b024eSKalle Valo if (!beacon_ie) {
146277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
147277b024eSKalle Valo " failed to alloc beacon_ie\n");
148277b024eSKalle Valo return -ENOMEM;
149277b024eSKalle Valo }
150277b024eSKalle Valo
151277b024eSKalle Valo memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
152277b024eSKalle Valo bss_desc->rssi = bss->signal;
153277b024eSKalle Valo /* The caller of this function will free beacon_ie */
154277b024eSKalle Valo bss_desc->beacon_buf = beacon_ie;
155277b024eSKalle Valo bss_desc->beacon_buf_size = beacon_ie_len;
156277b024eSKalle Valo bss_desc->beacon_period = bss->beacon_interval;
157277b024eSKalle Valo bss_desc->cap_info_bitmap = bss->capability;
158277b024eSKalle Valo bss_desc->bss_band = bss_priv->band;
159277b024eSKalle Valo bss_desc->fw_tsf = bss_priv->fw_tsf;
160277b024eSKalle Valo if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
161277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
162277b024eSKalle Valo "info: InterpretIE: AP WEP enabled\n");
163277b024eSKalle Valo bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
164277b024eSKalle Valo } else {
165277b024eSKalle Valo bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
166277b024eSKalle Valo }
167277b024eSKalle Valo if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
168277b024eSKalle Valo bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
169277b024eSKalle Valo else
170277b024eSKalle Valo bss_desc->bss_mode = NL80211_IFTYPE_STATION;
171277b024eSKalle Valo
172277b024eSKalle Valo /* Disable 11ac by default. Enable it only where there
173277b024eSKalle Valo * exist VHT_CAP IE in AP beacon
174277b024eSKalle Valo */
175277b024eSKalle Valo bss_desc->disable_11ac = true;
176277b024eSKalle Valo
177277b024eSKalle Valo if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
178277b024eSKalle Valo bss_desc->sensed_11h = true;
179277b024eSKalle Valo
18053a70942SGanapathi Bhat return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
181277b024eSKalle Valo }
182277b024eSKalle Valo
mwifiex_dnld_txpwr_table(struct mwifiex_private * priv)183277b024eSKalle Valo void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
184277b024eSKalle Valo {
185277b024eSKalle Valo if (priv->adapter->dt_node) {
186277b024eSKalle Valo char txpwr[] = {"marvell,00_txpwrlimit"};
187277b024eSKalle Valo
188277b024eSKalle Valo memcpy(&txpwr[8], priv->adapter->country_code, 2);
189277b024eSKalle Valo mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
190277b024eSKalle Valo }
191277b024eSKalle Valo }
192277b024eSKalle Valo
mwifiex_process_country_ie(struct mwifiex_private * priv,struct cfg80211_bss * bss)193277b024eSKalle Valo static int mwifiex_process_country_ie(struct mwifiex_private *priv,
194277b024eSKalle Valo struct cfg80211_bss *bss)
195277b024eSKalle Valo {
196277b024eSKalle Valo const u8 *country_ie;
197277b024eSKalle Valo u8 country_ie_len;
198277b024eSKalle Valo struct mwifiex_802_11d_domain_reg *domain_info =
199277b024eSKalle Valo &priv->adapter->domain_reg;
200277b024eSKalle Valo
201277b024eSKalle Valo rcu_read_lock();
202277b024eSKalle Valo country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
203277b024eSKalle Valo if (!country_ie) {
204277b024eSKalle Valo rcu_read_unlock();
205277b024eSKalle Valo return 0;
206277b024eSKalle Valo }
207277b024eSKalle Valo
208277b024eSKalle Valo country_ie_len = country_ie[1];
209277b024eSKalle Valo if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
210277b024eSKalle Valo rcu_read_unlock();
211277b024eSKalle Valo return 0;
212277b024eSKalle Valo }
213277b024eSKalle Valo
214277b024eSKalle Valo if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
215277b024eSKalle Valo rcu_read_unlock();
216277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
217277b024eSKalle Valo "11D: skip setting domain info in FW\n");
218277b024eSKalle Valo return 0;
219277b024eSKalle Valo }
2203d94a4a8SGanapathi Bhat
2213d94a4a8SGanapathi Bhat if (country_ie_len >
2223d94a4a8SGanapathi Bhat (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) {
22365b1aae0SBrian Norris rcu_read_unlock();
2243d94a4a8SGanapathi Bhat mwifiex_dbg(priv->adapter, ERROR,
2253d94a4a8SGanapathi Bhat "11D: country_ie_len overflow!, deauth AP\n");
2263d94a4a8SGanapathi Bhat return -EINVAL;
2273d94a4a8SGanapathi Bhat }
2283d94a4a8SGanapathi Bhat
229277b024eSKalle Valo memcpy(priv->adapter->country_code, &country_ie[2], 2);
230277b024eSKalle Valo
231277b024eSKalle Valo domain_info->country_code[0] = country_ie[2];
232277b024eSKalle Valo domain_info->country_code[1] = country_ie[3];
233277b024eSKalle Valo domain_info->country_code[2] = ' ';
234277b024eSKalle Valo
235277b024eSKalle Valo country_ie_len -= IEEE80211_COUNTRY_STRING_LEN;
236277b024eSKalle Valo
237277b024eSKalle Valo domain_info->no_of_triplet =
238277b024eSKalle Valo country_ie_len / sizeof(struct ieee80211_country_ie_triplet);
239277b024eSKalle Valo
240277b024eSKalle Valo memcpy((u8 *)domain_info->triplet,
241277b024eSKalle Valo &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);
242277b024eSKalle Valo
243277b024eSKalle Valo rcu_read_unlock();
244277b024eSKalle Valo
245277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
246277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, NULL, false)) {
247277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
248277b024eSKalle Valo "11D: setting domain info in FW fail\n");
249277b024eSKalle Valo return -1;
250277b024eSKalle Valo }
251277b024eSKalle Valo
252277b024eSKalle Valo mwifiex_dnld_txpwr_table(priv);
253277b024eSKalle Valo
254277b024eSKalle Valo return 0;
255277b024eSKalle Valo }
256277b024eSKalle Valo
257277b024eSKalle Valo /*
258277b024eSKalle Valo * In Ad-Hoc mode, the IBSS is created if not found in scan list.
259277b024eSKalle Valo * In both Ad-Hoc and infra mode, an deauthentication is performed
260277b024eSKalle Valo * first.
261277b024eSKalle Valo */
mwifiex_bss_start(struct mwifiex_private * priv,struct cfg80211_bss * bss,struct cfg80211_ssid * req_ssid)262277b024eSKalle Valo int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
263277b024eSKalle Valo struct cfg80211_ssid *req_ssid)
264277b024eSKalle Valo {
265277b024eSKalle Valo int ret;
266277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
267277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc = NULL;
268277b024eSKalle Valo
269277b024eSKalle Valo priv->scan_block = false;
270277b024eSKalle Valo
271277b024eSKalle Valo if (bss) {
2723d94a4a8SGanapathi Bhat if (adapter->region_code == 0x00 &&
2733d94a4a8SGanapathi Bhat mwifiex_process_country_ie(priv, bss))
2743d94a4a8SGanapathi Bhat return -EINVAL;
275277b024eSKalle Valo
276277b024eSKalle Valo /* Allocate and fill new bss descriptor */
277277b024eSKalle Valo bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
278277b024eSKalle Valo GFP_KERNEL);
279277b024eSKalle Valo if (!bss_desc)
280277b024eSKalle Valo return -ENOMEM;
281277b024eSKalle Valo
282277b024eSKalle Valo ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
283277b024eSKalle Valo if (ret)
284277b024eSKalle Valo goto done;
285277b024eSKalle Valo }
286277b024eSKalle Valo
287277b024eSKalle Valo if (priv->bss_mode == NL80211_IFTYPE_STATION ||
288277b024eSKalle Valo priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
289277b024eSKalle Valo u8 config_bands;
290277b024eSKalle Valo
291277b024eSKalle Valo if (!bss_desc)
292277b024eSKalle Valo return -1;
293277b024eSKalle Valo
294277b024eSKalle Valo if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
295277b024eSKalle Valo HostCmd_SCAN_RADIO_TYPE_BG) {
296277b024eSKalle Valo config_bands = BAND_B | BAND_G | BAND_GN;
297277b024eSKalle Valo } else {
298277b024eSKalle Valo config_bands = BAND_A | BAND_AN;
299277b024eSKalle Valo if (adapter->fw_bands & BAND_AAC)
300277b024eSKalle Valo config_bands |= BAND_AAC;
301277b024eSKalle Valo }
302277b024eSKalle Valo
303277b024eSKalle Valo if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
304277b024eSKalle Valo adapter->config_bands = config_bands;
305277b024eSKalle Valo
306277b024eSKalle Valo ret = mwifiex_check_network_compatibility(priv, bss_desc);
307277b024eSKalle Valo if (ret)
308277b024eSKalle Valo goto done;
309277b024eSKalle Valo
310277b024eSKalle Valo if (mwifiex_11h_get_csa_closed_channel(priv) ==
311277b024eSKalle Valo (u8)bss_desc->channel) {
312277b024eSKalle Valo mwifiex_dbg(adapter, ERROR,
313277b024eSKalle Valo "Attempt to reconnect on csa closed chan(%d)\n",
314277b024eSKalle Valo bss_desc->channel);
315a6139b62SAmitkumar Karwar ret = -1;
316277b024eSKalle Valo goto done;
317277b024eSKalle Valo }
318277b024eSKalle Valo
319277b024eSKalle Valo mwifiex_dbg(adapter, INFO,
320277b024eSKalle Valo "info: SSID found in scan list ...\t"
321277b024eSKalle Valo "associating...\n");
322277b024eSKalle Valo
323277b024eSKalle Valo mwifiex_stop_net_dev_queue(priv->netdev, adapter);
324277b024eSKalle Valo if (netif_carrier_ok(priv->netdev))
325277b024eSKalle Valo netif_carrier_off(priv->netdev);
326277b024eSKalle Valo
327277b024eSKalle Valo /* Clear any past association response stored for
328277b024eSKalle Valo * application retrieval */
329277b024eSKalle Valo priv->assoc_rsp_size = 0;
330277b024eSKalle Valo ret = mwifiex_associate(priv, bss_desc);
331277b024eSKalle Valo
332277b024eSKalle Valo /* If auth type is auto and association fails using open mode,
333277b024eSKalle Valo * try to connect using shared mode */
334277b024eSKalle Valo if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
335277b024eSKalle Valo priv->sec_info.is_authtype_auto &&
336277b024eSKalle Valo priv->sec_info.wep_enabled) {
337277b024eSKalle Valo priv->sec_info.authentication_mode =
338277b024eSKalle Valo NL80211_AUTHTYPE_SHARED_KEY;
339277b024eSKalle Valo ret = mwifiex_associate(priv, bss_desc);
340277b024eSKalle Valo }
341277b024eSKalle Valo
342277b024eSKalle Valo if (bss)
343277b024eSKalle Valo cfg80211_put_bss(priv->adapter->wiphy, bss);
344277b024eSKalle Valo } else {
345277b024eSKalle Valo /* Adhoc mode */
346277b024eSKalle Valo /* If the requested SSID matches current SSID, return */
347277b024eSKalle Valo if (bss_desc && bss_desc->ssid.ssid_len &&
348277b024eSKalle Valo (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor.
349277b024eSKalle Valo ssid, &bss_desc->ssid))) {
350277b024eSKalle Valo ret = 0;
351277b024eSKalle Valo goto done;
352277b024eSKalle Valo }
353277b024eSKalle Valo
354277b024eSKalle Valo priv->adhoc_is_link_sensed = false;
355277b024eSKalle Valo
356277b024eSKalle Valo ret = mwifiex_check_network_compatibility(priv, bss_desc);
357277b024eSKalle Valo
358277b024eSKalle Valo mwifiex_stop_net_dev_queue(priv->netdev, adapter);
359277b024eSKalle Valo if (netif_carrier_ok(priv->netdev))
360277b024eSKalle Valo netif_carrier_off(priv->netdev);
361277b024eSKalle Valo
362277b024eSKalle Valo if (!ret) {
363277b024eSKalle Valo mwifiex_dbg(adapter, INFO,
364277b024eSKalle Valo "info: network found in scan\t"
365277b024eSKalle Valo " list. Joining...\n");
366277b024eSKalle Valo ret = mwifiex_adhoc_join(priv, bss_desc);
367277b024eSKalle Valo if (bss)
368277b024eSKalle Valo cfg80211_put_bss(priv->adapter->wiphy, bss);
369277b024eSKalle Valo } else {
370277b024eSKalle Valo mwifiex_dbg(adapter, INFO,
371277b024eSKalle Valo "info: Network not found in\t"
372277b024eSKalle Valo "the list, creating adhoc with ssid = %s\n",
373277b024eSKalle Valo req_ssid->ssid);
374277b024eSKalle Valo ret = mwifiex_adhoc_start(priv, req_ssid);
375277b024eSKalle Valo }
376277b024eSKalle Valo }
377277b024eSKalle Valo
378277b024eSKalle Valo done:
379277b024eSKalle Valo /* beacon_ie buffer was allocated in function
380277b024eSKalle Valo * mwifiex_fill_new_bss_desc(). Free it now.
381277b024eSKalle Valo */
382277b024eSKalle Valo if (bss_desc)
383277b024eSKalle Valo kfree(bss_desc->beacon_buf);
384277b024eSKalle Valo kfree(bss_desc);
3854699fc3fSGanapathi Bhat
3864699fc3fSGanapathi Bhat if (ret < 0)
3874699fc3fSGanapathi Bhat priv->attempted_bss_desc = NULL;
3884699fc3fSGanapathi Bhat
389277b024eSKalle Valo return ret;
390277b024eSKalle Valo }
391277b024eSKalle Valo
392277b024eSKalle Valo /*
393277b024eSKalle Valo * IOCTL request handler to set host sleep configuration.
394277b024eSKalle Valo *
395277b024eSKalle Valo * This function prepares the correct firmware command and
396277b024eSKalle Valo * issues it.
397277b024eSKalle Valo */
mwifiex_set_hs_params(struct mwifiex_private * priv,u16 action,int cmd_type,struct mwifiex_ds_hs_cfg * hs_cfg)398277b024eSKalle Valo int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
399277b024eSKalle Valo int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
400277b024eSKalle Valo
401277b024eSKalle Valo {
402277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
403277b024eSKalle Valo int status = 0;
404277b024eSKalle Valo u32 prev_cond = 0;
405277b024eSKalle Valo
406277b024eSKalle Valo if (!hs_cfg)
407277b024eSKalle Valo return -ENOMEM;
408277b024eSKalle Valo
409277b024eSKalle Valo switch (action) {
410277b024eSKalle Valo case HostCmd_ACT_GEN_SET:
411277b024eSKalle Valo if (adapter->pps_uapsd_mode) {
412277b024eSKalle Valo mwifiex_dbg(adapter, INFO,
413277b024eSKalle Valo "info: Host Sleep IOCTL\t"
414277b024eSKalle Valo "is blocked in UAPSD/PPS mode\n");
415277b024eSKalle Valo status = -1;
416277b024eSKalle Valo break;
417277b024eSKalle Valo }
418277b024eSKalle Valo if (hs_cfg->is_invoke_hostcmd) {
419277b024eSKalle Valo if (hs_cfg->conditions == HS_CFG_CANCEL) {
420fc3a2fcaSGanapathi Bhat if (!test_bit(MWIFIEX_IS_HS_CONFIGURED,
421fc3a2fcaSGanapathi Bhat &adapter->work_flags))
422277b024eSKalle Valo /* Already cancelled */
423277b024eSKalle Valo break;
424277b024eSKalle Valo /* Save previous condition */
425277b024eSKalle Valo prev_cond = le32_to_cpu(adapter->hs_cfg
426277b024eSKalle Valo .conditions);
427277b024eSKalle Valo adapter->hs_cfg.conditions =
428277b024eSKalle Valo cpu_to_le32(hs_cfg->conditions);
429277b024eSKalle Valo } else if (hs_cfg->conditions) {
430277b024eSKalle Valo adapter->hs_cfg.conditions =
431277b024eSKalle Valo cpu_to_le32(hs_cfg->conditions);
432277b024eSKalle Valo adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
433277b024eSKalle Valo if (hs_cfg->gap)
434277b024eSKalle Valo adapter->hs_cfg.gap = (u8)hs_cfg->gap;
435277b024eSKalle Valo } else if (adapter->hs_cfg.conditions ==
436277b024eSKalle Valo cpu_to_le32(HS_CFG_CANCEL)) {
437277b024eSKalle Valo /* Return failure if no parameters for HS
438277b024eSKalle Valo enable */
439277b024eSKalle Valo status = -1;
440277b024eSKalle Valo break;
441277b024eSKalle Valo }
442277b024eSKalle Valo
443277b024eSKalle Valo status = mwifiex_send_cmd(priv,
444277b024eSKalle Valo HostCmd_CMD_802_11_HS_CFG_ENH,
445277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0,
446277b024eSKalle Valo &adapter->hs_cfg,
447277b024eSKalle Valo cmd_type == MWIFIEX_SYNC_CMD);
448277b024eSKalle Valo
449277b024eSKalle Valo if (hs_cfg->conditions == HS_CFG_CANCEL)
450277b024eSKalle Valo /* Restore previous condition */
451277b024eSKalle Valo adapter->hs_cfg.conditions =
452277b024eSKalle Valo cpu_to_le32(prev_cond);
453277b024eSKalle Valo } else {
454277b024eSKalle Valo adapter->hs_cfg.conditions =
455277b024eSKalle Valo cpu_to_le32(hs_cfg->conditions);
456277b024eSKalle Valo adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
457277b024eSKalle Valo adapter->hs_cfg.gap = (u8)hs_cfg->gap;
458277b024eSKalle Valo }
459277b024eSKalle Valo break;
460277b024eSKalle Valo case HostCmd_ACT_GEN_GET:
461277b024eSKalle Valo hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
462277b024eSKalle Valo hs_cfg->gpio = adapter->hs_cfg.gpio;
463277b024eSKalle Valo hs_cfg->gap = adapter->hs_cfg.gap;
464277b024eSKalle Valo break;
465277b024eSKalle Valo default:
466277b024eSKalle Valo status = -1;
467277b024eSKalle Valo break;
468277b024eSKalle Valo }
469277b024eSKalle Valo
470277b024eSKalle Valo return status;
471277b024eSKalle Valo }
472277b024eSKalle Valo
473277b024eSKalle Valo /*
474277b024eSKalle Valo * Sends IOCTL request to cancel the existing Host Sleep configuration.
475277b024eSKalle Valo *
476277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
477277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
478277b024eSKalle Valo */
mwifiex_cancel_hs(struct mwifiex_private * priv,int cmd_type)479277b024eSKalle Valo int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
480277b024eSKalle Valo {
481277b024eSKalle Valo struct mwifiex_ds_hs_cfg hscfg;
482277b024eSKalle Valo
483277b024eSKalle Valo hscfg.conditions = HS_CFG_CANCEL;
484277b024eSKalle Valo hscfg.is_invoke_hostcmd = true;
485277b024eSKalle Valo
486277b024eSKalle Valo return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
487277b024eSKalle Valo cmd_type, &hscfg);
488277b024eSKalle Valo }
489277b024eSKalle Valo EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
490277b024eSKalle Valo
491277b024eSKalle Valo /*
492277b024eSKalle Valo * Sends IOCTL request to cancel the existing Host Sleep configuration.
493277b024eSKalle Valo *
494277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
495277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
496277b024eSKalle Valo */
mwifiex_enable_hs(struct mwifiex_adapter * adapter)497277b024eSKalle Valo int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
498277b024eSKalle Valo {
499277b024eSKalle Valo struct mwifiex_ds_hs_cfg hscfg;
500277b024eSKalle Valo struct mwifiex_private *priv;
501277b024eSKalle Valo int i;
502277b024eSKalle Valo
503277b024eSKalle Valo if (disconnect_on_suspend) {
504277b024eSKalle Valo for (i = 0; i < adapter->priv_num; i++) {
505277b024eSKalle Valo priv = adapter->priv[i];
506277b024eSKalle Valo if (priv)
507277b024eSKalle Valo mwifiex_deauthenticate(priv, NULL);
508277b024eSKalle Valo }
509277b024eSKalle Valo }
510277b024eSKalle Valo
5110c9b7f22SXinming Hu priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
5127d7f07d8Schunfan chen
5130c9b7f22SXinming Hu if (priv && priv->sched_scanning) {
5147d7f07d8Schunfan chen #ifdef CONFIG_PM
515a5c92f0bSWei-Ning Huang if (priv->wdev.wiphy->wowlan_config &&
516a5c92f0bSWei-Ning Huang !priv->wdev.wiphy->wowlan_config->nd_config) {
5177d7f07d8Schunfan chen #endif
5187d7f07d8Schunfan chen mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");
5190c9b7f22SXinming Hu mwifiex_stop_bg_scan(priv);
520b34939b9SArend Van Spriel cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0);
5217d7f07d8Schunfan chen #ifdef CONFIG_PM
5227d7f07d8Schunfan chen }
5237d7f07d8Schunfan chen #endif
5240c9b7f22SXinming Hu }
5250c9b7f22SXinming Hu
526277b024eSKalle Valo if (adapter->hs_activated) {
527277b024eSKalle Valo mwifiex_dbg(adapter, CMD,
528277b024eSKalle Valo "cmd: HS Already activated\n");
529277b024eSKalle Valo return true;
530277b024eSKalle Valo }
531277b024eSKalle Valo
532277b024eSKalle Valo adapter->hs_activate_wait_q_woken = false;
533277b024eSKalle Valo
5346a162200SChristophe Jaillet memset(&hscfg, 0, sizeof(hscfg));
535277b024eSKalle Valo hscfg.is_invoke_hostcmd = true;
536277b024eSKalle Valo
537fc3a2fcaSGanapathi Bhat set_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
538277b024eSKalle Valo mwifiex_cancel_all_pending_cmd(adapter);
539277b024eSKalle Valo
540277b024eSKalle Valo if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
541277b024eSKalle Valo MWIFIEX_BSS_ROLE_STA),
542277b024eSKalle Valo HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
543277b024eSKalle Valo &hscfg)) {
544277b024eSKalle Valo mwifiex_dbg(adapter, ERROR,
545277b024eSKalle Valo "IOCTL request HS enable failed\n");
546277b024eSKalle Valo return false;
547277b024eSKalle Valo }
548277b024eSKalle Valo
549277b024eSKalle Valo if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
550277b024eSKalle Valo adapter->hs_activate_wait_q_woken,
551277b024eSKalle Valo (10 * HZ)) <= 0) {
552277b024eSKalle Valo mwifiex_dbg(adapter, ERROR,
553277b024eSKalle Valo "hs_activate_wait_q terminated\n");
554277b024eSKalle Valo return false;
555277b024eSKalle Valo }
556277b024eSKalle Valo
557277b024eSKalle Valo return true;
558277b024eSKalle Valo }
559277b024eSKalle Valo EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
560277b024eSKalle Valo
561277b024eSKalle Valo /*
562277b024eSKalle Valo * IOCTL request handler to get BSS information.
563277b024eSKalle Valo *
564277b024eSKalle Valo * This function collates the information from different driver structures
565277b024eSKalle Valo * to send to the user.
566277b024eSKalle Valo */
mwifiex_get_bss_info(struct mwifiex_private * priv,struct mwifiex_bss_info * info)567277b024eSKalle Valo int mwifiex_get_bss_info(struct mwifiex_private *priv,
568277b024eSKalle Valo struct mwifiex_bss_info *info)
569277b024eSKalle Valo {
570277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
571277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc;
572277b024eSKalle Valo
573277b024eSKalle Valo if (!info)
574277b024eSKalle Valo return -1;
575277b024eSKalle Valo
576277b024eSKalle Valo bss_desc = &priv->curr_bss_params.bss_descriptor;
577277b024eSKalle Valo
578277b024eSKalle Valo info->bss_mode = priv->bss_mode;
579277b024eSKalle Valo
580277b024eSKalle Valo memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));
581277b024eSKalle Valo
582277b024eSKalle Valo memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
583277b024eSKalle Valo
584277b024eSKalle Valo info->bss_chan = bss_desc->channel;
585277b024eSKalle Valo
586277b024eSKalle Valo memcpy(info->country_code, adapter->country_code,
587277b024eSKalle Valo IEEE80211_COUNTRY_STRING_LEN);
588277b024eSKalle Valo
589277b024eSKalle Valo info->media_connected = priv->media_connected;
590277b024eSKalle Valo
591277b024eSKalle Valo info->max_power_level = priv->max_tx_power_level;
592277b024eSKalle Valo info->min_power_level = priv->min_tx_power_level;
593277b024eSKalle Valo
594277b024eSKalle Valo info->adhoc_state = priv->adhoc_state;
595277b024eSKalle Valo
596277b024eSKalle Valo info->bcn_nf_last = priv->bcn_nf_last;
597277b024eSKalle Valo
598277b024eSKalle Valo if (priv->sec_info.wep_enabled)
599277b024eSKalle Valo info->wep_status = true;
600277b024eSKalle Valo else
601277b024eSKalle Valo info->wep_status = false;
602277b024eSKalle Valo
603fc3a2fcaSGanapathi Bhat info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED,
604fc3a2fcaSGanapathi Bhat &adapter->work_flags);
605277b024eSKalle Valo info->is_deep_sleep = adapter->is_deep_sleep;
606277b024eSKalle Valo
607277b024eSKalle Valo return 0;
608277b024eSKalle Valo }
609277b024eSKalle Valo
610277b024eSKalle Valo /*
611277b024eSKalle Valo * The function disables auto deep sleep mode.
612277b024eSKalle Valo */
mwifiex_disable_auto_ds(struct mwifiex_private * priv)613277b024eSKalle Valo int mwifiex_disable_auto_ds(struct mwifiex_private *priv)
614277b024eSKalle Valo {
6159557d9f2SBrian Norris struct mwifiex_ds_auto_ds auto_ds = {
6169557d9f2SBrian Norris .auto_ds = DEEP_SLEEP_OFF,
6179557d9f2SBrian Norris };
618277b024eSKalle Valo
619277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
620277b024eSKalle Valo DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);
621277b024eSKalle Valo }
622277b024eSKalle Valo EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);
623277b024eSKalle Valo
624277b024eSKalle Valo /*
625277b024eSKalle Valo * Sends IOCTL request to get the data rate.
626277b024eSKalle Valo *
627277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
628277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
629277b024eSKalle Valo */
mwifiex_drv_get_data_rate(struct mwifiex_private * priv,u32 * rate)630277b024eSKalle Valo int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)
631277b024eSKalle Valo {
632277b024eSKalle Valo int ret;
633277b024eSKalle Valo
634277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
635277b024eSKalle Valo HostCmd_ACT_GEN_GET, 0, NULL, true);
636277b024eSKalle Valo
637277b024eSKalle Valo if (!ret) {
638277b024eSKalle Valo if (priv->is_data_rate_auto)
639277b024eSKalle Valo *rate = mwifiex_index_to_data_rate(priv, priv->tx_rate,
640277b024eSKalle Valo priv->tx_htinfo);
641277b024eSKalle Valo else
642277b024eSKalle Valo *rate = priv->data_rate;
643277b024eSKalle Valo }
644277b024eSKalle Valo
645277b024eSKalle Valo return ret;
646277b024eSKalle Valo }
647277b024eSKalle Valo
648277b024eSKalle Valo /*
649277b024eSKalle Valo * IOCTL request handler to set tx power configuration.
650277b024eSKalle Valo *
651277b024eSKalle Valo * This function prepares the correct firmware command and
652277b024eSKalle Valo * issues it.
653277b024eSKalle Valo *
654277b024eSKalle Valo * For non-auto power mode, all the following power groups are set -
655277b024eSKalle Valo * - Modulation class HR/DSSS
656277b024eSKalle Valo * - Modulation class OFDM
657277b024eSKalle Valo * - Modulation class HTBW20
658277b024eSKalle Valo * - Modulation class HTBW40
659277b024eSKalle Valo */
mwifiex_set_tx_power(struct mwifiex_private * priv,struct mwifiex_power_cfg * power_cfg)660277b024eSKalle Valo int mwifiex_set_tx_power(struct mwifiex_private *priv,
661277b024eSKalle Valo struct mwifiex_power_cfg *power_cfg)
662277b024eSKalle Valo {
663277b024eSKalle Valo int ret;
664277b024eSKalle Valo struct host_cmd_ds_txpwr_cfg *txp_cfg;
665277b024eSKalle Valo struct mwifiex_types_power_group *pg_tlv;
666277b024eSKalle Valo struct mwifiex_power_group *pg;
667277b024eSKalle Valo u8 *buf;
668277b024eSKalle Valo u16 dbm = 0;
669277b024eSKalle Valo
670277b024eSKalle Valo if (!power_cfg->is_power_auto) {
671277b024eSKalle Valo dbm = (u16) power_cfg->power_level;
672277b024eSKalle Valo if ((dbm < priv->min_tx_power_level) ||
673277b024eSKalle Valo (dbm > priv->max_tx_power_level)) {
674277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
675277b024eSKalle Valo "txpower value %d dBm\t"
676277b024eSKalle Valo "is out of range (%d dBm-%d dBm)\n",
677277b024eSKalle Valo dbm, priv->min_tx_power_level,
678277b024eSKalle Valo priv->max_tx_power_level);
679277b024eSKalle Valo return -1;
680277b024eSKalle Valo }
681277b024eSKalle Valo }
682277b024eSKalle Valo buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
683277b024eSKalle Valo if (!buf)
684277b024eSKalle Valo return -ENOMEM;
685277b024eSKalle Valo
686277b024eSKalle Valo txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
687277b024eSKalle Valo txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
688277b024eSKalle Valo if (!power_cfg->is_power_auto) {
68965a576e2SAdrian Bunk u16 dbm_min = power_cfg->is_power_fixed ?
69065a576e2SAdrian Bunk dbm : priv->min_tx_power_level;
69165a576e2SAdrian Bunk
692277b024eSKalle Valo txp_cfg->mode = cpu_to_le32(1);
693277b024eSKalle Valo pg_tlv = (struct mwifiex_types_power_group *)
694277b024eSKalle Valo (buf + sizeof(struct host_cmd_ds_txpwr_cfg));
695277b024eSKalle Valo pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);
696277b024eSKalle Valo pg_tlv->length =
697277b024eSKalle Valo cpu_to_le16(4 * sizeof(struct mwifiex_power_group));
698277b024eSKalle Valo pg = (struct mwifiex_power_group *)
699277b024eSKalle Valo (buf + sizeof(struct host_cmd_ds_txpwr_cfg)
700277b024eSKalle Valo + sizeof(struct mwifiex_types_power_group));
701277b024eSKalle Valo /* Power group for modulation class HR/DSSS */
702277b024eSKalle Valo pg->first_rate_code = 0x00;
703277b024eSKalle Valo pg->last_rate_code = 0x03;
704277b024eSKalle Valo pg->modulation_class = MOD_CLASS_HR_DSSS;
705277b024eSKalle Valo pg->power_step = 0;
70665a576e2SAdrian Bunk pg->power_min = (s8) dbm_min;
707277b024eSKalle Valo pg->power_max = (s8) dbm;
708277b024eSKalle Valo pg++;
709277b024eSKalle Valo /* Power group for modulation class OFDM */
710277b024eSKalle Valo pg->first_rate_code = 0x00;
711277b024eSKalle Valo pg->last_rate_code = 0x07;
712277b024eSKalle Valo pg->modulation_class = MOD_CLASS_OFDM;
713277b024eSKalle Valo pg->power_step = 0;
71465a576e2SAdrian Bunk pg->power_min = (s8) dbm_min;
715277b024eSKalle Valo pg->power_max = (s8) dbm;
716277b024eSKalle Valo pg++;
717277b024eSKalle Valo /* Power group for modulation class HTBW20 */
718277b024eSKalle Valo pg->first_rate_code = 0x00;
719277b024eSKalle Valo pg->last_rate_code = 0x20;
720277b024eSKalle Valo pg->modulation_class = MOD_CLASS_HT;
721277b024eSKalle Valo pg->power_step = 0;
72265a576e2SAdrian Bunk pg->power_min = (s8) dbm_min;
723277b024eSKalle Valo pg->power_max = (s8) dbm;
724277b024eSKalle Valo pg->ht_bandwidth = HT_BW_20;
725277b024eSKalle Valo pg++;
726277b024eSKalle Valo /* Power group for modulation class HTBW40 */
727277b024eSKalle Valo pg->first_rate_code = 0x00;
728277b024eSKalle Valo pg->last_rate_code = 0x20;
729277b024eSKalle Valo pg->modulation_class = MOD_CLASS_HT;
730277b024eSKalle Valo pg->power_step = 0;
73165a576e2SAdrian Bunk pg->power_min = (s8) dbm_min;
732277b024eSKalle Valo pg->power_max = (s8) dbm;
733277b024eSKalle Valo pg->ht_bandwidth = HT_BW_40;
734277b024eSKalle Valo }
735277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,
736277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, buf, true);
737277b024eSKalle Valo
738277b024eSKalle Valo kfree(buf);
739277b024eSKalle Valo return ret;
740277b024eSKalle Valo }
741277b024eSKalle Valo
742277b024eSKalle Valo /*
743277b024eSKalle Valo * IOCTL request handler to get power save mode.
744277b024eSKalle Valo *
745277b024eSKalle Valo * This function prepares the correct firmware command and
746277b024eSKalle Valo * issues it.
747277b024eSKalle Valo */
mwifiex_drv_set_power(struct mwifiex_private * priv,u32 * ps_mode)748277b024eSKalle Valo int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
749277b024eSKalle Valo {
750277b024eSKalle Valo int ret;
751277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
752277b024eSKalle Valo u16 sub_cmd;
753277b024eSKalle Valo
754277b024eSKalle Valo if (*ps_mode)
755277b024eSKalle Valo adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
756277b024eSKalle Valo else
757277b024eSKalle Valo adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
758277b024eSKalle Valo sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
759277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
760277b024eSKalle Valo sub_cmd, BITMAP_STA_PS, NULL, true);
761277b024eSKalle Valo if ((!ret) && (sub_cmd == DIS_AUTO_PS))
762277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
763277b024eSKalle Valo GET_PS, 0, NULL, false);
764277b024eSKalle Valo
765277b024eSKalle Valo return ret;
766277b024eSKalle Valo }
767277b024eSKalle Valo
768277b024eSKalle Valo /*
769277b024eSKalle Valo * IOCTL request handler to set/reset WPA IE.
770277b024eSKalle Valo *
771277b024eSKalle Valo * The supplied WPA IE is treated as a opaque buffer. Only the first field
772277b024eSKalle Valo * is checked to determine WPA version. If buffer length is zero, the existing
773277b024eSKalle Valo * WPA IE is reset.
774277b024eSKalle Valo */
mwifiex_set_wpa_ie(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)7759ddb378bSXinming Hu static int mwifiex_set_wpa_ie(struct mwifiex_private *priv,
776277b024eSKalle Valo u8 *ie_data_ptr, u16 ie_len)
777277b024eSKalle Valo {
778277b024eSKalle Valo if (ie_len) {
779277b024eSKalle Valo if (ie_len > sizeof(priv->wpa_ie)) {
780277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
781277b024eSKalle Valo "failed to copy WPA IE, too big\n");
782277b024eSKalle Valo return -1;
783277b024eSKalle Valo }
784277b024eSKalle Valo memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
7851d8f5c13Schunfan chen priv->wpa_ie_len = ie_len;
786277b024eSKalle Valo mwifiex_dbg(priv->adapter, CMD,
787277b024eSKalle Valo "cmd: Set Wpa_ie_len=%d IE=%#x\n",
788277b024eSKalle Valo priv->wpa_ie_len, priv->wpa_ie[0]);
789277b024eSKalle Valo
790277b024eSKalle Valo if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
791277b024eSKalle Valo priv->sec_info.wpa_enabled = true;
792277b024eSKalle Valo } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
793277b024eSKalle Valo priv->sec_info.wpa2_enabled = true;
794277b024eSKalle Valo } else {
795277b024eSKalle Valo priv->sec_info.wpa_enabled = false;
796277b024eSKalle Valo priv->sec_info.wpa2_enabled = false;
797277b024eSKalle Valo }
798277b024eSKalle Valo } else {
799277b024eSKalle Valo memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
800277b024eSKalle Valo priv->wpa_ie_len = 0;
801277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
802277b024eSKalle Valo "info: reset wpa_ie_len=%d IE=%#x\n",
803277b024eSKalle Valo priv->wpa_ie_len, priv->wpa_ie[0]);
804277b024eSKalle Valo priv->sec_info.wpa_enabled = false;
805277b024eSKalle Valo priv->sec_info.wpa2_enabled = false;
806277b024eSKalle Valo }
807277b024eSKalle Valo
808277b024eSKalle Valo return 0;
809277b024eSKalle Valo }
810277b024eSKalle Valo
811277b024eSKalle Valo /*
812277b024eSKalle Valo * IOCTL request handler to set/reset WAPI IE.
813277b024eSKalle Valo *
814277b024eSKalle Valo * The supplied WAPI IE is treated as a opaque buffer. Only the first field
815277b024eSKalle Valo * is checked to internally enable WAPI. If buffer length is zero, the existing
816277b024eSKalle Valo * WAPI IE is reset.
817277b024eSKalle Valo */
mwifiex_set_wapi_ie(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)818277b024eSKalle Valo static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
819277b024eSKalle Valo u8 *ie_data_ptr, u16 ie_len)
820277b024eSKalle Valo {
821277b024eSKalle Valo if (ie_len) {
822277b024eSKalle Valo if (ie_len > sizeof(priv->wapi_ie)) {
823277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
824277b024eSKalle Valo "info: failed to copy WAPI IE, too big\n");
825277b024eSKalle Valo return -1;
826277b024eSKalle Valo }
827277b024eSKalle Valo memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
828277b024eSKalle Valo priv->wapi_ie_len = ie_len;
829277b024eSKalle Valo mwifiex_dbg(priv->adapter, CMD,
830277b024eSKalle Valo "cmd: Set wapi_ie_len=%d IE=%#x\n",
831277b024eSKalle Valo priv->wapi_ie_len, priv->wapi_ie[0]);
832277b024eSKalle Valo
833277b024eSKalle Valo if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
834277b024eSKalle Valo priv->sec_info.wapi_enabled = true;
835277b024eSKalle Valo } else {
836277b024eSKalle Valo memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
837277b024eSKalle Valo priv->wapi_ie_len = ie_len;
838277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
839277b024eSKalle Valo "info: Reset wapi_ie_len=%d IE=%#x\n",
840277b024eSKalle Valo priv->wapi_ie_len, priv->wapi_ie[0]);
841277b024eSKalle Valo priv->sec_info.wapi_enabled = false;
842277b024eSKalle Valo }
843277b024eSKalle Valo return 0;
844277b024eSKalle Valo }
845277b024eSKalle Valo
846277b024eSKalle Valo /*
847277b024eSKalle Valo * IOCTL request handler to set/reset WPS IE.
848277b024eSKalle Valo *
849277b024eSKalle Valo * The supplied WPS IE is treated as a opaque buffer. Only the first field
850277b024eSKalle Valo * is checked to internally enable WPS. If buffer length is zero, the existing
851277b024eSKalle Valo * WPS IE is reset.
852277b024eSKalle Valo */
mwifiex_set_wps_ie(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)853277b024eSKalle Valo static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
854277b024eSKalle Valo u8 *ie_data_ptr, u16 ie_len)
855277b024eSKalle Valo {
856277b024eSKalle Valo if (ie_len) {
857277b024eSKalle Valo if (ie_len > MWIFIEX_MAX_VSIE_LEN) {
858277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
859277b024eSKalle Valo "info: failed to copy WPS IE, too big\n");
860277b024eSKalle Valo return -1;
861277b024eSKalle Valo }
862277b024eSKalle Valo
863277b024eSKalle Valo priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
864277b024eSKalle Valo if (!priv->wps_ie)
865277b024eSKalle Valo return -ENOMEM;
866277b024eSKalle Valo
867277b024eSKalle Valo memcpy(priv->wps_ie, ie_data_ptr, ie_len);
868277b024eSKalle Valo priv->wps_ie_len = ie_len;
869277b024eSKalle Valo mwifiex_dbg(priv->adapter, CMD,
870277b024eSKalle Valo "cmd: Set wps_ie_len=%d IE=%#x\n",
871277b024eSKalle Valo priv->wps_ie_len, priv->wps_ie[0]);
872277b024eSKalle Valo } else {
873277b024eSKalle Valo kfree(priv->wps_ie);
874277b024eSKalle Valo priv->wps_ie_len = ie_len;
875277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO,
876277b024eSKalle Valo "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
877277b024eSKalle Valo }
878277b024eSKalle Valo return 0;
879277b024eSKalle Valo }
880277b024eSKalle Valo
881277b024eSKalle Valo /*
882277b024eSKalle Valo * IOCTL request handler to set WAPI key.
883277b024eSKalle Valo *
884277b024eSKalle Valo * This function prepares the correct firmware command and
885277b024eSKalle Valo * issues it.
886277b024eSKalle Valo */
mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)887277b024eSKalle Valo static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
888277b024eSKalle Valo struct mwifiex_ds_encrypt_key *encrypt_key)
889277b024eSKalle Valo {
890277b024eSKalle Valo
891277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
892277b024eSKalle Valo HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
893277b024eSKalle Valo encrypt_key, true);
894277b024eSKalle Valo }
895277b024eSKalle Valo
896277b024eSKalle Valo /*
897277b024eSKalle Valo * IOCTL request handler to set WEP network key.
898277b024eSKalle Valo *
899277b024eSKalle Valo * This function prepares the correct firmware command and
900277b024eSKalle Valo * issues it, after validation checks.
901277b024eSKalle Valo */
mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)902277b024eSKalle Valo static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
903277b024eSKalle Valo struct mwifiex_ds_encrypt_key *encrypt_key)
904277b024eSKalle Valo {
905277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
906277b024eSKalle Valo int ret;
907277b024eSKalle Valo struct mwifiex_wep_key *wep_key;
908277b024eSKalle Valo int index;
909277b024eSKalle Valo
910277b024eSKalle Valo if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
911277b024eSKalle Valo priv->wep_key_curr_index = 0;
912277b024eSKalle Valo wep_key = &priv->wep_key[priv->wep_key_curr_index];
913277b024eSKalle Valo index = encrypt_key->key_index;
914277b024eSKalle Valo if (encrypt_key->key_disable) {
915277b024eSKalle Valo priv->sec_info.wep_enabled = 0;
916277b024eSKalle Valo } else if (!encrypt_key->key_len) {
917277b024eSKalle Valo /* Copy the required key as the current key */
918277b024eSKalle Valo wep_key = &priv->wep_key[index];
919277b024eSKalle Valo if (!wep_key->key_length) {
920277b024eSKalle Valo mwifiex_dbg(adapter, ERROR,
921277b024eSKalle Valo "key not set, so cannot enable it\n");
922277b024eSKalle Valo return -1;
923277b024eSKalle Valo }
924277b024eSKalle Valo
925277b024eSKalle Valo if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
926277b024eSKalle Valo memcpy(encrypt_key->key_material,
927277b024eSKalle Valo wep_key->key_material, wep_key->key_length);
928277b024eSKalle Valo encrypt_key->key_len = wep_key->key_length;
929277b024eSKalle Valo }
930277b024eSKalle Valo
931277b024eSKalle Valo priv->wep_key_curr_index = (u16) index;
932277b024eSKalle Valo priv->sec_info.wep_enabled = 1;
933277b024eSKalle Valo } else {
934277b024eSKalle Valo wep_key = &priv->wep_key[index];
935277b024eSKalle Valo memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
936277b024eSKalle Valo /* Copy the key in the driver */
937277b024eSKalle Valo memcpy(wep_key->key_material,
938277b024eSKalle Valo encrypt_key->key_material,
939277b024eSKalle Valo encrypt_key->key_len);
940277b024eSKalle Valo wep_key->key_index = index;
941277b024eSKalle Valo wep_key->key_length = encrypt_key->key_len;
942277b024eSKalle Valo priv->sec_info.wep_enabled = 1;
943277b024eSKalle Valo }
944277b024eSKalle Valo if (wep_key->key_length) {
945277b024eSKalle Valo void *enc_key;
946277b024eSKalle Valo
947277b024eSKalle Valo if (encrypt_key->key_disable) {
948277b024eSKalle Valo memset(&priv->wep_key[index], 0,
949277b024eSKalle Valo sizeof(struct mwifiex_wep_key));
950277b024eSKalle Valo goto done;
951277b024eSKalle Valo }
952277b024eSKalle Valo
953277b024eSKalle Valo if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
954277b024eSKalle Valo enc_key = encrypt_key;
955277b024eSKalle Valo else
956277b024eSKalle Valo enc_key = NULL;
957277b024eSKalle Valo
958277b024eSKalle Valo /* Send request to firmware */
959277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
960277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, enc_key, false);
961277b024eSKalle Valo if (ret)
962277b024eSKalle Valo return ret;
963277b024eSKalle Valo }
964277b024eSKalle Valo
965277b024eSKalle Valo done:
966277b024eSKalle Valo if (priv->sec_info.wep_enabled)
967277b024eSKalle Valo priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
968277b024eSKalle Valo else
969277b024eSKalle Valo priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
970277b024eSKalle Valo
971277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
972277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0,
973277b024eSKalle Valo &priv->curr_pkt_filter, true);
974277b024eSKalle Valo
975277b024eSKalle Valo return ret;
976277b024eSKalle Valo }
977277b024eSKalle Valo
978277b024eSKalle Valo /*
979277b024eSKalle Valo * IOCTL request handler to set WPA key.
980277b024eSKalle Valo *
981277b024eSKalle Valo * This function prepares the correct firmware command and
982277b024eSKalle Valo * issues it, after validation checks.
983277b024eSKalle Valo *
984277b024eSKalle Valo * Current driver only supports key length of up to 32 bytes.
985277b024eSKalle Valo *
986277b024eSKalle Valo * This function can also be used to disable a currently set key.
987277b024eSKalle Valo */
mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)988277b024eSKalle Valo static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
989277b024eSKalle Valo struct mwifiex_ds_encrypt_key *encrypt_key)
990277b024eSKalle Valo {
991277b024eSKalle Valo int ret;
992277b024eSKalle Valo u8 remove_key = false;
993277b024eSKalle Valo struct host_cmd_ds_802_11_key_material *ibss_key;
994277b024eSKalle Valo
995277b024eSKalle Valo /* Current driver only supports key length of up to 32 bytes */
996277b024eSKalle Valo if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
997277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
998277b024eSKalle Valo "key length too long\n");
999277b024eSKalle Valo return -1;
1000277b024eSKalle Valo }
1001277b024eSKalle Valo
1002277b024eSKalle Valo if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
1003277b024eSKalle Valo /*
1004277b024eSKalle Valo * IBSS/WPA-None uses only one key (Group) for both receiving
1005277b024eSKalle Valo * and sending unicast and multicast packets.
1006277b024eSKalle Valo */
1007277b024eSKalle Valo /* Send the key as PTK to firmware */
1008277b024eSKalle Valo encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1009277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1010277b024eSKalle Valo HostCmd_ACT_GEN_SET,
1011277b024eSKalle Valo KEY_INFO_ENABLED, encrypt_key, false);
1012277b024eSKalle Valo if (ret)
1013277b024eSKalle Valo return ret;
1014277b024eSKalle Valo
1015277b024eSKalle Valo ibss_key = &priv->aes_key;
1016277b024eSKalle Valo memset(ibss_key, 0,
1017277b024eSKalle Valo sizeof(struct host_cmd_ds_802_11_key_material));
1018277b024eSKalle Valo /* Copy the key in the driver */
1019277b024eSKalle Valo memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
1020277b024eSKalle Valo encrypt_key->key_len);
1021277b024eSKalle Valo memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
1022277b024eSKalle Valo sizeof(ibss_key->key_param_set.key_len));
1023277b024eSKalle Valo ibss_key->key_param_set.key_type_id
1024277b024eSKalle Valo = cpu_to_le16(KEY_TYPE_ID_TKIP);
1025277b024eSKalle Valo ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);
1026277b024eSKalle Valo
1027277b024eSKalle Valo /* Send the key as GTK to firmware */
1028277b024eSKalle Valo encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
1029277b024eSKalle Valo }
1030277b024eSKalle Valo
1031277b024eSKalle Valo if (!encrypt_key->key_index)
1032277b024eSKalle Valo encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1033277b024eSKalle Valo
1034277b024eSKalle Valo if (remove_key)
1035277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1036277b024eSKalle Valo HostCmd_ACT_GEN_SET,
1037277b024eSKalle Valo !KEY_INFO_ENABLED, encrypt_key, true);
1038277b024eSKalle Valo else
1039277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1040277b024eSKalle Valo HostCmd_ACT_GEN_SET,
1041277b024eSKalle Valo KEY_INFO_ENABLED, encrypt_key, true);
1042277b024eSKalle Valo
1043277b024eSKalle Valo return ret;
1044277b024eSKalle Valo }
1045277b024eSKalle Valo
1046277b024eSKalle Valo /*
1047277b024eSKalle Valo * IOCTL request handler to set/get network keys.
1048277b024eSKalle Valo *
1049277b024eSKalle Valo * This is a generic key handling function which supports WEP, WPA
1050277b024eSKalle Valo * and WAPI.
1051277b024eSKalle Valo */
1052277b024eSKalle Valo static int
mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private * priv,struct mwifiex_ds_encrypt_key * encrypt_key)1053277b024eSKalle Valo mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
1054277b024eSKalle Valo struct mwifiex_ds_encrypt_key *encrypt_key)
1055277b024eSKalle Valo {
1056277b024eSKalle Valo int status;
1057277b024eSKalle Valo
1058277b024eSKalle Valo if (encrypt_key->is_wapi_key)
1059277b024eSKalle Valo status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
1060277b024eSKalle Valo else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
1061277b024eSKalle Valo status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);
1062277b024eSKalle Valo else
1063277b024eSKalle Valo status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);
1064277b024eSKalle Valo return status;
1065277b024eSKalle Valo }
1066277b024eSKalle Valo
1067277b024eSKalle Valo /*
1068277b024eSKalle Valo * This function returns the driver version.
1069277b024eSKalle Valo */
1070277b024eSKalle Valo int
mwifiex_drv_get_driver_version(struct mwifiex_adapter * adapter,char * version,int max_len)1071277b024eSKalle Valo mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
1072277b024eSKalle Valo int max_len)
1073277b024eSKalle Valo {
1074277b024eSKalle Valo union {
1075277b024eSKalle Valo __le32 l;
1076277b024eSKalle Valo u8 c[4];
1077277b024eSKalle Valo } ver;
1078277b024eSKalle Valo char fw_ver[32];
1079277b024eSKalle Valo
1080277b024eSKalle Valo ver.l = cpu_to_le32(adapter->fw_release_number);
1081277b024eSKalle Valo sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
1082277b024eSKalle Valo
1083277b024eSKalle Valo snprintf(version, max_len, driver_version, fw_ver);
1084277b024eSKalle Valo
1085277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);
1086277b024eSKalle Valo
1087277b024eSKalle Valo return 0;
1088277b024eSKalle Valo }
1089277b024eSKalle Valo
1090277b024eSKalle Valo /*
1091277b024eSKalle Valo * Sends IOCTL request to set encoding parameters.
1092277b024eSKalle Valo *
1093277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1094277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1095277b024eSKalle Valo */
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)1096277b024eSKalle Valo int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
1097277b024eSKalle Valo const u8 *key, int key_len, u8 key_index,
1098277b024eSKalle Valo const u8 *mac_addr, int disable)
1099277b024eSKalle Valo {
1100277b024eSKalle Valo struct mwifiex_ds_encrypt_key encrypt_key;
1101277b024eSKalle Valo
11026a162200SChristophe Jaillet memset(&encrypt_key, 0, sizeof(encrypt_key));
1103277b024eSKalle Valo encrypt_key.key_len = key_len;
1104277b024eSKalle Valo encrypt_key.key_index = key_index;
1105277b024eSKalle Valo
1106277b024eSKalle Valo if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
1107277b024eSKalle Valo encrypt_key.is_igtk_key = true;
1108277b024eSKalle Valo
1109277b024eSKalle Valo if (!disable) {
1110277b024eSKalle Valo if (key_len)
1111277b024eSKalle Valo memcpy(encrypt_key.key_material, key, key_len);
1112277b024eSKalle Valo else
1113277b024eSKalle Valo encrypt_key.is_current_wep_key = true;
1114277b024eSKalle Valo
1115277b024eSKalle Valo if (mac_addr)
1116277b024eSKalle Valo memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
1117277b024eSKalle Valo if (kp && kp->seq && kp->seq_len) {
1118277b024eSKalle Valo memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
1119277b024eSKalle Valo encrypt_key.pn_len = kp->seq_len;
1120277b024eSKalle Valo encrypt_key.is_rx_seq_valid = true;
1121277b024eSKalle Valo }
1122277b024eSKalle Valo } else {
1123277b024eSKalle Valo encrypt_key.key_disable = true;
1124277b024eSKalle Valo if (mac_addr)
1125277b024eSKalle Valo memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
1126277b024eSKalle Valo }
1127277b024eSKalle Valo
1128277b024eSKalle Valo return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
1129277b024eSKalle Valo }
1130277b024eSKalle Valo
1131277b024eSKalle Valo /*
1132277b024eSKalle Valo * Sends IOCTL request to get extended version.
1133277b024eSKalle Valo *
1134277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1135277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1136277b024eSKalle Valo */
1137277b024eSKalle Valo int
mwifiex_get_ver_ext(struct mwifiex_private * priv,u32 version_str_sel)113817934b6aSXinming Hu mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)
1139277b024eSKalle Valo {
1140277b024eSKalle Valo struct mwifiex_ver_ext ver_ext;
1141277b024eSKalle Valo
1142ba852018SChristophe Jaillet memset(&ver_ext, 0, sizeof(ver_ext));
114317934b6aSXinming Hu ver_ext.version_str_sel = version_str_sel;
1144277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
1145277b024eSKalle Valo HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
1146277b024eSKalle Valo return -1;
1147277b024eSKalle Valo
1148277b024eSKalle Valo return 0;
1149277b024eSKalle Valo }
1150277b024eSKalle Valo
1151277b024eSKalle Valo int
mwifiex_remain_on_chan_cfg(struct mwifiex_private * priv,u16 action,struct ieee80211_channel * chan,unsigned int duration)1152277b024eSKalle Valo mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
1153277b024eSKalle Valo struct ieee80211_channel *chan,
1154277b024eSKalle Valo unsigned int duration)
1155277b024eSKalle Valo {
1156277b024eSKalle Valo struct host_cmd_ds_remain_on_chan roc_cfg;
1157277b024eSKalle Valo u8 sc;
1158277b024eSKalle Valo
1159277b024eSKalle Valo memset(&roc_cfg, 0, sizeof(roc_cfg));
1160277b024eSKalle Valo roc_cfg.action = cpu_to_le16(action);
1161277b024eSKalle Valo if (action == HostCmd_ACT_GEN_SET) {
1162277b024eSKalle Valo roc_cfg.band_cfg = chan->band;
1163277b024eSKalle Valo sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);
1164277b024eSKalle Valo roc_cfg.band_cfg |= (sc << 2);
1165277b024eSKalle Valo
1166277b024eSKalle Valo roc_cfg.channel =
1167277b024eSKalle Valo ieee80211_frequency_to_channel(chan->center_freq);
1168277b024eSKalle Valo roc_cfg.duration = cpu_to_le32(duration);
1169277b024eSKalle Valo }
1170277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
1171277b024eSKalle Valo action, 0, &roc_cfg, true)) {
1172277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
1173277b024eSKalle Valo "failed to remain on channel\n");
1174277b024eSKalle Valo return -1;
1175277b024eSKalle Valo }
1176277b024eSKalle Valo
1177277b024eSKalle Valo return roc_cfg.status;
1178277b024eSKalle Valo }
1179277b024eSKalle Valo
1180277b024eSKalle Valo /*
1181277b024eSKalle Valo * Sends IOCTL request to get statistics information.
1182277b024eSKalle Valo *
1183277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1184277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1185277b024eSKalle Valo */
1186277b024eSKalle Valo int
mwifiex_get_stats_info(struct mwifiex_private * priv,struct mwifiex_ds_get_stats * log)1187277b024eSKalle Valo mwifiex_get_stats_info(struct mwifiex_private *priv,
1188277b024eSKalle Valo struct mwifiex_ds_get_stats *log)
1189277b024eSKalle Valo {
1190277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
1191277b024eSKalle Valo HostCmd_ACT_GEN_GET, 0, log, true);
1192277b024eSKalle Valo }
1193277b024eSKalle Valo
1194277b024eSKalle Valo /*
1195277b024eSKalle Valo * IOCTL request handler to read/write register.
1196277b024eSKalle Valo *
1197277b024eSKalle Valo * This function prepares the correct firmware command and
1198277b024eSKalle Valo * issues it.
1199277b024eSKalle Valo *
1200277b024eSKalle Valo * Access to the following registers are supported -
1201277b024eSKalle Valo * - MAC
1202277b024eSKalle Valo * - BBP
1203277b024eSKalle Valo * - RF
1204277b024eSKalle Valo * - PMIC
1205277b024eSKalle Valo * - CAU
1206277b024eSKalle Valo */
mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private * priv,struct mwifiex_ds_reg_rw * reg_rw,u16 action)1207277b024eSKalle Valo static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
1208277b024eSKalle Valo struct mwifiex_ds_reg_rw *reg_rw,
1209277b024eSKalle Valo u16 action)
1210277b024eSKalle Valo {
1211277b024eSKalle Valo u16 cmd_no;
1212277b024eSKalle Valo
12138cfb8600SPrasun Maiti switch (reg_rw->type) {
1214277b024eSKalle Valo case MWIFIEX_REG_MAC:
1215277b024eSKalle Valo cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
1216277b024eSKalle Valo break;
1217277b024eSKalle Valo case MWIFIEX_REG_BBP:
1218277b024eSKalle Valo cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
1219277b024eSKalle Valo break;
1220277b024eSKalle Valo case MWIFIEX_REG_RF:
1221277b024eSKalle Valo cmd_no = HostCmd_CMD_RF_REG_ACCESS;
1222277b024eSKalle Valo break;
1223277b024eSKalle Valo case MWIFIEX_REG_PMIC:
1224277b024eSKalle Valo cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
1225277b024eSKalle Valo break;
1226277b024eSKalle Valo case MWIFIEX_REG_CAU:
1227277b024eSKalle Valo cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
1228277b024eSKalle Valo break;
1229277b024eSKalle Valo default:
1230277b024eSKalle Valo return -1;
1231277b024eSKalle Valo }
1232277b024eSKalle Valo
1233277b024eSKalle Valo return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);
1234277b024eSKalle Valo }
1235277b024eSKalle Valo
1236277b024eSKalle Valo /*
1237277b024eSKalle Valo * Sends IOCTL request to write to a register.
1238277b024eSKalle Valo *
1239277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1240277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1241277b024eSKalle Valo */
1242277b024eSKalle Valo int
mwifiex_reg_write(struct mwifiex_private * priv,u32 reg_type,u32 reg_offset,u32 reg_value)1243277b024eSKalle Valo mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
1244277b024eSKalle Valo u32 reg_offset, u32 reg_value)
1245277b024eSKalle Valo {
1246277b024eSKalle Valo struct mwifiex_ds_reg_rw reg_rw;
1247277b024eSKalle Valo
12488cfb8600SPrasun Maiti reg_rw.type = reg_type;
12498cfb8600SPrasun Maiti reg_rw.offset = reg_offset;
12508cfb8600SPrasun Maiti reg_rw.value = reg_value;
1251277b024eSKalle Valo
1252277b024eSKalle Valo return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET);
1253277b024eSKalle Valo }
1254277b024eSKalle Valo
1255277b024eSKalle Valo /*
1256277b024eSKalle Valo * Sends IOCTL request to read from a register.
1257277b024eSKalle Valo *
1258277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1259277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1260277b024eSKalle Valo */
1261277b024eSKalle Valo int
mwifiex_reg_read(struct mwifiex_private * priv,u32 reg_type,u32 reg_offset,u32 * value)1262277b024eSKalle Valo mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
1263277b024eSKalle Valo u32 reg_offset, u32 *value)
1264277b024eSKalle Valo {
1265277b024eSKalle Valo int ret;
1266277b024eSKalle Valo struct mwifiex_ds_reg_rw reg_rw;
1267277b024eSKalle Valo
12688cfb8600SPrasun Maiti reg_rw.type = reg_type;
12698cfb8600SPrasun Maiti reg_rw.offset = reg_offset;
1270277b024eSKalle Valo ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET);
1271277b024eSKalle Valo
1272277b024eSKalle Valo if (ret)
1273277b024eSKalle Valo goto done;
1274277b024eSKalle Valo
12758cfb8600SPrasun Maiti *value = reg_rw.value;
1276277b024eSKalle Valo
1277277b024eSKalle Valo done:
1278277b024eSKalle Valo return ret;
1279277b024eSKalle Valo }
1280277b024eSKalle Valo
1281277b024eSKalle Valo /*
1282277b024eSKalle Valo * Sends IOCTL request to read from EEPROM.
1283277b024eSKalle Valo *
1284277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1285277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1286277b024eSKalle Valo */
1287277b024eSKalle Valo int
mwifiex_eeprom_read(struct mwifiex_private * priv,u16 offset,u16 bytes,u8 * value)1288277b024eSKalle Valo mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
1289277b024eSKalle Valo u8 *value)
1290277b024eSKalle Valo {
1291277b024eSKalle Valo int ret;
1292277b024eSKalle Valo struct mwifiex_ds_read_eeprom rd_eeprom;
1293277b024eSKalle Valo
12948cfb8600SPrasun Maiti rd_eeprom.offset = offset;
12958cfb8600SPrasun Maiti rd_eeprom.byte_count = bytes;
1296277b024eSKalle Valo
1297277b024eSKalle Valo /* Send request to firmware */
1298277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
1299277b024eSKalle Valo HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);
1300277b024eSKalle Valo
1301277b024eSKalle Valo if (!ret)
13028cfb8600SPrasun Maiti memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA,
13038cfb8600SPrasun Maiti rd_eeprom.byte_count));
1304277b024eSKalle Valo return ret;
1305277b024eSKalle Valo }
1306277b024eSKalle Valo
1307277b024eSKalle Valo /*
1308277b024eSKalle Valo * This function sets a generic IE. In addition to generic IE, it can
1309277b024eSKalle Valo * also handle WPA, WPA2 and WAPI IEs.
1310277b024eSKalle Valo */
1311277b024eSKalle Valo static int
mwifiex_set_gen_ie_helper(struct mwifiex_private * priv,u8 * ie_data_ptr,u16 ie_len)1312277b024eSKalle Valo mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
1313277b024eSKalle Valo u16 ie_len)
1314277b024eSKalle Valo {
1315277b024eSKalle Valo struct ieee_types_vendor_header *pvendor_ie;
1316da2c9cedSColin Ian King static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
1317da2c9cedSColin Ian King static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
13189ddb378bSXinming Hu u16 unparsed_len = ie_len, cur_ie_len;
1319277b024eSKalle Valo
1320277b024eSKalle Valo /* If the passed length is zero, reset the buffer */
1321277b024eSKalle Valo if (!ie_len) {
1322277b024eSKalle Valo priv->gen_ie_buf_len = 0;
1323277b024eSKalle Valo priv->wps.session_enable = false;
1324277b024eSKalle Valo return 0;
13259ddb378bSXinming Hu } else if (!ie_data_ptr ||
13269ddb378bSXinming Hu ie_len <= sizeof(struct ieee_types_header)) {
1327277b024eSKalle Valo return -1;
1328277b024eSKalle Valo }
1329277b024eSKalle Valo pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
1330277b024eSKalle Valo
133184a38fb3Schunfan chen while (pvendor_ie) {
13329ddb378bSXinming Hu cur_ie_len = pvendor_ie->len + sizeof(struct ieee_types_header);
133384a38fb3Schunfan chen
133484a38fb3Schunfan chen if (pvendor_ie->element_id == WLAN_EID_RSN) {
13359ddb378bSXinming Hu /* IE is a WPA/WPA2 IE so call set_wpa function */
13369ddb378bSXinming Hu mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len);
13379ddb378bSXinming Hu priv->wps.session_enable = false;
13389ddb378bSXinming Hu goto next_ie;
133984a38fb3Schunfan chen }
134084a38fb3Schunfan chen
134184a38fb3Schunfan chen if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
1342277b024eSKalle Valo /* IE is a WAPI IE so call set_wapi function */
13439ddb378bSXinming Hu mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie,
13449ddb378bSXinming Hu cur_ie_len);
13459ddb378bSXinming Hu goto next_ie;
1346277b024eSKalle Valo }
134784a38fb3Schunfan chen
13489ddb378bSXinming Hu if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) {
13499ddb378bSXinming Hu /* Test to see if it is a WPA IE, if not, then
13509ddb378bSXinming Hu * it is a gen IE
13519ddb378bSXinming Hu */
135263d7ef36SBrian Norris if (!memcmp(&pvendor_ie->oui, wpa_oui,
13539ddb378bSXinming Hu sizeof(wpa_oui))) {
13549ddb378bSXinming Hu /* IE is a WPA/WPA2 IE so call set_wpa function
13559ddb378bSXinming Hu */
13569ddb378bSXinming Hu mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie,
13579ddb378bSXinming Hu cur_ie_len);
13589ddb378bSXinming Hu priv->wps.session_enable = false;
13599ddb378bSXinming Hu goto next_ie;
13609ddb378bSXinming Hu }
13619ddb378bSXinming Hu
136263d7ef36SBrian Norris if (!memcmp(&pvendor_ie->oui, wps_oui,
13639ddb378bSXinming Hu sizeof(wps_oui))) {
13649ddb378bSXinming Hu /* Test to see if it is a WPS IE,
13659ddb378bSXinming Hu * if so, enable wps session flag
13669ddb378bSXinming Hu */
13679ddb378bSXinming Hu priv->wps.session_enable = true;
13689ddb378bSXinming Hu mwifiex_dbg(priv->adapter, MSG,
13699ddb378bSXinming Hu "WPS Session Enabled.\n");
13709ddb378bSXinming Hu mwifiex_set_wps_ie(priv, (u8 *)pvendor_ie,
13719ddb378bSXinming Hu cur_ie_len);
13729ddb378bSXinming Hu goto next_ie;
13739ddb378bSXinming Hu }
13749ddb378bSXinming Hu }
13759ddb378bSXinming Hu
13769ddb378bSXinming Hu /* Saved in gen_ie, such as P2P IE.etc.*/
13779ddb378bSXinming Hu
13789ddb378bSXinming Hu /* Verify that the passed length is not larger than the
13799ddb378bSXinming Hu * available space remaining in the buffer
13809ddb378bSXinming Hu */
13819ddb378bSXinming Hu if (cur_ie_len <
13829ddb378bSXinming Hu (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
13839ddb378bSXinming Hu /* Append the passed data to the end
13849ddb378bSXinming Hu * of the genIeBuffer
13859ddb378bSXinming Hu */
13869ddb378bSXinming Hu memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len,
13879ddb378bSXinming Hu (u8 *)pvendor_ie, cur_ie_len);
13889ddb378bSXinming Hu /* Increment the stored buffer length by the
13899ddb378bSXinming Hu * size passed
13909ddb378bSXinming Hu */
13919ddb378bSXinming Hu priv->gen_ie_buf_len += cur_ie_len;
13929ddb378bSXinming Hu }
13939ddb378bSXinming Hu
13949ddb378bSXinming Hu next_ie:
13959ddb378bSXinming Hu unparsed_len -= cur_ie_len;
139684a38fb3Schunfan chen
139784a38fb3Schunfan chen if (unparsed_len <= sizeof(struct ieee_types_header))
139884a38fb3Schunfan chen pvendor_ie = NULL;
139984a38fb3Schunfan chen else
140084a38fb3Schunfan chen pvendor_ie = (struct ieee_types_vendor_header *)
14019ddb378bSXinming Hu (((u8 *)pvendor_ie) + cur_ie_len);
140284a38fb3Schunfan chen }
140384a38fb3Schunfan chen
14049ddb378bSXinming Hu return 0;
1405277b024eSKalle Valo }
1406277b024eSKalle Valo
1407277b024eSKalle Valo /*
1408277b024eSKalle Valo * IOCTL request handler to set/get generic IE.
1409277b024eSKalle Valo *
1410277b024eSKalle Valo * In addition to various generic IEs, this function can also be
1411277b024eSKalle Valo * used to set the ARP filter.
1412277b024eSKalle Valo */
mwifiex_misc_ioctl_gen_ie(struct mwifiex_private * priv,struct mwifiex_ds_misc_gen_ie * gen_ie,u16 action)1413277b024eSKalle Valo static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
1414277b024eSKalle Valo struct mwifiex_ds_misc_gen_ie *gen_ie,
1415277b024eSKalle Valo u16 action)
1416277b024eSKalle Valo {
1417277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
1418277b024eSKalle Valo
1419277b024eSKalle Valo switch (gen_ie->type) {
1420277b024eSKalle Valo case MWIFIEX_IE_TYPE_GEN_IE:
1421277b024eSKalle Valo if (action == HostCmd_ACT_GEN_GET) {
1422277b024eSKalle Valo gen_ie->len = priv->wpa_ie_len;
1423277b024eSKalle Valo memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
1424277b024eSKalle Valo } else {
1425277b024eSKalle Valo mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
1426277b024eSKalle Valo (u16) gen_ie->len);
1427277b024eSKalle Valo }
1428277b024eSKalle Valo break;
1429277b024eSKalle Valo case MWIFIEX_IE_TYPE_ARP_FILTER:
1430277b024eSKalle Valo memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
1431277b024eSKalle Valo if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
1432277b024eSKalle Valo adapter->arp_filter_size = 0;
1433277b024eSKalle Valo mwifiex_dbg(adapter, ERROR,
1434277b024eSKalle Valo "invalid ARP filter size\n");
1435277b024eSKalle Valo return -1;
1436277b024eSKalle Valo } else {
1437277b024eSKalle Valo memcpy(adapter->arp_filter, gen_ie->ie_data,
1438277b024eSKalle Valo gen_ie->len);
1439277b024eSKalle Valo adapter->arp_filter_size = gen_ie->len;
1440277b024eSKalle Valo }
1441277b024eSKalle Valo break;
1442277b024eSKalle Valo default:
1443277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "invalid IE type\n");
1444277b024eSKalle Valo return -1;
1445277b024eSKalle Valo }
1446277b024eSKalle Valo return 0;
1447277b024eSKalle Valo }
1448277b024eSKalle Valo
1449277b024eSKalle Valo /*
1450277b024eSKalle Valo * Sends IOCTL request to set a generic IE.
1451277b024eSKalle Valo *
1452277b024eSKalle Valo * This function allocates the IOCTL request buffer, fills it
1453277b024eSKalle Valo * with requisite parameters and calls the IOCTL handler.
1454277b024eSKalle Valo */
1455277b024eSKalle Valo int
mwifiex_set_gen_ie(struct mwifiex_private * priv,const u8 * ie,int ie_len)1456277b024eSKalle Valo mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
1457277b024eSKalle Valo {
1458277b024eSKalle Valo struct mwifiex_ds_misc_gen_ie gen_ie;
1459277b024eSKalle Valo
1460277b024eSKalle Valo if (ie_len > IEEE_MAX_IE_SIZE)
1461277b024eSKalle Valo return -EFAULT;
1462277b024eSKalle Valo
1463277b024eSKalle Valo gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
1464277b024eSKalle Valo gen_ie.len = ie_len;
1465277b024eSKalle Valo memcpy(gen_ie.ie_data, ie, ie_len);
1466277b024eSKalle Valo if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))
1467277b024eSKalle Valo return -EFAULT;
1468277b024eSKalle Valo
1469277b024eSKalle Valo return 0;
1470277b024eSKalle Valo }
14718de00f1bSchunfan chen
14728de00f1bSchunfan chen /* This function get Host Sleep wake up reason.
14738de00f1bSchunfan chen *
14748de00f1bSchunfan chen */
mwifiex_get_wakeup_reason(struct mwifiex_private * priv,u16 action,int cmd_type,struct mwifiex_ds_wakeup_reason * wakeup_reason)14758de00f1bSchunfan chen int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
14768de00f1bSchunfan chen int cmd_type,
14778de00f1bSchunfan chen struct mwifiex_ds_wakeup_reason *wakeup_reason)
14788de00f1bSchunfan chen {
14798de00f1bSchunfan chen int status = 0;
14808de00f1bSchunfan chen
14818de00f1bSchunfan chen status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,
14828de00f1bSchunfan chen HostCmd_ACT_GEN_GET, 0, wakeup_reason,
14838de00f1bSchunfan chen cmd_type == MWIFIEX_SYNC_CMD);
14848de00f1bSchunfan chen
14858de00f1bSchunfan chen return status;
14868de00f1bSchunfan chen }
148728bf8312SGanapathi Bhat
mwifiex_get_chan_info(struct mwifiex_private * priv,struct mwifiex_channel_band * channel_band)148828bf8312SGanapathi Bhat int mwifiex_get_chan_info(struct mwifiex_private *priv,
148928bf8312SGanapathi Bhat struct mwifiex_channel_band *channel_band)
149028bf8312SGanapathi Bhat {
149128bf8312SGanapathi Bhat int status = 0;
149228bf8312SGanapathi Bhat
149328bf8312SGanapathi Bhat status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE,
149428bf8312SGanapathi Bhat HostCmd_ACT_GEN_GET, 0, channel_band,
149528bf8312SGanapathi Bhat MWIFIEX_SYNC_CMD);
149628bf8312SGanapathi Bhat
149728bf8312SGanapathi Bhat return status;
149828bf8312SGanapathi Bhat }
1499