blob: be3be7a63cf013151fa89955ca1a47c7c24a8a0b [file] [log] [blame]
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001/*
2 * Marvell Wireless LAN device driver: functions for station ioctl
3 *
Xinming Hu65da33f2014-06-19 21:38:57 -07004 * Copyright (C) 2011-2014, Marvell International Ltd.
Bing Zhao5e6e3a92011-03-21 18:00:50 -07005 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27#include "cfg80211.h"
28
Bing Zhaoef0a68a2014-06-06 19:47:44 -070029static int disconnect_on_suspend;
Amitkumar Karwar22c22d22012-09-20 20:23:17 -070030module_param(disconnect_on_suspend, int, 0644);
31
Bing Zhao5e6e3a92011-03-21 18:00:50 -070032/*
33 * Copies the multicast address list from device to driver.
34 *
35 * This function does not validate the destination memory for
36 * size, and the calling function must ensure enough memory is
37 * available.
38 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -070039int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
40 struct net_device *dev)
Bing Zhao5e6e3a92011-03-21 18:00:50 -070041{
42 int i = 0;
43 struct netdev_hw_addr *ha;
44
45 netdev_for_each_mc_addr(ha, dev)
46 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
47
48 return i;
49}
50
51/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -070052 * Wait queue completion handler.
53 *
Amitkumar Karwar600f5d92011-04-13 17:27:06 -070054 * This function waits on a cmd wait queue. It also cancels the pending
55 * request after waking up, in case of errors.
Bing Zhao5e6e3a92011-03-21 18:00:50 -070056 */
Amitkumar Karwar00d7ea12013-03-15 18:47:05 -070057int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
58 struct cmd_ctrl_node *cmd_queued)
Bing Zhao5e6e3a92011-03-21 18:00:50 -070059{
Amitkumar Karwarb7097eb2012-02-01 20:41:43 -080060 int status;
Amitkumar Karwarb015dbc2012-01-02 16:18:40 -080061
Amitkumar Karwar600f5d92011-04-13 17:27:06 -070062 /* Wait for completion */
Amitkumar Karwarf8d2b922014-04-14 15:31:06 -070063 status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait,
64 *(cmd_queued->condition),
65 (12 * HZ));
66 if (status <= 0) {
Dmitry Torokhov4e0ff942015-04-30 16:52:02 -070067 if (status == 0)
68 status = -ETIMEDOUT;
Andreas Fenkartc5bc15f2015-07-17 09:13:06 +020069 mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n",
70 status);
Amitkumar Karwar3d026d02014-03-20 16:23:49 -070071 mwifiex_cancel_all_pending_cmd(adapter);
Bing Zhao9c969d82013-01-02 16:07:35 -080072 return status;
Bing Zhao5e6e3a92011-03-21 18:00:50 -070073 }
Amitkumar Karwarb7097eb2012-02-01 20:41:43 -080074
75 status = adapter->cmd_wait_q.status;
Amitkumar Karwar600f5d92011-04-13 17:27:06 -070076 adapter->cmd_wait_q.status = 0;
Bing Zhao5e6e3a92011-03-21 18:00:50 -070077
Bing Zhao5e6e3a92011-03-21 18:00:50 -070078 return status;
79}
80
81/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -070082 * This function prepares the correct firmware command and
83 * issues it to set the multicast list.
84 *
85 * This function can be used to enable promiscuous mode, or enable all
86 * multicast packets, or to enable selective multicast.
87 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -070088int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
89 struct mwifiex_multicast_list *mcast_list)
Bing Zhao5e6e3a92011-03-21 18:00:50 -070090{
91 int ret = 0;
92 u16 old_pkt_filter;
93
94 old_pkt_filter = priv->curr_pkt_filter;
Bing Zhao5e6e3a92011-03-21 18:00:50 -070095
96 if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +053097 mwifiex_dbg(priv->adapter, INFO,
98 "info: Enable Promiscuous mode\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -070099 priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
100 priv->curr_pkt_filter &=
101 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
102 } else {
103 /* Multicast */
104 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
Daniel Drakeccd384b2013-05-08 15:37:19 -0400105 if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530106 mwifiex_dbg(priv->adapter, INFO,
107 "info: Enabling All Multicast!\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700108 priv->curr_pkt_filter |=
109 HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
110 } else {
111 priv->curr_pkt_filter &=
112 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530113 mwifiex_dbg(priv->adapter, INFO,
114 "info: Set multicast list=%d\n",
115 mcast_list->num_multicast_addr);
Daniel Drake6390d882013-06-14 15:24:24 -0400116 /* Send multicast addresses to firmware */
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800117 ret = mwifiex_send_cmd(priv,
118 HostCmd_CMD_MAC_MULTICAST_ADR,
119 HostCmd_ACT_GEN_SET, 0,
120 mcast_list, false);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700121 }
122 }
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530123 mwifiex_dbg(priv->adapter, INFO,
124 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
125 old_pkt_filter, priv->curr_pkt_filter);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700126 if (old_pkt_filter != priv->curr_pkt_filter) {
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800127 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
128 HostCmd_ACT_GEN_SET,
129 0, &priv->curr_pkt_filter, false);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700130 }
131
132 return ret;
133}
134
135/*
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700136 * This function fills bss descriptor structure using provided
137 * information.
Bing Zhaod837a2a2013-04-12 10:34:17 -0700138 * beacon_ie buffer is allocated in this function. It is caller's
139 * responsibility to free the memory.
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700140 */
141int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700142 struct cfg80211_bss *bss,
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700143 struct mwifiex_bssdescriptor *bss_desc)
144{
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700145 u8 *beacon_ie;
John W. Linville403e1672012-12-06 14:58:41 -0500146 size_t beacon_ie_len;
Amitkumar Karwarb5abcf02012-04-16 21:36:52 -0700147 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
Johannes Berg9caf0362012-11-29 01:25:20 +0100148 const struct cfg80211_bss_ies *ies;
Amitkumar Karwarbcc920e2016-04-11 07:52:41 -0700149 int ret;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700150
Johannes Berg9caf0362012-11-29 01:25:20 +0100151 rcu_read_lock();
152 ies = rcu_dereference(bss->ies);
Johannes Berg9caf0362012-11-29 01:25:20 +0100153 beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
154 beacon_ie_len = ies->len;
Johannes Berg8cef2c92013-02-05 16:54:31 +0100155 bss_desc->timestamp = ies->tsf;
Johannes Berg9caf0362012-11-29 01:25:20 +0100156 rcu_read_unlock();
157
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700158 if (!beacon_ie) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530159 mwifiex_dbg(priv->adapter, ERROR,
160 " failed to alloc beacon_ie\n");
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700161 return -ENOMEM;
162 }
163
164 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
165 bss_desc->rssi = bss->signal;
Bing Zhaod837a2a2013-04-12 10:34:17 -0700166 /* The caller of this function will free beacon_ie */
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700167 bss_desc->beacon_buf = beacon_ie;
Johannes Berg904f1372012-11-28 21:53:45 +0100168 bss_desc->beacon_buf_size = beacon_ie_len;
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700169 bss_desc->beacon_period = bss->beacon_interval;
170 bss_desc->cap_info_bitmap = bss->capability;
Amitkumar Karwarb5abcf02012-04-16 21:36:52 -0700171 bss_desc->bss_band = bss_priv->band;
172 bss_desc->fw_tsf = bss_priv->fw_tsf;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700173 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530174 mwifiex_dbg(priv->adapter, INFO,
175 "info: InterpretIE: AP WEP enabled\n");
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700176 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
177 } else {
178 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
179 }
180 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
181 bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
182 else
183 bss_desc->bss_mode = NL80211_IFTYPE_STATION;
184
Bing Zhaoc43933e2013-04-12 10:34:18 -0700185 /* Disable 11ac by default. Enable it only where there
186 * exist VHT_CAP IE in AP beacon
187 */
188 bss_desc->disable_11ac = true;
189
Amitkumar Karwar2a7305c2013-06-19 08:49:05 -0700190 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
191 bss_desc->sensed_11h = true;
192
Amitkumar Karwarbcc920e2016-04-11 07:52:41 -0700193 ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
194 if (ret)
195 return ret;
196
197 /* Update HT40 capability based on current channel information */
198 if (bss_desc->bcn_ht_oper && bss_desc->bcn_ht_cap) {
199 u8 ht_param = bss_desc->bcn_ht_oper->ht_param;
200 u8 radio = mwifiex_band_to_radio_type(bss_desc->bss_band);
201 struct ieee80211_supported_band *sband =
202 priv->wdev.wiphy->bands[radio];
203 int freq = ieee80211_channel_to_frequency(bss_desc->channel,
204 radio);
205 struct ieee80211_channel *chan =
206 ieee80211_get_channel(priv->adapter->wiphy, freq);
207
208 switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
209 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
210 if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) {
211 sband->ht_cap.cap &=
212 ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
213 sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
214 } else {
215 sband->ht_cap.cap |=
216 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
217 IEEE80211_HT_CAP_SGI_40;
218 }
219 break;
220 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
221 if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) {
222 sband->ht_cap.cap &=
223 ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
224 sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
225 } else {
226 sband->ht_cap.cap |=
227 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
228 IEEE80211_HT_CAP_SGI_40;
229 }
230 break;
231 }
232 }
233
234 return 0;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700235}
236
Bing Zhaob58df442014-01-08 15:45:57 -0800237void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
238{
239 if (priv->adapter->dt_node) {
240 char txpwr[] = {"marvell,00_txpwrlimit"};
241
242 memcpy(&txpwr[8], priv->adapter->country_code, 2);
243 mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
244 }
245}
246
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700247static int mwifiex_process_country_ie(struct mwifiex_private *priv,
248 struct cfg80211_bss *bss)
249{
Johannes Berg9caf0362012-11-29 01:25:20 +0100250 const u8 *country_ie;
251 u8 country_ie_len;
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700252 struct mwifiex_802_11d_domain_reg *domain_info =
253 &priv->adapter->domain_reg;
254
Johannes Berg9caf0362012-11-29 01:25:20 +0100255 rcu_read_lock();
256 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
257 if (!country_ie) {
258 rcu_read_unlock();
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700259 return 0;
Johannes Berg9caf0362012-11-29 01:25:20 +0100260 }
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700261
262 country_ie_len = country_ie[1];
Johannes Berg9caf0362012-11-29 01:25:20 +0100263 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
264 rcu_read_unlock();
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700265 return 0;
Johannes Berg9caf0362012-11-29 01:25:20 +0100266 }
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700267
Bing Zhaodd4a9ac2013-12-13 18:32:59 -0800268 if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
269 rcu_read_unlock();
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530270 mwifiex_dbg(priv->adapter, INFO,
271 "11D: skip setting domain info in FW\n");
Bing Zhaodd4a9ac2013-12-13 18:32:59 -0800272 return 0;
273 }
Ganapathi Bhatefa99b62019-11-21 21:34:38 +0530274
275 if (country_ie_len >
276 (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) {
277 mwifiex_dbg(priv->adapter, ERROR,
278 "11D: country_ie_len overflow!, deauth AP\n");
279 return -EINVAL;
280 }
281
Bing Zhaodd4a9ac2013-12-13 18:32:59 -0800282 memcpy(priv->adapter->country_code, &country_ie[2], 2);
283
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700284 domain_info->country_code[0] = country_ie[2];
285 domain_info->country_code[1] = country_ie[3];
286 domain_info->country_code[2] = ' ';
287
288 country_ie_len -= IEEE80211_COUNTRY_STRING_LEN;
289
290 domain_info->no_of_triplet =
291 country_ie_len / sizeof(struct ieee80211_country_ie_triplet);
292
293 memcpy((u8 *)domain_info->triplet,
294 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);
295
Johannes Berg9caf0362012-11-29 01:25:20 +0100296 rcu_read_unlock();
297
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800298 if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
299 HostCmd_ACT_GEN_SET, 0, NULL, false)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530300 mwifiex_dbg(priv->adapter, ERROR,
301 "11D: setting domain info in FW fail\n");
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700302 return -1;
303 }
304
Bing Zhaob58df442014-01-08 15:45:57 -0800305 mwifiex_dnld_txpwr_table(priv);
Bing Zhao82efa162013-12-13 18:33:02 -0800306
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700307 return 0;
308}
309
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700310/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700311 * In Ad-Hoc mode, the IBSS is created if not found in scan list.
312 * In both Ad-Hoc and infra mode, an deauthentication is performed
313 * first.
314 */
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700315int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
Amitkumar Karwarb9be5f32012-02-27 22:04:14 -0800316 struct cfg80211_ssid *req_ssid)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700317{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -0700318 int ret;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700319 struct mwifiex_adapter *adapter = priv->adapter;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700320 struct mwifiex_bssdescriptor *bss_desc = NULL;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700321
322 priv->scan_block = false;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700323
324 if (bss) {
Ganapathi Bhatefa99b62019-11-21 21:34:38 +0530325 if (adapter->region_code == 0x00 &&
326 mwifiex_process_country_ie(priv, bss))
327 return -EINVAL;
Amitkumar Karware89e2da2012-09-10 18:30:45 -0700328
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700329 /* Allocate and fill new bss descriptor */
330 bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
Joe Perches0d2e7a52013-02-03 17:28:14 +0000331 GFP_KERNEL);
332 if (!bss_desc)
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700333 return -ENOMEM;
Yogesh Ashok Powar5982b472011-08-29 13:21:10 -0700334
Amitkumar Karwar9558a402012-04-16 21:36:51 -0700335 ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700336 if (ret)
337 goto done;
338 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700339
Stone Piao6621fe12013-07-29 16:32:39 -0700340 if (priv->bss_mode == NL80211_IFTYPE_STATION ||
341 priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
Amitkumar Karwarf2bbb072013-06-18 16:36:56 -0700342 u8 config_bands;
343
Amitkumar Karwarf2bbb072013-06-18 16:36:56 -0700344 if (!bss_desc)
345 return -1;
Amitkumar Karward7b9c522013-01-08 17:53:10 -0800346
Amitkumar Karwarf2bbb072013-06-18 16:36:56 -0700347 if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
Xinming Hua659c432014-09-12 20:08:50 +0530348 HostCmd_SCAN_RADIO_TYPE_BG) {
Bing Zhaof25b1432014-02-07 16:21:01 -0800349 config_bands = BAND_B | BAND_G | BAND_GN;
Xinming Hua659c432014-09-12 20:08:50 +0530350 } else {
351 config_bands = BAND_A | BAND_AN;
352 if (adapter->fw_bands & BAND_AAC)
353 config_bands |= BAND_AAC;
354 }
Amitkumar Karward7b9c522013-01-08 17:53:10 -0800355
Amitkumar Karwarf2bbb072013-06-18 16:36:56 -0700356 if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
357 adapter->config_bands = config_bands;
Amitkumar Karward7b9c522013-01-08 17:53:10 -0800358
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700359 ret = mwifiex_check_network_compatibility(priv, bss_desc);
360 if (ret)
361 goto done;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700362
Amitkumar Karwarb8876642013-06-18 16:36:58 -0700363 if (mwifiex_11h_get_csa_closed_channel(priv) ==
364 (u8)bss_desc->channel) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530365 mwifiex_dbg(adapter, ERROR,
366 "Attempt to reconnect on csa closed chan(%d)\n",
367 bss_desc->channel);
Amitkumar Karwara6139b62016-02-23 05:16:17 -0800368 ret = -1;
Amitkumar Karwarb8876642013-06-18 16:36:58 -0700369 goto done;
370 }
371
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530372 mwifiex_dbg(adapter, INFO,
373 "info: SSID found in scan list ...\t"
374 "associating...\n");
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700375
Avinash Patil47411a02012-11-01 18:44:16 -0700376 mwifiex_stop_net_dev_queue(priv->netdev, adapter);
Amitkumar Karwarb7097eb2012-02-01 20:41:43 -0800377 if (netif_carrier_ok(priv->netdev))
378 netif_carrier_off(priv->netdev);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700379
380 /* Clear any past association response stored for
381 * application retrieval */
382 priv->assoc_rsp_size = 0;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700383 ret = mwifiex_associate(priv, bss_desc);
Amitkumar Karwara0f6d6c2012-02-24 21:36:05 -0800384
385 /* If auth type is auto and association fails using open mode,
386 * try to connect using shared mode */
387 if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
388 priv->sec_info.is_authtype_auto &&
389 priv->sec_info.wep_enabled) {
390 priv->sec_info.authentication_mode =
391 NL80211_AUTHTYPE_SHARED_KEY;
392 ret = mwifiex_associate(priv, bss_desc);
393 }
394
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700395 if (bss)
Johannes Berg5b112d32013-02-01 01:49:58 +0100396 cfg80211_put_bss(priv->adapter->wiphy, bss);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700397 } else {
398 /* Adhoc mode */
399 /* If the requested SSID matches current SSID, return */
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700400 if (bss_desc && bss_desc->ssid.ssid_len &&
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -0700401 (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor.
402 ssid, &bss_desc->ssid))) {
Ujjal Roy517543f2013-11-21 11:08:56 -0800403 ret = 0;
404 goto done;
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700405 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700406
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700407 priv->adhoc_is_link_sensed = false;
408
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700409 ret = mwifiex_check_network_compatibility(priv, bss_desc);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700410
Avinash Patil47411a02012-11-01 18:44:16 -0700411 mwifiex_stop_net_dev_queue(priv->netdev, adapter);
Amitkumar Karwarb7097eb2012-02-01 20:41:43 -0800412 if (netif_carrier_ok(priv->netdev))
413 netif_carrier_off(priv->netdev);
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700414
415 if (!ret) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530416 mwifiex_dbg(adapter, INFO,
417 "info: network found in scan\t"
418 " list. Joining...\n");
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700419 ret = mwifiex_adhoc_join(priv, bss_desc);
420 if (bss)
Johannes Berg5b112d32013-02-01 01:49:58 +0100421 cfg80211_put_bss(priv->adapter->wiphy, bss);
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -0700422 } else {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530423 mwifiex_dbg(adapter, INFO,
424 "info: Network not found in\t"
425 "the list, creating adhoc with ssid = %s\n",
426 req_ssid->ssid);
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700427 ret = mwifiex_adhoc_start(priv, req_ssid);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700428 }
429 }
430
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700431done:
Bing Zhaod837a2a2013-04-12 10:34:17 -0700432 /* beacon_ie buffer was allocated in function
433 * mwifiex_fill_new_bss_desc(). Free it now.
434 */
435 if (bss_desc)
436 kfree(bss_desc->beacon_buf);
Amitkumar Karwar7c6fa2a2011-08-10 18:53:57 -0700437 kfree(bss_desc);
Ganapathi Bhat4699fc32016-06-16 18:52:21 +0530438
439 if (ret < 0)
440 priv->attempted_bss_desc = NULL;
441
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700442 return ret;
443}
444
445/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700446 * IOCTL request handler to set host sleep configuration.
447 *
448 * This function prepares the correct firmware command and
449 * issues it.
450 */
Xinming Hu937a5042014-06-19 21:38:56 -0700451int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
452 int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700453
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700454{
455 struct mwifiex_adapter *adapter = priv->adapter;
456 int status = 0;
457 u32 prev_cond = 0;
458
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700459 if (!hs_cfg)
460 return -ENOMEM;
461
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700462 switch (action) {
463 case HostCmd_ACT_GEN_SET:
464 if (adapter->pps_uapsd_mode) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530465 mwifiex_dbg(adapter, INFO,
466 "info: Host Sleep IOCTL\t"
467 "is blocked in UAPSD/PPS mode\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700468 status = -1;
469 break;
470 }
471 if (hs_cfg->is_invoke_hostcmd) {
Amitkumar Karwarcc0b5a62013-03-04 16:27:57 -0800472 if (hs_cfg->conditions == HS_CFG_CANCEL) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700473 if (!adapter->is_hs_configured)
474 /* Already cancelled */
475 break;
476 /* Save previous condition */
477 prev_cond = le32_to_cpu(adapter->hs_cfg
478 .conditions);
479 adapter->hs_cfg.conditions =
480 cpu_to_le32(hs_cfg->conditions);
481 } else if (hs_cfg->conditions) {
482 adapter->hs_cfg.conditions =
483 cpu_to_le32(hs_cfg->conditions);
484 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
485 if (hs_cfg->gap)
486 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
Amitkumar Karwarcc0b5a62013-03-04 16:27:57 -0800487 } else if (adapter->hs_cfg.conditions ==
488 cpu_to_le32(HS_CFG_CANCEL)) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700489 /* Return failure if no parameters for HS
490 enable */
491 status = -1;
492 break;
493 }
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800494
495 status = mwifiex_send_cmd(priv,
496 HostCmd_CMD_802_11_HS_CFG_ENH,
497 HostCmd_ACT_GEN_SET, 0,
498 &adapter->hs_cfg,
499 cmd_type == MWIFIEX_SYNC_CMD);
500
Amitkumar Karwarcc0b5a62013-03-04 16:27:57 -0800501 if (hs_cfg->conditions == HS_CFG_CANCEL)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700502 /* Restore previous condition */
503 adapter->hs_cfg.conditions =
504 cpu_to_le32(prev_cond);
505 } else {
506 adapter->hs_cfg.conditions =
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -0700507 cpu_to_le32(hs_cfg->conditions);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700508 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
509 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
510 }
511 break;
512 case HostCmd_ACT_GEN_GET:
513 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
514 hs_cfg->gpio = adapter->hs_cfg.gpio;
515 hs_cfg->gap = adapter->hs_cfg.gap;
516 break;
517 default:
518 status = -1;
519 break;
520 }
521
522 return status;
523}
524
525/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700526 * Sends IOCTL request to cancel the existing Host Sleep configuration.
527 *
528 * This function allocates the IOCTL request buffer, fills it
529 * with requisite parameters and calls the IOCTL handler.
530 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700531int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700532{
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700533 struct mwifiex_ds_hs_cfg hscfg;
534
Amitkumar Karwarcc0b5a62013-03-04 16:27:57 -0800535 hscfg.conditions = HS_CFG_CANCEL;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700536 hscfg.is_invoke_hostcmd = true;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700537
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -0700538 return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
539 cmd_type, &hscfg);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700540}
541EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
542
543/*
544 * Sends IOCTL request to cancel the existing Host Sleep configuration.
545 *
546 * This function allocates the IOCTL request buffer, fills it
547 * with requisite parameters and calls the IOCTL handler.
548 */
549int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
550{
551 struct mwifiex_ds_hs_cfg hscfg;
Amitkumar Karwar22c22d22012-09-20 20:23:17 -0700552 struct mwifiex_private *priv;
553 int i;
554
555 if (disconnect_on_suspend) {
556 for (i = 0; i < adapter->priv_num; i++) {
557 priv = adapter->priv[i];
558 if (priv)
559 mwifiex_deauthenticate(priv, NULL);
560 }
561 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700562
Xinming Hu0c9b7f22016-01-13 01:26:52 -0800563 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
chunfan chen7d7f07d2016-01-13 01:26:54 -0800564
Xinming Hu0c9b7f22016-01-13 01:26:52 -0800565 if (priv && priv->sched_scanning) {
chunfan chen7d7f07d2016-01-13 01:26:54 -0800566#ifdef CONFIG_PM
Wei-Ning Huanga5c92f02016-03-30 18:14:55 +0800567 if (priv->wdev.wiphy->wowlan_config &&
568 !priv->wdev.wiphy->wowlan_config->nd_config) {
chunfan chen7d7f07d2016-01-13 01:26:54 -0800569#endif
570 mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");
571 mwifiex_stop_bg_scan(priv);
572 cfg80211_sched_scan_stopped(priv->wdev.wiphy);
573#ifdef CONFIG_PM
574 }
575#endif
Xinming Hu0c9b7f22016-01-13 01:26:52 -0800576 }
577
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700578 if (adapter->hs_activated) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530579 mwifiex_dbg(adapter, CMD,
580 "cmd: HS Already activated\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700581 return true;
582 }
583
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700584 adapter->hs_activate_wait_q_woken = false;
585
Christophe Jaillet6a162202016-08-08 09:39:00 +0200586 memset(&hscfg, 0, sizeof(hscfg));
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700587 hscfg.is_invoke_hostcmd = true;
588
Amitkumar Karwarc0dbba62014-03-25 19:01:20 -0700589 adapter->hs_enabling = true;
590 mwifiex_cancel_all_pending_cmd(adapter);
591
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700592 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -0700593 MWIFIEX_BSS_ROLE_STA),
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700594 HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
595 &hscfg)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530596 mwifiex_dbg(adapter, ERROR,
597 "IOCTL request HS enable failed\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700598 return false;
599 }
600
Amitkumar Karwar52250cb2014-03-20 16:23:50 -0700601 if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
602 adapter->hs_activate_wait_q_woken,
603 (10 * HZ)) <= 0) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530604 mwifiex_dbg(adapter, ERROR,
605 "hs_activate_wait_q terminated\n");
Bing Zhao9c969d82013-01-02 16:07:35 -0800606 return false;
607 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700608
609 return true;
610}
611EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
612
613/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700614 * IOCTL request handler to get BSS information.
615 *
616 * This function collates the information from different driver structures
617 * to send to the user.
618 */
619int mwifiex_get_bss_info(struct mwifiex_private *priv,
620 struct mwifiex_bss_info *info)
621{
622 struct mwifiex_adapter *adapter = priv->adapter;
623 struct mwifiex_bssdescriptor *bss_desc;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700624
625 if (!info)
626 return -1;
627
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700628 bss_desc = &priv->curr_bss_params.bss_descriptor;
629
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700630 info->bss_mode = priv->bss_mode;
631
Amitkumar Karwarb9be5f32012-02-27 22:04:14 -0800632 memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700633
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700634 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
635
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700636 info->bss_chan = bss_desc->channel;
637
Avinash Patil67fdf392012-05-08 18:30:17 -0700638 memcpy(info->country_code, adapter->country_code,
Amitkumar Karwar5e218b72012-04-09 20:06:55 -0700639 IEEE80211_COUNTRY_STRING_LEN);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700640
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700641 info->media_connected = priv->media_connected;
642
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700643 info->max_power_level = priv->max_tx_power_level;
644 info->min_power_level = priv->min_tx_power_level;
645
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700646 info->adhoc_state = priv->adhoc_state;
647
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700648 info->bcn_nf_last = priv->bcn_nf_last;
649
Amitkumar Karwar5eb02e42012-02-24 21:36:04 -0800650 if (priv->sec_info.wep_enabled)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700651 info->wep_status = true;
652 else
653 info->wep_status = false;
654
655 info->is_hs_configured = adapter->is_hs_configured;
656 info->is_deep_sleep = adapter->is_deep_sleep;
657
658 return 0;
659}
660
661/*
Amitkumar Karwara0490932011-07-13 20:51:59 -0700662 * The function disables auto deep sleep mode.
663 */
664int mwifiex_disable_auto_ds(struct mwifiex_private *priv)
665{
666 struct mwifiex_ds_auto_ds auto_ds;
667
668 auto_ds.auto_ds = DEEP_SLEEP_OFF;
669
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800670 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
671 DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);
Amitkumar Karwara0490932011-07-13 20:51:59 -0700672}
673EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);
674
675/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700676 * Sends IOCTL request to get the data rate.
677 *
678 * This function allocates the IOCTL request buffer, fills it
679 * with requisite parameters and calls the IOCTL handler.
680 */
Amitkumar Karwar006606c2012-07-13 20:09:31 -0700681int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700682{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -0700683 int ret;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700684
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800685 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
686 HostCmd_ACT_GEN_GET, 0, NULL, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700687
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700688 if (!ret) {
Amitkumar Karwar006606c2012-07-13 20:09:31 -0700689 if (priv->is_data_rate_auto)
690 *rate = mwifiex_index_to_data_rate(priv, priv->tx_rate,
691 priv->tx_htinfo);
Dan Carpenter49753122011-09-21 10:13:56 +0300692 else
Amitkumar Karwar006606c2012-07-13 20:09:31 -0700693 *rate = priv->data_rate;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700694 }
695
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700696 return ret;
697}
698
699/*
700 * IOCTL request handler to set tx power configuration.
701 *
702 * This function prepares the correct firmware command and
703 * issues it.
704 *
705 * For non-auto power mode, all the following power groups are set -
706 * - Modulation class HR/DSSS
707 * - Modulation class OFDM
708 * - Modulation class HTBW20
709 * - Modulation class HTBW40
710 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700711int mwifiex_set_tx_power(struct mwifiex_private *priv,
712 struct mwifiex_power_cfg *power_cfg)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700713{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -0700714 int ret;
715 struct host_cmd_ds_txpwr_cfg *txp_cfg;
716 struct mwifiex_types_power_group *pg_tlv;
717 struct mwifiex_power_group *pg;
718 u8 *buf;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700719 u16 dbm = 0;
720
721 if (!power_cfg->is_power_auto) {
722 dbm = (u16) power_cfg->power_level;
723 if ((dbm < priv->min_tx_power_level) ||
724 (dbm > priv->max_tx_power_level)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530725 mwifiex_dbg(priv->adapter, ERROR,
726 "txpower value %d dBm\t"
727 "is out of range (%d dBm-%d dBm)\n",
728 dbm, priv->min_tx_power_level,
729 priv->max_tx_power_level);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700730 return -1;
731 }
732 }
733 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
Joe Perches0d2e7a52013-02-03 17:28:14 +0000734 if (!buf)
Christoph Fritzb53575e2011-05-08 22:50:09 +0200735 return -ENOMEM;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700736
737 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
738 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
739 if (!power_cfg->is_power_auto) {
Adrian Bunk9c8e98a2019-02-13 15:59:38 +0200740 u16 dbm_min = power_cfg->is_power_fixed ?
741 dbm : priv->min_tx_power_level;
742
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700743 txp_cfg->mode = cpu_to_le32(1);
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -0700744 pg_tlv = (struct mwifiex_types_power_group *)
745 (buf + sizeof(struct host_cmd_ds_txpwr_cfg));
Amitkumar Karwar930fd352013-10-22 15:24:43 -0700746 pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);
747 pg_tlv->length =
748 cpu_to_le16(4 * sizeof(struct mwifiex_power_group));
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -0700749 pg = (struct mwifiex_power_group *)
750 (buf + sizeof(struct host_cmd_ds_txpwr_cfg)
751 + sizeof(struct mwifiex_types_power_group));
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700752 /* Power group for modulation class HR/DSSS */
753 pg->first_rate_code = 0x00;
754 pg->last_rate_code = 0x03;
755 pg->modulation_class = MOD_CLASS_HR_DSSS;
756 pg->power_step = 0;
Adrian Bunk9c8e98a2019-02-13 15:59:38 +0200757 pg->power_min = (s8) dbm_min;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700758 pg->power_max = (s8) dbm;
759 pg++;
760 /* Power group for modulation class OFDM */
761 pg->first_rate_code = 0x00;
762 pg->last_rate_code = 0x07;
763 pg->modulation_class = MOD_CLASS_OFDM;
764 pg->power_step = 0;
Adrian Bunk9c8e98a2019-02-13 15:59:38 +0200765 pg->power_min = (s8) dbm_min;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700766 pg->power_max = (s8) dbm;
767 pg++;
768 /* Power group for modulation class HTBW20 */
769 pg->first_rate_code = 0x00;
770 pg->last_rate_code = 0x20;
771 pg->modulation_class = MOD_CLASS_HT;
772 pg->power_step = 0;
Adrian Bunk9c8e98a2019-02-13 15:59:38 +0200773 pg->power_min = (s8) dbm_min;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700774 pg->power_max = (s8) dbm;
775 pg->ht_bandwidth = HT_BW_20;
776 pg++;
777 /* Power group for modulation class HTBW40 */
778 pg->first_rate_code = 0x00;
779 pg->last_rate_code = 0x20;
780 pg->modulation_class = MOD_CLASS_HT;
781 pg->power_step = 0;
Adrian Bunk9c8e98a2019-02-13 15:59:38 +0200782 pg->power_min = (s8) dbm_min;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700783 pg->power_max = (s8) dbm;
784 pg->ht_bandwidth = HT_BW_40;
785 }
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800786 ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,
787 HostCmd_ACT_GEN_SET, 0, buf, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700788
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700789 kfree(buf);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700790 return ret;
791}
792
793/*
794 * IOCTL request handler to get power save mode.
795 *
796 * This function prepares the correct firmware command and
797 * issues it.
798 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700799int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700800{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -0700801 int ret;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700802 struct mwifiex_adapter *adapter = priv->adapter;
803 u16 sub_cmd;
804
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700805 if (*ps_mode)
806 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
807 else
808 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
809 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800810 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
811 sub_cmd, BITMAP_STA_PS, NULL, true);
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700812 if ((!ret) && (sub_cmd == DIS_AUTO_PS))
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800813 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
814 GET_PS, 0, NULL, false);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700815
816 return ret;
817}
818
819/*
820 * IOCTL request handler to set/reset WPA IE.
821 *
822 * The supplied WPA IE is treated as a opaque buffer. Only the first field
823 * is checked to determine WPA version. If buffer length is zero, the existing
824 * WPA IE is reset.
825 */
826static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
827 u8 *ie_data_ptr, u16 ie_len)
828{
829 if (ie_len) {
830 if (ie_len > sizeof(priv->wpa_ie)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530831 mwifiex_dbg(priv->adapter, ERROR,
832 "failed to copy WPA IE, too big\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700833 return -1;
834 }
835 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
chunfan chen1d8f5c12015-12-16 04:21:42 -0800836 priv->wpa_ie_len = ie_len;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530837 mwifiex_dbg(priv->adapter, CMD,
838 "cmd: Set Wpa_ie_len=%d IE=%#x\n",
839 priv->wpa_ie_len, priv->wpa_ie[0]);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700840
Arend van Spriel04b23122012-10-12 12:28:14 +0200841 if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700842 priv->sec_info.wpa_enabled = true;
843 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
844 priv->sec_info.wpa2_enabled = true;
845 } else {
846 priv->sec_info.wpa_enabled = false;
847 priv->sec_info.wpa2_enabled = false;
848 }
849 } else {
850 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
851 priv->wpa_ie_len = 0;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530852 mwifiex_dbg(priv->adapter, INFO,
853 "info: reset wpa_ie_len=%d IE=%#x\n",
854 priv->wpa_ie_len, priv->wpa_ie[0]);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700855 priv->sec_info.wpa_enabled = false;
856 priv->sec_info.wpa2_enabled = false;
857 }
858
859 return 0;
860}
861
862/*
863 * IOCTL request handler to set/reset WAPI IE.
864 *
865 * The supplied WAPI IE is treated as a opaque buffer. Only the first field
866 * is checked to internally enable WAPI. If buffer length is zero, the existing
867 * WAPI IE is reset.
868 */
869static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
870 u8 *ie_data_ptr, u16 ie_len)
871{
872 if (ie_len) {
873 if (ie_len > sizeof(priv->wapi_ie)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530874 mwifiex_dbg(priv->adapter, ERROR,
875 "info: failed to copy WAPI IE, too big\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700876 return -1;
877 }
878 memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
879 priv->wapi_ie_len = ie_len;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530880 mwifiex_dbg(priv->adapter, CMD,
881 "cmd: Set wapi_ie_len=%d IE=%#x\n",
882 priv->wapi_ie_len, priv->wapi_ie[0]);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700883
884 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
885 priv->sec_info.wapi_enabled = true;
886 } else {
887 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
888 priv->wapi_ie_len = ie_len;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530889 mwifiex_dbg(priv->adapter, INFO,
890 "info: Reset wapi_ie_len=%d IE=%#x\n",
891 priv->wapi_ie_len, priv->wapi_ie[0]);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700892 priv->sec_info.wapi_enabled = false;
893 }
894 return 0;
895}
896
897/*
Avinash Patil13d7ba72012-04-09 20:06:56 -0700898 * IOCTL request handler to set/reset WPS IE.
899 *
900 * The supplied WPS IE is treated as a opaque buffer. Only the first field
901 * is checked to internally enable WPS. If buffer length is zero, the existing
902 * WPS IE is reset.
903 */
904static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
905 u8 *ie_data_ptr, u16 ie_len)
906{
907 if (ie_len) {
Avinash Patil8795ca62013-07-22 19:17:46 -0700908 if (ie_len > MWIFIEX_MAX_VSIE_LEN) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530909 mwifiex_dbg(priv->adapter, ERROR,
910 "info: failed to copy WPS IE, too big\n");
Avinash Patil8795ca62013-07-22 19:17:46 -0700911 return -1;
912 }
913
Avinash Patil13d7ba72012-04-09 20:06:56 -0700914 priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
915 if (!priv->wps_ie)
916 return -ENOMEM;
Avinash Patil8795ca62013-07-22 19:17:46 -0700917
Avinash Patil13d7ba72012-04-09 20:06:56 -0700918 memcpy(priv->wps_ie, ie_data_ptr, ie_len);
919 priv->wps_ie_len = ie_len;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530920 mwifiex_dbg(priv->adapter, CMD,
921 "cmd: Set wps_ie_len=%d IE=%#x\n",
922 priv->wps_ie_len, priv->wps_ie[0]);
Avinash Patil13d7ba72012-04-09 20:06:56 -0700923 } else {
924 kfree(priv->wps_ie);
925 priv->wps_ie_len = ie_len;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530926 mwifiex_dbg(priv->adapter, INFO,
927 "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
Avinash Patil13d7ba72012-04-09 20:06:56 -0700928 }
929 return 0;
930}
931
932/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700933 * IOCTL request handler to set WAPI key.
934 *
935 * This function prepares the correct firmware command and
936 * issues it.
937 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700938static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700939 struct mwifiex_ds_encrypt_key *encrypt_key)
940{
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700941
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800942 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
943 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
944 encrypt_key, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700945}
946
947/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700948 * IOCTL request handler to set WEP network key.
949 *
950 * This function prepares the correct firmware command and
951 * issues it, after validation checks.
952 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -0700953static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700954 struct mwifiex_ds_encrypt_key *encrypt_key)
955{
Avinash Patile57f1732014-02-07 16:32:35 -0800956 struct mwifiex_adapter *adapter = priv->adapter;
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -0700957 int ret;
958 struct mwifiex_wep_key *wep_key;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700959 int index;
960
961 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
962 priv->wep_key_curr_index = 0;
963 wep_key = &priv->wep_key[priv->wep_key_curr_index];
964 index = encrypt_key->key_index;
965 if (encrypt_key->key_disable) {
Amitkumar Karwar5eb02e42012-02-24 21:36:04 -0800966 priv->sec_info.wep_enabled = 0;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700967 } else if (!encrypt_key->key_len) {
968 /* Copy the required key as the current key */
969 wep_key = &priv->wep_key[index];
970 if (!wep_key->key_length) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530971 mwifiex_dbg(adapter, ERROR,
972 "key not set, so cannot enable it\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700973 return -1;
974 }
Avinash Patile57f1732014-02-07 16:32:35 -0800975
Amitkumar Karwar4b9fede2014-08-19 08:24:25 -0400976 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
Avinash Patile57f1732014-02-07 16:32:35 -0800977 memcpy(encrypt_key->key_material,
978 wep_key->key_material, wep_key->key_length);
979 encrypt_key->key_len = wep_key->key_length;
980 }
981
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700982 priv->wep_key_curr_index = (u16) index;
Amitkumar Karwar5eb02e42012-02-24 21:36:04 -0800983 priv->sec_info.wep_enabled = 1;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700984 } else {
985 wep_key = &priv->wep_key[index];
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700986 memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
987 /* Copy the key in the driver */
988 memcpy(wep_key->key_material,
989 encrypt_key->key_material,
990 encrypt_key->key_len);
991 wep_key->key_index = index;
992 wep_key->key_length = encrypt_key->key_len;
Amitkumar Karwar5eb02e42012-02-24 21:36:04 -0800993 priv->sec_info.wep_enabled = 1;
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700994 }
995 if (wep_key->key_length) {
Avinash Patile57f1732014-02-07 16:32:35 -0800996 void *enc_key;
997
Xinming Hu2ab87d52014-12-26 03:02:32 -0800998 if (encrypt_key->key_disable) {
Avinash Patile57f1732014-02-07 16:32:35 -0800999 memset(&priv->wep_key[index], 0,
1000 sizeof(struct mwifiex_wep_key));
Dan Carpenter97276c12015-12-04 16:17:15 +03001001 goto done;
1002 }
Avinash Patile57f1732014-02-07 16:32:35 -08001003
Amitkumar Karwar4b9fede2014-08-19 08:24:25 -04001004 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
Avinash Patile57f1732014-02-07 16:32:35 -08001005 enc_key = encrypt_key;
1006 else
1007 enc_key = NULL;
1008
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001009 /* Send request to firmware */
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001010 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1011 HostCmd_ACT_GEN_SET, 0, enc_key, false);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001012 if (ret)
1013 return ret;
1014 }
Avinash Patile57f1732014-02-07 16:32:35 -08001015
Xinming Hu2ab87d52014-12-26 03:02:32 -08001016done:
Amitkumar Karwar5eb02e42012-02-24 21:36:04 -08001017 if (priv->sec_info.wep_enabled)
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001018 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
1019 else
1020 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
1021
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001022 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1023 HostCmd_ACT_GEN_SET, 0,
1024 &priv->curr_pkt_filter, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001025
1026 return ret;
1027}
1028
1029/*
1030 * IOCTL request handler to set WPA key.
1031 *
1032 * This function prepares the correct firmware command and
1033 * issues it, after validation checks.
1034 *
1035 * Current driver only supports key length of up to 32 bytes.
1036 *
1037 * This function can also be used to disable a currently set key.
1038 */
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001039static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001040 struct mwifiex_ds_encrypt_key *encrypt_key)
1041{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -07001042 int ret;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001043 u8 remove_key = false;
1044 struct host_cmd_ds_802_11_key_material *ibss_key;
1045
1046 /* Current driver only supports key length of up to 32 bytes */
Amitkumar Karwara3731652011-04-15 20:50:41 -07001047 if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301048 mwifiex_dbg(priv->adapter, ERROR,
1049 "key length too long\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001050 return -1;
1051 }
1052
Bing Zhaoeecd8252011-03-28 17:55:41 -07001053 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001054 /*
1055 * IBSS/WPA-None uses only one key (Group) for both receiving
1056 * and sending unicast and multicast packets.
1057 */
1058 /* Send the key as PTK to firmware */
1059 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001060 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1061 HostCmd_ACT_GEN_SET,
1062 KEY_INFO_ENABLED, encrypt_key, false);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001063 if (ret)
1064 return ret;
1065
1066 ibss_key = &priv->aes_key;
1067 memset(ibss_key, 0,
1068 sizeof(struct host_cmd_ds_802_11_key_material));
1069 /* Copy the key in the driver */
1070 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
1071 encrypt_key->key_len);
1072 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
1073 sizeof(ibss_key->key_param_set.key_len));
1074 ibss_key->key_param_set.key_type_id
1075 = cpu_to_le16(KEY_TYPE_ID_TKIP);
Yogesh Ashok Powar6a35a0a2011-04-06 16:46:56 -07001076 ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001077
1078 /* Send the key as GTK to firmware */
1079 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
1080 }
1081
1082 if (!encrypt_key->key_index)
1083 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1084
1085 if (remove_key)
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001086 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1087 HostCmd_ACT_GEN_SET,
1088 !KEY_INFO_ENABLED, encrypt_key, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001089 else
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001090 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1091 HostCmd_ACT_GEN_SET,
1092 KEY_INFO_ENABLED, encrypt_key, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001093
1094 return ret;
1095}
1096
1097/*
1098 * IOCTL request handler to set/get network keys.
1099 *
1100 * This is a generic key handling function which supports WEP, WPA
1101 * and WAPI.
1102 */
1103static int
1104mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001105 struct mwifiex_ds_encrypt_key *encrypt_key)
1106{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -07001107 int status;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001108
1109 if (encrypt_key->is_wapi_key)
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001110 status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001111 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001112 status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001113 else
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001114 status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001115 return status;
1116}
1117
1118/*
1119 * This function returns the driver version.
1120 */
1121int
1122mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
1123 int max_len)
1124{
1125 union {
Amitkumar Karwar0d4b5c72014-11-07 02:14:52 -08001126 __le32 l;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001127 u8 c[4];
1128 } ver;
1129 char fw_ver[32];
1130
Amitkumar Karwar0d4b5c72014-11-07 02:14:52 -08001131 ver.l = cpu_to_le32(adapter->fw_release_number);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001132 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
1133
1134 snprintf(version, max_len, driver_version, fw_ver);
1135
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301136 mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001137
1138 return 0;
1139}
1140
1141/*
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001142 * Sends IOCTL request to set encoding parameters.
1143 *
1144 * This function allocates the IOCTL request buffer, fills it
1145 * with requisite parameters and calls the IOCTL handler.
1146 */
Ying Luo53b11232012-08-03 18:06:13 -07001147int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
1148 const u8 *key, int key_len, u8 key_index,
1149 const u8 *mac_addr, int disable)
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001150{
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001151 struct mwifiex_ds_encrypt_key encrypt_key;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001152
Christophe Jaillet6a162202016-08-08 09:39:00 +02001153 memset(&encrypt_key, 0, sizeof(encrypt_key));
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001154 encrypt_key.key_len = key_len;
Avinash Patile57f1732014-02-07 16:32:35 -08001155 encrypt_key.key_index = key_index;
Ying Luo53b11232012-08-03 18:06:13 -07001156
1157 if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
1158 encrypt_key.is_igtk_key = true;
1159
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001160 if (!disable) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001161 if (key_len)
1162 memcpy(encrypt_key.key_material, key, key_len);
Avinash Patile57f1732014-02-07 16:32:35 -08001163 else
1164 encrypt_key.is_current_wep_key = true;
1165
Avinash Patil75edd2c2012-05-08 18:30:18 -07001166 if (mac_addr)
1167 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
Avinash Patile57f1732014-02-07 16:32:35 -08001168 if (kp && kp->seq && kp->seq_len) {
Ying Luo53b11232012-08-03 18:06:13 -07001169 memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
Avinash Patile57f1732014-02-07 16:32:35 -08001170 encrypt_key.pn_len = kp->seq_len;
1171 encrypt_key.is_rx_seq_valid = true;
1172 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001173 } else {
1174 encrypt_key.key_disable = true;
Avinash Patil75edd2c2012-05-08 18:30:18 -07001175 if (mac_addr)
1176 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001177 }
1178
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -07001179 return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001180}
1181
1182/*
1183 * Sends IOCTL request to get extended version.
1184 *
1185 * This function allocates the IOCTL request buffer, fills it
1186 * with requisite parameters and calls the IOCTL handler.
1187 */
1188int
Xinming Hu17934b62016-01-06 23:40:49 -08001189mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001190{
1191 struct mwifiex_ver_ext ver_ext;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001192
Christophe Jailletba852012016-08-08 09:38:48 +02001193 memset(&ver_ext, 0, sizeof(ver_ext));
Xinming Hu17934b62016-01-06 23:40:49 -08001194 ver_ext.version_str_sel = version_str_sel;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001195 if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
1196 HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -07001197 return -1;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001198
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -07001199 return 0;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001200}
1201
Stone Piao7feb4c42012-09-25 20:23:36 -07001202int
1203mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
1204 struct ieee80211_channel *chan,
Stone Piao7feb4c42012-09-25 20:23:36 -07001205 unsigned int duration)
1206{
1207 struct host_cmd_ds_remain_on_chan roc_cfg;
1208 u8 sc;
1209
1210 memset(&roc_cfg, 0, sizeof(roc_cfg));
1211 roc_cfg.action = cpu_to_le16(action);
1212 if (action == HostCmd_ACT_GEN_SET) {
1213 roc_cfg.band_cfg = chan->band;
Johannes Berg42d97a52012-11-08 18:31:02 +01001214 sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);
Stone Piao7feb4c42012-09-25 20:23:36 -07001215 roc_cfg.band_cfg |= (sc << 2);
1216
1217 roc_cfg.channel =
1218 ieee80211_frequency_to_channel(chan->center_freq);
1219 roc_cfg.duration = cpu_to_le32(duration);
1220 }
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001221 if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
1222 action, 0, &roc_cfg, true)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301223 mwifiex_dbg(priv->adapter, ERROR,
1224 "failed to remain on channel\n");
Stone Piao7feb4c42012-09-25 20:23:36 -07001225 return -1;
1226 }
1227
1228 return roc_cfg.status;
1229}
1230
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001231/*
1232 * Sends IOCTL request to get statistics information.
1233 *
1234 * This function allocates the IOCTL request buffer, fills it
1235 * with requisite parameters and calls the IOCTL handler.
1236 */
1237int
1238mwifiex_get_stats_info(struct mwifiex_private *priv,
1239 struct mwifiex_ds_get_stats *log)
1240{
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001241 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
1242 HostCmd_ACT_GEN_GET, 0, log, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001243}
1244
1245/*
1246 * IOCTL request handler to read/write register.
1247 *
1248 * This function prepares the correct firmware command and
1249 * issues it.
1250 *
1251 * Access to the following registers are supported -
1252 * - MAC
1253 * - BBP
1254 * - RF
1255 * - PMIC
1256 * - CAU
1257 */
1258static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001259 struct mwifiex_ds_reg_rw *reg_rw,
1260 u16 action)
1261{
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001262 u16 cmd_no;
1263
Prasun Maiti8cfb8602016-06-27 15:43:22 +05301264 switch (reg_rw->type) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001265 case MWIFIEX_REG_MAC:
1266 cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
1267 break;
1268 case MWIFIEX_REG_BBP:
1269 cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
1270 break;
1271 case MWIFIEX_REG_RF:
1272 cmd_no = HostCmd_CMD_RF_REG_ACCESS;
1273 break;
1274 case MWIFIEX_REG_PMIC:
1275 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
1276 break;
1277 case MWIFIEX_REG_CAU:
1278 cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
1279 break;
1280 default:
1281 return -1;
1282 }
1283
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001284 return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001285}
1286
1287/*
1288 * Sends IOCTL request to write to a register.
1289 *
1290 * This function allocates the IOCTL request buffer, fills it
1291 * with requisite parameters and calls the IOCTL handler.
1292 */
1293int
1294mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
1295 u32 reg_offset, u32 reg_value)
1296{
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001297 struct mwifiex_ds_reg_rw reg_rw;
1298
Prasun Maiti8cfb8602016-06-27 15:43:22 +05301299 reg_rw.type = reg_type;
1300 reg_rw.offset = reg_offset;
1301 reg_rw.value = reg_value;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001302
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -07001303 return mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_SET);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001304}
1305
1306/*
1307 * Sends IOCTL request to read from a register.
1308 *
1309 * This function allocates the IOCTL request buffer, fills it
1310 * with requisite parameters and calls the IOCTL handler.
1311 */
1312int
1313mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
1314 u32 reg_offset, u32 *value)
1315{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -07001316 int ret;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001317 struct mwifiex_ds_reg_rw reg_rw;
1318
Prasun Maiti8cfb8602016-06-27 15:43:22 +05301319 reg_rw.type = reg_type;
1320 reg_rw.offset = reg_offset;
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001321 ret = mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_GET);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001322
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001323 if (ret)
1324 goto done;
1325
Prasun Maiti8cfb8602016-06-27 15:43:22 +05301326 *value = reg_rw.value;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001327
1328done:
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001329 return ret;
1330}
1331
1332/*
1333 * Sends IOCTL request to read from EEPROM.
1334 *
1335 * This function allocates the IOCTL request buffer, fills it
1336 * with requisite parameters and calls the IOCTL handler.
1337 */
1338int
1339mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
1340 u8 *value)
1341{
Yogesh Ashok Powar270e58e2011-05-03 20:11:46 -07001342 int ret;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001343 struct mwifiex_ds_read_eeprom rd_eeprom;
1344
Prasun Maiti8cfb8602016-06-27 15:43:22 +05301345 rd_eeprom.offset = offset;
1346 rd_eeprom.byte_count = bytes;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001347
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001348 /* Send request to firmware */
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001349 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
1350 HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001351
Amitkumar Karwar600f5d92011-04-13 17:27:06 -07001352 if (!ret)
Prasun Maiti8cfb8602016-06-27 15:43:22 +05301353 memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA,
1354 rd_eeprom.byte_count));
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001355 return ret;
1356}
1357
1358/*
1359 * This function sets a generic IE. In addition to generic IE, it can
1360 * also handle WPA, WPA2 and WAPI IEs.
1361 */
1362static int
1363mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
1364 u16 ie_len)
1365{
1366 int ret = 0;
1367 struct ieee_types_vendor_header *pvendor_ie;
1368 const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
1369 const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
chunfan chen84a38fb2015-12-14 04:15:15 -08001370 u16 unparsed_len = ie_len;
1371 int find_wpa_ie = 0;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001372
1373 /* If the passed length is zero, reset the buffer */
1374 if (!ie_len) {
1375 priv->gen_ie_buf_len = 0;
1376 priv->wps.session_enable = false;
1377
1378 return 0;
1379 } else if (!ie_data_ptr) {
1380 return -1;
1381 }
1382 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001383
chunfan chen84a38fb2015-12-14 04:15:15 -08001384 while (pvendor_ie) {
1385 if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) {
1386 /* Test to see if it is a WPA IE, if not, then it is a
1387 * gen IE
1388 */
Brian Norris052020f2019-06-14 17:13:20 -07001389 if (!memcmp(&pvendor_ie->oui, wpa_oui,
chunfan chen84a38fb2015-12-14 04:15:15 -08001390 sizeof(wpa_oui))) {
1391 find_wpa_ie = 1;
1392 break;
1393 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001394
chunfan chen84a38fb2015-12-14 04:15:15 -08001395 /* Test to see if it is a WPS IE, if so, enable
1396 * wps session flag
1397 */
Brian Norris052020f2019-06-14 17:13:20 -07001398 if (!memcmp(&pvendor_ie->oui, wps_oui,
chunfan chen84a38fb2015-12-14 04:15:15 -08001399 sizeof(wps_oui))) {
1400 priv->wps.session_enable = true;
1401 mwifiex_dbg(priv->adapter, MSG,
1402 "info: WPS Session Enabled.\n");
1403 ret = mwifiex_set_wps_ie(priv,
1404 (u8 *)pvendor_ie,
1405 unparsed_len);
1406 }
1407 }
1408
1409 if (pvendor_ie->element_id == WLAN_EID_RSN) {
1410 find_wpa_ie = 1;
1411 break;
1412 }
1413
1414 if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001415 /* IE is a WAPI IE so call set_wapi function */
chunfan chen84a38fb2015-12-14 04:15:15 -08001416 ret = mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie,
1417 unparsed_len);
1418 return ret;
1419 }
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001420
chunfan chen84a38fb2015-12-14 04:15:15 -08001421 unparsed_len -= (pvendor_ie->len +
1422 sizeof(struct ieee_types_header));
1423
1424 if (unparsed_len <= sizeof(struct ieee_types_header))
1425 pvendor_ie = NULL;
1426 else
1427 pvendor_ie = (struct ieee_types_vendor_header *)
1428 (((u8 *)pvendor_ie) + pvendor_ie->len +
1429 sizeof(struct ieee_types_header));
1430 }
1431
1432 if (find_wpa_ie) {
1433 /* IE is a WPA/WPA2 IE so call set_wpa function */
1434 ret = mwifiex_set_wpa_ie_helper(priv, (u8 *)pvendor_ie,
1435 unparsed_len);
1436 priv->wps.session_enable = false;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001437 return ret;
1438 }
chunfan chen84a38fb2015-12-14 04:15:15 -08001439
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001440 /*
1441 * Verify that the passed length is not larger than the
1442 * available space remaining in the buffer
1443 */
1444 if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
1445
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001446 /* Append the passed data to the end of the
1447 genIeBuffer */
1448 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -07001449 ie_len);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001450 /* Increment the stored buffer length by the
1451 size passed */
1452 priv->gen_ie_buf_len += ie_len;
1453 } else {
1454 /* Passed data does not fit in the remaining
1455 buffer space */
1456 ret = -1;
1457 }
1458
1459 /* Return 0, or -1 for error case */
1460 return ret;
1461}
1462
1463/*
1464 * IOCTL request handler to set/get generic IE.
1465 *
1466 * In addition to various generic IEs, this function can also be
1467 * used to set the ARP filter.
1468 */
1469static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
1470 struct mwifiex_ds_misc_gen_ie *gen_ie,
1471 u16 action)
1472{
1473 struct mwifiex_adapter *adapter = priv->adapter;
1474
1475 switch (gen_ie->type) {
1476 case MWIFIEX_IE_TYPE_GEN_IE:
1477 if (action == HostCmd_ACT_GEN_GET) {
1478 gen_ie->len = priv->wpa_ie_len;
1479 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
1480 } else {
1481 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
1482 (u16) gen_ie->len);
1483 }
1484 break;
1485 case MWIFIEX_IE_TYPE_ARP_FILTER:
1486 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
1487 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
1488 adapter->arp_filter_size = 0;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301489 mwifiex_dbg(adapter, ERROR,
1490 "invalid ARP filter size\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001491 return -1;
1492 } else {
1493 memcpy(adapter->arp_filter, gen_ie->ie_data,
Yogesh Ashok Powar500f7472012-03-13 19:22:41 -07001494 gen_ie->len);
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001495 adapter->arp_filter_size = gen_ie->len;
1496 }
1497 break;
1498 default:
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301499 mwifiex_dbg(adapter, ERROR, "invalid IE type\n");
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001500 return -1;
1501 }
1502 return 0;
1503}
1504
1505/*
1506 * Sends IOCTL request to set a generic IE.
1507 *
1508 * This function allocates the IOCTL request buffer, fills it
1509 * with requisite parameters and calls the IOCTL handler.
1510 */
1511int
Johannes Berg4b5800f2014-01-15 14:55:59 +01001512mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001513{
1514 struct mwifiex_ds_misc_gen_ie gen_ie;
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001515
Bing Zhao67a50032011-07-13 18:38:34 -07001516 if (ie_len > IEEE_MAX_IE_SIZE)
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001517 return -EFAULT;
1518
1519 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
1520 gen_ie.len = ie_len;
1521 memcpy(gen_ie.ie_data, ie, ie_len);
Yogesh Ashok Powar636c4592011-04-15 20:50:40 -07001522 if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001523 return -EFAULT;
1524
1525 return 0;
1526}
chunfan chen8de00f12016-01-13 01:26:55 -08001527
1528/* This function get Host Sleep wake up reason.
1529 *
1530 */
1531int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
1532 int cmd_type,
1533 struct mwifiex_ds_wakeup_reason *wakeup_reason)
1534{
1535 int status = 0;
1536
1537 status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,
1538 HostCmd_ACT_GEN_GET, 0, wakeup_reason,
1539 cmd_type == MWIFIEX_SYNC_CMD);
1540
1541 return status;
1542}