aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/mwifiex/11n.c922
-rw-r--r--drivers/net/wireless/mwifiex/11n.h178
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c423
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.h32
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c637
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.h67
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig21
-rw-r--r--drivers/net/wireless/mwifiex/Makefile41
-rw-r--r--drivers/net/wireless/mwifiex/README204
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c1517
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.h31
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c368
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c1463
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c773
-rw-r--r--drivers/net/wireless/mwifiex/decl.h177
-rw-r--r--drivers/net/wireless/mwifiex/fw.h1376
-rw-r--r--drivers/net/wireless/mwifiex/init.c665
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h433
-rw-r--r--drivers/net/wireless/mwifiex/join.c1464
-rw-r--r--drivers/net/wireless/mwifiex/main.c1102
-rw-r--r--drivers/net/wireless/mwifiex/main.h1081
-rw-r--r--drivers/net/wireless/mwifiex/scan.c3098
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c1770
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h305
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c1226
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c986
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c405
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c2478
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c182
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c202
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c202
-rw-r--r--drivers/net/wireless/mwifiex/util.c252
-rw-r--r--drivers/net/wireless/mwifiex/util.h32
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c1237
-rw-r--r--drivers/net/wireless/mwifiex/wmm.h112
37 files changed, 25465 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7aeb113cbb90..f354bd4e121e 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig"
284source "drivers/net/wireless/wl1251/Kconfig" 284source "drivers/net/wireless/wl1251/Kconfig"
285source "drivers/net/wireless/wl12xx/Kconfig" 285source "drivers/net/wireless/wl12xx/Kconfig"
286source "drivers/net/wireless/zd1211rw/Kconfig" 286source "drivers/net/wireless/zd1211rw/Kconfig"
287source "drivers/net/wireless/mwifiex/Kconfig"
287 288
288endif # WLAN 289endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index ddd3fb6ba1d3..7bba6a82b875 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/
56obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ 56obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
57 57
58obj-$(CONFIG_IWM) += iwmc3200wifi/ 58obj-$(CONFIG_IWM) += iwmc3200wifi/
59
60obj-$(CONFIG_MWIFIEX) += mwifiex/
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
new file mode 100644
index 000000000000..0e04a21be0a3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -0,0 +1,922 @@
1/*
2 * Marvell Wireless LAN device driver: 802.11n
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * Fills HT capability information field, AMPDU Parameters field, HT extended
30 * capability field, and supported MCS set fields.
31 *
32 * Only the following HT capability information fields are used, all other
33 * fields are always turned off.
34 *
35 * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz)
36 * Bit 4 : Greenfield support (0: Not supported, 1: Supported)
37 * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported)
38 * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported)
39 * Bit 7 : Tx STBC (0: Not supported, 1: Supported)
40 * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams)
41 * Bit 10 : Delayed BA support (0: Not supported, 1: Supported)
42 * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets)
43 * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported)
44 *
45 * In addition, the following AMPDU Parameters are set -
46 * - Maximum AMPDU length exponent (set to 3)
47 * - Minimum AMPDU start spacing (set to 0 - No restrictions)
48 *
49 * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz
50 * support.
51 *
52 * RD responder bit to set to clear in the extended capability header.
53 */
54void
55mwifiex_fill_cap_info(struct mwifiex_private *priv,
56 struct mwifiex_ie_types_htcap *ht_cap)
57{
58 struct mwifiex_adapter *adapter = priv->adapter;
59 u8 *mcs;
60 int rx_mcs_supp;
61 uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
62 uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
63
64 if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) &&
65 ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap))
66 SETHT_SUPPCHANWIDTH(ht_cap_info);
67 else
68 RESETHT_SUPPCHANWIDTH(ht_cap_info);
69
70 if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap) &&
71 ISSUPP_GREENFIELD(adapter->usr_dot_11n_dev_cap))
72 SETHT_GREENFIELD(ht_cap_info);
73 else
74 RESETHT_GREENFIELD(ht_cap_info);
75
76 if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap) &&
77 ISSUPP_SHORTGI20(adapter->usr_dot_11n_dev_cap))
78 SETHT_SHORTGI20(ht_cap_info);
79 else
80 RESETHT_SHORTGI20(ht_cap_info);
81
82 if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap) &&
83 ISSUPP_SHORTGI40(adapter->usr_dot_11n_dev_cap))
84 SETHT_SHORTGI40(ht_cap_info);
85 else
86 RESETHT_SHORTGI40(ht_cap_info);
87
88 /* No user config for RX STBC yet */
89 if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)
90 && ISSUPP_RXSTBC(adapter->usr_dot_11n_dev_cap))
91 SETHT_RXSTBC(ht_cap_info, 1);
92 else
93 RESETHT_RXSTBC(ht_cap_info);
94
95 /* No user config for TX STBC yet */
96 if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
97 SETHT_TXSTBC(ht_cap_info);
98 else
99 RESETHT_TXSTBC(ht_cap_info);
100
101 /* No user config for Delayed BACK yet */
102 if (GET_DELAYEDBACK(adapter->hw_dot_11n_dev_cap))
103 SETHT_DELAYEDBACK(ht_cap_info);
104 else
105 RESETHT_DELAYEDBACK(ht_cap_info);
106
107 if (ISENABLED_40MHZ_INTOLARENT(adapter->usr_dot_11n_dev_cap))
108 SETHT_40MHZ_INTOLARANT(ht_cap_info);
109 else
110 RESETHT_40MHZ_INTOLARANT(ht_cap_info);
111
112 SETAMPDU_SIZE(ht_cap->ht_cap.ampdu_params_info, AMPDU_FACTOR_64K);
113 SETAMPDU_SPACING(ht_cap->ht_cap.ampdu_params_info, 0);
114
115 /* Need change to support 8k AMSDU receive */
116 RESETHT_MAXAMSDU(ht_cap_info);
117
118 rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
119
120 mcs = (u8 *)&ht_cap->ht_cap.mcs;
121
122 /* Set MCS for 1x1 */
123 memset(mcs, 0xff, rx_mcs_supp);
124
125 /* Clear all the other values */
126 memset(&mcs[rx_mcs_supp], 0,
127 sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
128
129 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA ||
130 (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) &&
131 ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap)))
132 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
133 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
134
135 /* Clear RD responder bit */
136 RESETHT_EXTCAP_RDG(ht_ext_cap);
137
138 ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info);
139 ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
140}
141
142/*
143 * Shows HT capability information fields.
144 *
145 * The following HT capability information fields are supported.
146 * - Maximum AMSDU length (3839 bytes or 7935 bytes)
147 * - Beam forming support
148 * - Greenfield preamble support
149 * - AMPDU support
150 * - MIMO Power Save support
151 * - Rx STBC support
152 * - Tx STBC support
153 * - Short GI for 20 MHz support
154 * - Short GI for 40 MHz support
155 * - LDPC coded packets receive support
156 * - Number of delayed BA streams
157 * - Number of immediate BA streams
158 * - 10 MHz channel width support
159 * - 20 MHz channel width support
160 * - 40 MHz channel width support
161 * - Presence of Tx antenna A/B/C/D
162 * - Presence of Rx antenna A/B/C/D
163 */
164void
165mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap)
166{
167 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Max MSDU len = %s octets\n",
168 (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
169 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Beam forming %s\n",
170 (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
171 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Greenfield preamble %s\n",
172 (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
173 dev_dbg(adapter->dev, "info: GET_HW_SPEC: AMPDU %s\n",
174 (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
175 dev_dbg(adapter->dev, "info: GET_HW_SPEC: MIMO Power Save %s\n",
176 (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
177 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Rx STBC %s\n",
178 (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
179 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Tx STBC %s\n",
180 (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
181 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 40 Mhz %s\n",
182 (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
183 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 20 Mhz %s\n",
184 (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
185 dev_dbg(adapter->dev, "info: GET_HW_SPEC: LDPC coded packet receive %s\n",
186 (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
187 dev_dbg(adapter->dev,
188 "info: GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n",
189 GET_DELAYEDBACK(cap));
190 dev_dbg(adapter->dev,
191 "info: GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n",
192 GET_IMMEDIATEBACK(cap));
193 dev_dbg(adapter->dev, "info: GET_HW_SPEC: 40 Mhz channel width %s\n",
194 (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
195 dev_dbg(adapter->dev, "info: GET_HW_SPEC: 20 Mhz channel width %s\n",
196 (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
197 dev_dbg(adapter->dev, "info: GET_HW_SPEC: 10 Mhz channel width %s\n",
198 (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));
199
200 if (ISSUPP_RXANTENNAA(cap))
201 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea A\n");
202
203 if (ISSUPP_RXANTENNAB(cap))
204 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea B\n");
205
206 if (ISSUPP_RXANTENNAC(cap))
207 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea C\n");
208
209 if (ISSUPP_RXANTENNAD(cap))
210 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea D\n");
211
212 if (ISSUPP_TXANTENNAA(cap))
213 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea A\n");
214
215 if (ISSUPP_TXANTENNAB(cap))
216 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea B\n");
217
218 if (ISSUPP_TXANTENNAC(cap))
219 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea C\n");
220
221 if (ISSUPP_TXANTENNAD(cap))
222 dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea D\n");
223
224 return;
225}
226
227/*
228 * Shows HT MCS support field.
229 */
230void
231mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support)
232{
233 dev_dbg(adapter->dev, "info: GET_HW_SPEC: MCSs for %dx%d MIMO\n",
234 GET_RXMCSSUPP(support), GET_TXMCSSUPP(support));
235 return;
236}
237
238/*
239 * This function returns the pointer to an entry in BA Stream
240 * table which matches the requested BA status.
241 */
242static struct mwifiex_tx_ba_stream_tbl *
243mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv,
244 enum mwifiex_ba_status ba_status)
245{
246 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
247 unsigned long flags;
248
249 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
250 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
251 if (tx_ba_tsr_tbl->ba_status == ba_status) {
252 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
253 flags);
254 return tx_ba_tsr_tbl;
255 }
256 }
257 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
258 return NULL;
259}
260
261/*
262 * This function handles the command response of delete a block
263 * ack request.
264 *
265 * The function checks the response success status and takes action
266 * accordingly (send an add BA request in case of success, or recreate
267 * the deleted stream in case of failure, if the add BA was also
268 * initiated by us).
269 */
270int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
271 struct host_cmd_ds_command *resp)
272{
273 int tid;
274 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
275 struct host_cmd_ds_11n_delba *del_ba =
276 (struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
277 uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
278
279 tid = del_ba_param_set >> DELBA_TID_POS;
280 if (del_ba->del_result == BA_RESULT_SUCCESS) {
281 mwifiex_11n_delete_ba_stream_tbl(priv, tid,
282 del_ba->peer_mac_addr, TYPE_DELBA_SENT,
283 INITIATOR_BIT(del_ba_param_set));
284
285 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
286 BA_STREAM_SETUP_INPROGRESS);
287 if (tx_ba_tbl)
288 mwifiex_send_addba(priv, tx_ba_tbl->tid,
289 tx_ba_tbl->ra);
290 } else { /*
291 * In case of failure, recreate the deleted stream in case
292 * we initiated the ADDBA
293 */
294 if (INITIATOR_BIT(del_ba_param_set)) {
295 mwifiex_11n_create_tx_ba_stream_tbl(priv,
296 del_ba->peer_mac_addr, tid,
297 BA_STREAM_SETUP_INPROGRESS);
298
299 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
300 BA_STREAM_SETUP_INPROGRESS);
301 if (tx_ba_tbl)
302 mwifiex_11n_delete_ba_stream_tbl(priv,
303 tx_ba_tbl->tid, tx_ba_tbl->ra,
304 TYPE_DELBA_SENT, true);
305 }
306 }
307
308 return 0;
309}
310
311/*
312 * This function handles the command response of add a block
313 * ack request.
314 *
315 * Handling includes changing the header fields to CPU formats, checking
316 * the response success status and taking actions accordingly (delete the
317 * BA stream table in case of failure).
318 */
319int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
320 struct host_cmd_ds_command *resp)
321{
322 int tid;
323 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
324 (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
325 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
326
327 add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
328 & SSN_MASK);
329
330 tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
331 & IEEE80211_ADDBA_PARAM_TID_MASK)
332 >> BLOCKACKPARAM_TID_POS;
333 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
334 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid,
335 add_ba_rsp->peer_mac_addr);
336 if (tx_ba_tbl) {
337 dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
338 tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
339 } else {
340 dev_err(priv->adapter->dev, "BA stream not created\n");
341 }
342 } else {
343 mwifiex_11n_delete_ba_stream_tbl(priv, tid,
344 add_ba_rsp->peer_mac_addr,
345 TYPE_DELBA_SENT, true);
346 if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
347 priv->aggr_prio_tbl[tid].ampdu_ap =
348 BA_STREAM_NOT_ALLOWED;
349 }
350
351 return 0;
352}
353
354/*
355 * This function handles the command response of 11n configuration request.
356 *
357 * Handling includes changing the header fields into CPU format.
358 */
359int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
360 struct host_cmd_ds_command *resp,
361 void *data_buf)
362{
363 struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
364 struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
365
366 if (data_buf) {
367 tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
368 tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
369 tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
370 }
371 return 0;
372}
373
374/*
375 * This function prepares command of reconfigure Tx buffer.
376 *
377 * Preparation includes -
378 * - Setting command ID, action and proper size
379 * - Setting Tx buffer size (for SET only)
380 * - Ensuring correct endian-ness
381 */
382int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
383 struct host_cmd_ds_command *cmd, int cmd_action,
384 void *data_buf)
385{
386 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
387 u16 action = (u16) cmd_action;
388 u16 buf_size = *((u16 *) data_buf);
389
390 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
391 cmd->size =
392 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
393 tx_buf->action = cpu_to_le16(action);
394 switch (action) {
395 case HostCmd_ACT_GEN_SET:
396 dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
397 tx_buf->buff_size = cpu_to_le16(buf_size);
398 break;
399 case HostCmd_ACT_GEN_GET:
400 default:
401 tx_buf->buff_size = 0;
402 break;
403 }
404 return 0;
405}
406
407/*
408 * This function prepares command of AMSDU aggregation control.
409 *
410 * Preparation includes -
411 * - Setting command ID, action and proper size
412 * - Setting AMSDU control parameters (for SET only)
413 * - Ensuring correct endian-ness
414 */
415int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
416 struct host_cmd_ds_command *cmd,
417 int cmd_action, void *data_buf)
418{
419 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
420 &cmd->params.amsdu_aggr_ctrl;
421 u16 action = (u16) cmd_action;
422 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
423 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
424
425 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
426 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
427 + S_DS_GEN);
428 amsdu_ctrl->action = cpu_to_le16(action);
429 switch (action) {
430 case HostCmd_ACT_GEN_SET:
431 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
432 amsdu_ctrl->curr_buf_size = 0;
433 break;
434 case HostCmd_ACT_GEN_GET:
435 default:
436 amsdu_ctrl->curr_buf_size = 0;
437 break;
438 }
439 return 0;
440}
441
442/*
443 * This function handles the command response of AMSDU aggregation
444 * control request.
445 *
446 * Handling includes changing the header fields into CPU format.
447 */
448int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
449 struct host_cmd_ds_command *resp,
450 void *data_buf)
451{
452 struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
453 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
454 &resp->params.amsdu_aggr_ctrl;
455
456 if (data_buf) {
457 amsdu_aggr_ctrl =
458 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
459 amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
460 amsdu_aggr_ctrl->curr_buf_size =
461 le16_to_cpu(amsdu_ctrl->curr_buf_size);
462 }
463 return 0;
464}
465
466/*
467 * This function prepares 11n configuration command.
468 *
469 * Preparation includes -
470 * - Setting command ID, action and proper size
471 * - Setting HT Tx capability and HT Tx information fields
472 * - Ensuring correct endian-ness
473 */
474int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
475 struct host_cmd_ds_command *cmd,
476 u16 cmd_action, void *data_buf)
477{
478 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
479 struct mwifiex_ds_11n_tx_cfg *txcfg =
480 (struct mwifiex_ds_11n_tx_cfg *) data_buf;
481
482 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
483 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
484 htcfg->action = cpu_to_le16(cmd_action);
485 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
486 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
487 return 0;
488}
489
490/*
491 * This function appends an 11n TLV to a buffer.
492 *
493 * Buffer allocation is responsibility of the calling
494 * function. No size validation is made here.
495 *
496 * The function fills up the following sections, if applicable -
497 * - HT capability IE
498 * - HT information IE (with channel list)
499 * - 20/40 BSS Coexistence IE
500 * - HT Extended Capabilities IE
501 */
502int
503mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
504 struct mwifiex_bssdescriptor *bss_desc,
505 u8 **buffer)
506{
507 struct mwifiex_ie_types_htcap *ht_cap;
508 struct mwifiex_ie_types_htinfo *ht_info;
509 struct mwifiex_ie_types_chan_list_param_set *chan_list;
510 struct mwifiex_ie_types_2040bssco *bss_co_2040;
511 struct mwifiex_ie_types_extcap *ext_cap;
512 int ret_len = 0;
513
514 if (!buffer || !*buffer)
515 return ret_len;
516
517 if (bss_desc->bcn_ht_cap) {
518 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
519 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
520 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
521 ht_cap->header.len =
522 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
523 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
524 (u8 *) bss_desc->bcn_ht_cap +
525 sizeof(struct ieee_types_header),
526 le16_to_cpu(ht_cap->header.len));
527
528 mwifiex_fill_cap_info(priv, ht_cap);
529
530 *buffer += sizeof(struct mwifiex_ie_types_htcap);
531 ret_len += sizeof(struct mwifiex_ie_types_htcap);
532 }
533
534 if (bss_desc->bcn_ht_info) {
535 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
536 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
537 memset(ht_info, 0,
538 sizeof(struct mwifiex_ie_types_htinfo));
539 ht_info->header.type =
540 cpu_to_le16(WLAN_EID_HT_INFORMATION);
541 ht_info->header.len =
542 cpu_to_le16(sizeof(struct ieee80211_ht_info));
543
544 memcpy((u8 *) ht_info +
545 sizeof(struct mwifiex_ie_types_header),
546 (u8 *) bss_desc->bcn_ht_info +
547 sizeof(struct ieee_types_header),
548 le16_to_cpu(ht_info->header.len));
549
550 if (!ISSUPP_CHANWIDTH40
551 (priv->adapter->hw_dot_11n_dev_cap)
552 || !ISSUPP_CHANWIDTH40(priv->adapter->
553 usr_dot_11n_dev_cap))
554 RESET_CHANWIDTH40(ht_info->ht_info.ht_param);
555
556 *buffer += sizeof(struct mwifiex_ie_types_htinfo);
557 ret_len += sizeof(struct mwifiex_ie_types_htinfo);
558 }
559
560 chan_list =
561 (struct mwifiex_ie_types_chan_list_param_set *) *buffer;
562 memset(chan_list, 0,
563 sizeof(struct mwifiex_ie_types_chan_list_param_set));
564 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
565 chan_list->header.len = cpu_to_le16(
566 sizeof(struct mwifiex_ie_types_chan_list_param_set) -
567 sizeof(struct mwifiex_ie_types_header));
568 chan_list->chan_scan_param[0].chan_number =
569 bss_desc->bcn_ht_info->control_chan;
570 chan_list->chan_scan_param[0].radio_type =
571 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
572
573 if ((ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
574 ISSUPP_CHANWIDTH40(priv->adapter->usr_dot_11n_dev_cap))
575 && ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_info->ht_param))
576 SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
577 radio_type,
578 GET_SECONDARYCHAN(bss_desc->
579 bcn_ht_info->ht_param));
580
581 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
582 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
583 }
584
585 if (bss_desc->bcn_bss_co_2040) {
586 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
587 memset(bss_co_2040, 0,
588 sizeof(struct mwifiex_ie_types_2040bssco));
589 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
590 bss_co_2040->header.len =
591 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
592
593 memcpy((u8 *) bss_co_2040 +
594 sizeof(struct mwifiex_ie_types_header),
595 (u8 *) bss_desc->bcn_bss_co_2040 +
596 sizeof(struct ieee_types_header),
597 le16_to_cpu(bss_co_2040->header.len));
598
599 *buffer += sizeof(struct mwifiex_ie_types_2040bssco);
600 ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
601 }
602
603 if (bss_desc->bcn_ext_cap) {
604 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
605 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
606 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
607 ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
608
609 memcpy((u8 *) ext_cap +
610 sizeof(struct mwifiex_ie_types_header),
611 (u8 *) bss_desc->bcn_ext_cap +
612 sizeof(struct ieee_types_header),
613 le16_to_cpu(ext_cap->header.len));
614
615 *buffer += sizeof(struct mwifiex_ie_types_extcap);
616 ret_len += sizeof(struct mwifiex_ie_types_extcap);
617 }
618
619 return ret_len;
620}
621
622/*
623 * This function reconfigures the Tx buffer size in firmware.
624 *
625 * This function prepares a firmware command and issues it, if
626 * the current Tx buffer size is different from the one requested.
627 * Maximum configurable Tx buffer size is limited by the HT capability
628 * field value.
629 */
630void
631mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
632 struct mwifiex_bssdescriptor *bss_desc)
633{
634 u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
635 u16 tx_buf = 0;
636 u16 curr_tx_buf_size = 0;
637
638 if (bss_desc->bcn_ht_cap) {
639 if (GETHT_MAXAMSDU(le16_to_cpu(bss_desc->bcn_ht_cap->cap_info)))
640 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
641 else
642 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
643 }
644
645 tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
646
647 dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
648 max_amsdu, priv->adapter->max_tx_buf_size);
649
650 if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
651 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
652 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
653 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
654 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
655 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
656 if (curr_tx_buf_size != tx_buf)
657 mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
658 HostCmd_ACT_GEN_SET, 0,
659 NULL, &tx_buf);
660
661 return;
662}
663
664/*
665 * This function checks if the given pointer is valid entry of
666 * Tx BA Stream table.
667 */
668static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
669 struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
670{
671 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
672
673 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
674 if (tx_ba_tsr_tbl == tx_tbl_ptr)
675 return true;
676 }
677
678 return false;
679}
680
681/*
682 * This function deletes the given entry in Tx BA Stream table.
683 *
684 * The function also performs a validity check on the supplied
685 * pointer before trying to delete.
686 */
687void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
688 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
689{
690 if (!tx_ba_tsr_tbl &&
691 mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
692 return;
693
694 dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
695
696 list_del(&tx_ba_tsr_tbl->list);
697
698 kfree(tx_ba_tsr_tbl);
699
700 return;
701}
702
703/*
704 * This function deletes all the entries in Tx BA Stream table.
705 */
706void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
707{
708 int i;
709 struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
710 unsigned long flags;
711
712 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
713 list_for_each_entry_safe(del_tbl_ptr, tmp_node,
714 &priv->tx_ba_stream_tbl_ptr, list)
715 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
716 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
717
718 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
719
720 for (i = 0; i < MAX_NUM_TID; ++i)
721 priv->aggr_prio_tbl[i].ampdu_ap =
722 priv->aggr_prio_tbl[i].ampdu_user;
723}
724
725/*
726 * This function returns the pointer to an entry in BA Stream
727 * table which matches the given RA/TID pair.
728 */
729struct mwifiex_tx_ba_stream_tbl *
730mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
731 int tid, u8 *ra)
732{
733 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
734 unsigned long flags;
735
736 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
737 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
738 if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
739 && (tx_ba_tsr_tbl->tid == tid)) {
740 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
741 flags);
742 return tx_ba_tsr_tbl;
743 }
744 }
745 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
746 return NULL;
747}
748
749/*
750 * This function creates an entry in Tx BA stream table for the
751 * given RA/TID pair.
752 */
753void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
754 u8 *ra, int tid,
755 enum mwifiex_ba_status ba_status)
756{
757 struct mwifiex_tx_ba_stream_tbl *new_node;
758 unsigned long flags;
759
760 if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
761 new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
762 GFP_ATOMIC);
763 if (!new_node) {
764 dev_err(priv->adapter->dev,
765 "%s: failed to alloc new_node\n", __func__);
766 return;
767 }
768
769 INIT_LIST_HEAD(&new_node->list);
770
771 new_node->tid = tid;
772 new_node->ba_status = ba_status;
773 memcpy(new_node->ra, ra, ETH_ALEN);
774
775 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
776 list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
777 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
778 }
779
780 return;
781}
782
783/*
784 * This function sends an add BA request to the given TID/RA pair.
785 */
786int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
787{
788 struct host_cmd_ds_11n_addba_req add_ba_req;
789 static u8 dialog_tok;
790 int ret;
791
792 dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
793
794 add_ba_req.block_ack_param_set = cpu_to_le16(
795 (u16) ((tid << BLOCKACKPARAM_TID_POS) |
796 (priv->add_ba_param.
797 tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
798 IMMEDIATE_BLOCK_ACK));
799 add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
800
801 ++dialog_tok;
802
803 if (dialog_tok == 0)
804 dialog_tok = 1;
805
806 add_ba_req.dialog_token = dialog_tok;
807 memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
808
809 /* We don't wait for the response of this command */
810 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ,
811 0, 0, NULL, &add_ba_req);
812
813 return ret;
814}
815
816/*
817 * This function sends a delete BA request to the given TID/RA pair.
818 */
819int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
820 int initiator)
821{
822 struct host_cmd_ds_11n_delba delba;
823 int ret;
824 uint16_t del_ba_param_set;
825
826 memset(&delba, 0, sizeof(delba));
827 delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
828
829 del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
830 if (initiator)
831 del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
832 else
833 del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
834
835 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
836
837 /* We don't wait for the response of this command */
838 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA,
839 HostCmd_ACT_GEN_SET, 0, NULL, &delba);
840
841 return ret;
842}
843
844/*
845 * This function handles the command response of a delete BA request.
846 */
847void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
848{
849 struct host_cmd_ds_11n_delba *cmd_del_ba =
850 (struct host_cmd_ds_11n_delba *) del_ba;
851 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
852 int tid;
853
854 tid = del_ba_param_set >> DELBA_TID_POS;
855
856 mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
857 TYPE_DELBA_RECEIVE,
858 INITIATOR_BIT(del_ba_param_set));
859}
860
861/*
862 * This function retrieves the Rx reordering table.
863 */
864int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
865 struct mwifiex_ds_rx_reorder_tbl *buf)
866{
867 int i;
868 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
869 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
870 int count = 0;
871 unsigned long flags;
872
873 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
874 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
875 list) {
876 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
877 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
878 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
879 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
880 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
881 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
882 rx_reo_tbl->buffer[i] = true;
883 else
884 rx_reo_tbl->buffer[i] = false;
885 }
886 rx_reo_tbl++;
887 count++;
888
889 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
890 break;
891 }
892 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
893
894 return count;
895}
896
897/*
898 * This function retrieves the Tx BA stream table.
899 */
900int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
901 struct mwifiex_ds_tx_ba_stream_tbl *buf)
902{
903 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
904 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
905 int count = 0;
906 unsigned long flags;
907
908 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
909 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
910 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
911 dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
912 __func__, rx_reo_tbl->tid);
913 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
914 rx_reo_tbl++;
915 count++;
916 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
917 break;
918 }
919 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
920
921 return count;
922}
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
new file mode 100644
index 000000000000..769a27f2b2c3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -0,0 +1,178 @@
1/*
2 * Marvell Wireless LAN device driver: 802.11n
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_11N_H_
21#define _MWIFIEX_11N_H_
22
23#include "11n_aggr.h"
24#include "11n_rxreorder.h"
25#include "wmm.h"
26
27void mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap);
28void mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support);
29int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
30 struct host_cmd_ds_command *resp);
31int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
32 struct host_cmd_ds_command *resp);
33int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
34 struct host_cmd_ds_command *resp,
35 void *data_buf);
36int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
37 struct host_cmd_ds_command *cmd,
38 u16 cmd_action, void *data_buf);
39
40int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
41 struct host_cmd_ds_command *cmd,
42 u16 cmd_action, void *data_buf);
43
44int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
45 struct mwifiex_bssdescriptor *bss_desc,
46 u8 **buffer);
47void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
48 struct mwifiex_bssdescriptor *bss_desc);
49void mwifiex_fill_cap_info(struct mwifiex_private *,
50 struct mwifiex_ie_types_htcap *);
51int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
52 u16 action, int *htcap_cfg);
53void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
54 struct mwifiex_tx_ba_stream_tbl
55 *tx_tbl);
56void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv);
57struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct
58 mwifiex_private
59 *priv, int tid,
60 u8 *ra);
61void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra,
62 int tid,
63 enum mwifiex_ba_status ba_status);
64int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac);
65int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
66 int initiator);
67void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba);
68int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
69 struct mwifiex_ds_rx_reorder_tbl *buf);
70int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
71 struct mwifiex_ds_tx_ba_stream_tbl *buf);
72int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
73 struct host_cmd_ds_command
74 *resp,
75 void *data_buf);
76int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
77 struct host_cmd_ds_command *cmd,
78 int cmd_action, void *data_buf);
79int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
80 struct host_cmd_ds_command *cmd,
81 int cmd_action,
82 void *data_buf);
83
84/*
85 * This function checks whether AMPDU is allowed or not for a particular TID.
86 */
87static inline u8
88mwifiex_is_ampdu_allowed(struct mwifiex_private *priv,
89 struct mwifiex_ra_list_tbl *ptr, int tid)
90{
91 return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
92 ? true : false);
93}
94
95/*
96 * This function checks whether AMSDU is allowed or not for a particular TID.
97 */
98static inline u8
99mwifiex_is_amsdu_allowed(struct mwifiex_private *priv,
100 struct mwifiex_ra_list_tbl *ptr, int tid)
101{
102 return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
103 && ((priv->is_data_rate_auto)
104 || !((priv->bitmap_rates[2]) & 0x03)))
105 ? true : false);
106}
107
108/*
109 * This function checks whether a BA stream is available or not.
110 */
111static inline u8
112mwifiex_is_ba_stream_avail(struct mwifiex_private *priv)
113{
114 struct mwifiex_private *pmpriv = NULL;
115 u8 i = 0;
116 u32 ba_stream_num = 0;
117
118 for (i = 0; i < priv->adapter->priv_num; i++) {
119 pmpriv = priv->adapter->priv[i];
120 if (pmpriv)
121 ba_stream_num +=
122 mwifiex_wmm_list_len(priv->adapter,
123 (struct list_head
124 *) &pmpriv->
125 tx_ba_stream_tbl_ptr);
126 }
127
128 return ((ba_stream_num <
129 MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false);
130}
131
132/*
133 * This function finds the correct Tx BA stream to delete.
134 *
135 * Upon successfully locating, both the TID and the RA are returned.
136 */
137static inline u8
138mwifiex_find_stream_to_delete(struct mwifiex_private *priv,
139 struct mwifiex_ra_list_tbl *ptr, int ptr_tid,
140 int *ptid, u8 *ra)
141{
142 int tid;
143 u8 ret = false;
144 struct mwifiex_tx_ba_stream_tbl *tx_tbl;
145 unsigned long flags;
146
147 tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
148
149 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
150 list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
151 if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) {
152 tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user;
153 *ptid = tx_tbl->tid;
154 memcpy(ra, tx_tbl->ra, ETH_ALEN);
155 ret = true;
156 }
157 }
158 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
159
160 return ret;
161}
162
163/*
164 * This function checks whether BA stream is set up or not.
165 */
166static inline int
167mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
168 struct mwifiex_ra_list_tbl *ptr, int tid)
169{
170 struct mwifiex_tx_ba_stream_tbl *tx_tbl;
171
172 tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra);
173 if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl))
174 return true;
175
176 return false;
177}
178#endif /* !_MWIFIEX_11N_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
new file mode 100644
index 000000000000..c2abced66957
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -0,0 +1,423 @@
1/*
2 * Marvell Wireless LAN device driver: 802.11n Aggregation
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27#include "11n_aggr.h"
28
29/*
30 * Creates an AMSDU subframe for aggregation into one AMSDU packet.
31 *
32 * The resultant AMSDU subframe format is -
33 *
34 * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
35 * | DA | SA | Length | SNAP header | MSDU |
36 * | data[0..5] | data[6..11] | | | data[14..] |
37 * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
38 * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes-->
39 *
40 * This function also computes the amount of padding required to make the
41 * buffer length multiple of 4 bytes.
42 *
43 * Data => |DA|SA|SNAP-TYPE|........ .|
44 * MSDU => |DA|SA|Length|SNAP|...... ..|
45 */
46static int
47mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter,
48 struct sk_buff *skb_aggr,
49 struct sk_buff *skb_src, int *pad)
50
51{
52 int dt_offset;
53 struct rfc_1042_hdr snap = {
54 0xaa, /* LLC DSAP */
55 0xaa, /* LLC SSAP */
56 0x03, /* LLC CTRL */
57 {0x00, 0x00, 0x00}, /* SNAP OUI */
58 0x0000 /* SNAP type */
59 /*
60 * This field will be overwritten
61 * later with ethertype
62 */
63 };
64 struct tx_packet_hdr *tx_header = NULL;
65
66 skb_put(skb_aggr, sizeof(*tx_header));
67
68 tx_header = (struct tx_packet_hdr *) skb_aggr->data;
69
70 /* Copy DA and SA */
71 dt_offset = 2 * ETH_ALEN;
72 memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset);
73
74 /* Copy SNAP header */
75 snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset);
76 dt_offset += sizeof(u16);
77
78 memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr));
79
80 skb_pull(skb_src, dt_offset);
81
82 /* Update Length field */
83 tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
84
85 /* Add payload */
86 skb_put(skb_aggr, skb_src->len);
87 memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
88 skb_src->len);
89 *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
90 LLC_SNAP_LEN)) & 3)) : 0;
91 skb_put(skb_aggr, *pad);
92
93 return skb_aggr->len + *pad;
94}
95
96/*
97 * Adds TxPD to AMSDU header.
98 *
99 * Each AMSDU packet will contain one TxPD at the beginning,
100 * followed by multiple AMSDU subframes.
101 */
102static void
103mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
104 struct sk_buff *skb)
105{
106 struct txpd *local_tx_pd;
107
108 skb_push(skb, sizeof(*local_tx_pd));
109
110 local_tx_pd = (struct txpd *) skb->data;
111 memset(local_tx_pd, 0, sizeof(struct txpd));
112
113 /* Original priority has been overwritten */
114 local_tx_pd->priority = (u8) skb->priority;
115 local_tx_pd->pkt_delay_2ms =
116 mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
117 local_tx_pd->bss_num = priv->bss_num;
118 local_tx_pd->bss_type = priv->bss_type;
119 /* Always zero as the data is followed by struct txpd */
120 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
121 local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
122 local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
123 sizeof(*local_tx_pd));
124
125 if (local_tx_pd->tx_control == 0)
126 /* TxCtrl set by user or default */
127 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
128
129 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
130 (priv->adapter->pps_uapsd_mode)) {
131 if (true == mwifiex_check_last_packet_indication(priv)) {
132 priv->adapter->tx_lock_flag = true;
133 local_tx_pd->flags =
134 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
135 }
136 }
137}
138
139/*
140 * Counts the number of subframes in an aggregate packet.
141 *
142 * This function parses an aggregate packet buffer, looking for
143 * subframes and counting the number of such subframe found. The
144 * function automatically skips the DA/SA fields at the beginning
145 * of each subframe and padding at the end.
146 */
147static int
148mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len)
149{
150 int pkt_count = 0, pkt_len, pad;
151
152 while (total_pkt_len > 0) {
153 /* Length will be in network format, change it to host */
154 pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN)));
155 pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
156 (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
157 data += pkt_len + pad + sizeof(struct ethhdr);
158 total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
159 ++pkt_count;
160 }
161
162 return pkt_count;
163}
164
165/*
166 * De-aggregate received packets.
167 *
168 * This function parses the received aggregate buffer, extracts each subframe,
169 * strips off the SNAP header from them and sends the data portion for further
170 * processing.
171 *
172 * Each subframe body is copied onto a separate buffer, which are freed by
173 * upper layer after processing. The function also performs sanity tests on
174 * the received buffer.
175 */
176int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
177 struct sk_buff *skb)
178{
179 u16 pkt_len;
180 int total_pkt_len;
181 u8 *data;
182 int pad;
183 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
184 struct rxpd *local_rx_pd = (struct rxpd *) skb->data;
185 struct sk_buff *skb_daggr;
186 struct mwifiex_rxinfo *rx_info_daggr = NULL;
187 int ret = -1;
188 struct rx_packet_hdr *rx_pkt_hdr;
189 struct mwifiex_adapter *adapter = priv->adapter;
190 u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
191
192 data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset);
193 total_pkt_len = local_rx_pd->rx_pkt_length;
194
195 /* Sanity test */
196 if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) {
197 dev_err(adapter->dev, "total pkt len greater than buffer"
198 " size %d\n", total_pkt_len);
199 return -1;
200 }
201
202 rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len);
203
204 while (total_pkt_len > 0) {
205 rx_pkt_hdr = (struct rx_packet_hdr *) data;
206 /* Length will be in network format, change it to host */
207 pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN)));
208 if (pkt_len > total_pkt_len) {
209 dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n",
210 total_pkt_len, pkt_len);
211 break;
212 }
213
214 pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
215 (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
216
217 total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
218
219 if (memcmp(&rx_pkt_hdr->rfc1042_hdr,
220 rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
221 memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN);
222 data += LLC_SNAP_LEN;
223 pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN;
224 } else {
225 *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0;
226 pkt_len += sizeof(struct ethhdr);
227 }
228
229 skb_daggr = dev_alloc_skb(pkt_len);
230 if (!skb_daggr) {
231 dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n",
232 __func__);
233 return -1;
234 }
235 rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr);
236
237 rx_info_daggr->bss_index = rx_info->bss_index;
238 skb_daggr->tstamp = skb->tstamp;
239 rx_info_daggr->parent = skb;
240 skb_daggr->priority = skb->priority;
241 skb_put(skb_daggr, pkt_len);
242 memcpy(skb_daggr->data, data, pkt_len);
243
244 ret = mwifiex_recv_packet(adapter, skb_daggr);
245
246 switch (ret) {
247 case -EINPROGRESS:
248 break;
249 case -1:
250 dev_err(adapter->dev, "deaggr: host_to_card failed\n");
251 case 0:
252 mwifiex_recv_packet_complete(adapter, skb_daggr, ret);
253 break;
254 default:
255 break;
256 }
257
258 data += pkt_len + pad;
259 }
260
261 return ret;
262}
263
264/*
265 * Create aggregated packet.
266 *
267 * This function creates an aggregated MSDU packet, by combining buffers
268 * from the RA list. Each individual buffer is encapsulated as an AMSDU
269 * subframe and all such subframes are concatenated together to form the
270 * AMSDU packet.
271 *
272 * A TxPD is also added to the front of the resultant AMSDU packets for
273 * transmission. The resultant packets format is -
274 *
275 * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+
276 * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame|
277 * | | 1 | 2 | .. | n |
278 * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+
279 */
280int
281mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
282 struct mwifiex_ra_list_tbl *pra_list, int headroom,
283 int ptrindex, unsigned long ra_list_flags)
284 __releases(&priv->wmm.ra_list_spinlock)
285{
286 struct mwifiex_adapter *adapter = priv->adapter;
287 struct sk_buff *skb_aggr, *skb_src;
288 struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
289 int pad = 0;
290 int ret = 0;
291 struct mwifiex_tx_param tx_param;
292 struct txpd *ptx_pd = NULL;
293
294 if (skb_queue_empty(&pra_list->skb_head)) {
295 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
296 ra_list_flags);
297 return 0;
298 }
299 skb_src = skb_peek(&pra_list->skb_head);
300 tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
301 skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
302 if (!skb_aggr) {
303 dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
304 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
305 ra_list_flags);
306 return -1;
307 }
308 skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
309 tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr);
310
311 tx_info_aggr->bss_index = tx_info_src->bss_index;
312 skb_aggr->priority = skb_src->priority;
313
314 while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len
315 + LLC_SNAP_LEN)
316 <= adapter->tx_buf_size)) {
317
318 if (!skb_queue_empty(&pra_list->skb_head))
319 skb_src = skb_dequeue(&pra_list->skb_head);
320 else
321 skb_src = NULL;
322
323 pra_list->total_pkts_size -= skb_src->len;
324
325 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
326 ra_list_flags);
327 mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad);
328
329 mwifiex_write_data_complete(adapter, skb_src, 0);
330
331 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
332
333 if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
334 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
335 ra_list_flags);
336 return -1;
337 }
338
339 if (!skb_queue_empty(&pra_list->skb_head))
340 skb_src = skb_peek(&pra_list->skb_head);
341 else
342 skb_src = NULL;
343 }
344
345 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
346
347 /* Last AMSDU packet does not need padding */
348 skb_trim(skb_aggr, skb_aggr->len - pad);
349
350 /* Form AMSDU */
351 mwifiex_11n_form_amsdu_txpd(priv, skb_aggr);
352 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
353 ptx_pd = (struct txpd *)skb_aggr->data;
354
355 skb_push(skb_aggr, headroom);
356
357 tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
358 (((pra_list->total_pkts_size) >
359 adapter->tx_buf_size) ? adapter->
360 tx_buf_size : pra_list->total_pkts_size +
361 LLC_SNAP_LEN + sizeof(struct txpd)) : 0);
362 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
363 skb_aggr->data,
364 skb_aggr->len, &tx_param);
365 switch (ret) {
366 case -EBUSY:
367 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
368 if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
369 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
370 ra_list_flags);
371 mwifiex_write_data_complete(adapter, skb_aggr, -1);
372 return -1;
373 }
374 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
375 (adapter->pps_uapsd_mode) &&
376 (adapter->tx_lock_flag)) {
377 priv->adapter->tx_lock_flag = false;
378 ptx_pd->flags = 0;
379 }
380
381 skb_queue_tail(&pra_list->skb_head, skb_aggr);
382
383 pra_list->total_pkts_size += skb_aggr->len;
384
385 tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
386 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
387 ra_list_flags);
388 dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
389 break;
390 case -1:
391 adapter->data_sent = false;
392 dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
393 __func__, ret);
394 adapter->dbg.num_tx_host_to_card_failure++;
395 mwifiex_write_data_complete(adapter, skb_aggr, ret);
396 return 0;
397 case -EINPROGRESS:
398 adapter->data_sent = false;
399 break;
400 case 0:
401 mwifiex_write_data_complete(adapter, skb_aggr, ret);
402 break;
403 default:
404 break;
405 }
406 if (ret != -EBUSY) {
407 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
408 if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
409 priv->wmm.packets_out[ptrindex]++;
410 priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
411 }
412 /* Now bss_prio_cur pointer points to next node */
413 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
414 list_first_entry(
415 &adapter->bss_prio_tbl[priv->bss_priority]
416 .bss_prio_cur->list,
417 struct mwifiex_bss_prio_node, list);
418 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
419 ra_list_flags);
420 }
421
422 return 0;
423}
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h
new file mode 100644
index 000000000000..9c6dca7ab02c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.h
@@ -0,0 +1,32 @@
1/*
2 * Marvell Wireless LAN device driver: 802.11n Aggregation
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_11N_AGGR_H_
21#define _MWIFIEX_11N_AGGR_H_
22
23#define PKT_TYPE_AMSDU 0xE6
24
25int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
26 struct sk_buff *skb);
27int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
28 struct mwifiex_ra_list_tbl *ptr, int headroom,
29 int ptr_index, unsigned long flags)
30 __releases(&priv->wmm.ra_list_spinlock);
31
32#endif /* !_MWIFIEX_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
new file mode 100644
index 000000000000..8e94e620e6f4
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -0,0 +1,637 @@
1/*
2 * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27#include "11n_rxreorder.h"
28
29/*
30 * This function processes a received packet and forwards
31 * it to the kernel/upper layer.
32 */
33static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
34{
35 int ret = 0;
36 struct mwifiex_adapter *adapter = priv->adapter;
37
38 ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload);
39 return ret;
40}
41
42/*
43 * This function dispatches all packets in the Rx reorder table.
44 *
45 * There could be holes in the buffer, which are skipped by the function.
46 * Since the buffer is linear, the function uses rotation to simulate
47 * circular buffer.
48 */
49static int
50mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
51 struct mwifiex_rx_reorder_tbl
52 *rx_reor_tbl_ptr, int start_win)
53{
54 int no_pkt_to_send, i, xchg;
55 void *rx_tmp_ptr = NULL;
56 unsigned long flags;
57
58 no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
59 min((start_win - rx_reor_tbl_ptr->start_win),
60 rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
61
62 for (i = 0; i < no_pkt_to_send; ++i) {
63 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
64 rx_tmp_ptr = NULL;
65 if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
66 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
67 rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
68 }
69 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
70 if (rx_tmp_ptr)
71 mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
72 }
73
74 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
75 /*
76 * We don't have a circular buffer, hence use rotation to simulate
77 * circular buffer
78 */
79 xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
80 for (i = 0; i < xchg; ++i) {
81 rx_reor_tbl_ptr->rx_reorder_ptr[i] =
82 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
83 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
84 }
85
86 rx_reor_tbl_ptr->start_win = start_win;
87 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
88
89 return 0;
90}
91
92/*
93 * This function dispatches all packets in the Rx reorder table until
94 * a hole is found.
95 *
96 * The start window is adjusted automatically when a hole is located.
97 * Since the buffer is linear, the function uses rotation to simulate
98 * circular buffer.
99 */
100static int
101mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
102 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
103{
104 int i, j, xchg;
105 void *rx_tmp_ptr = NULL;
106 unsigned long flags;
107
108 for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
109 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
110 if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
111 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
112 break;
113 }
114 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
115 rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
116 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
117 mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
118 }
119
120 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
121 /*
122 * We don't have a circular buffer, hence use rotation to simulate
123 * circular buffer
124 */
125 if (i > 0) {
126 xchg = rx_reor_tbl_ptr->win_size - i;
127 for (j = 0; j < xchg; ++j) {
128 rx_reor_tbl_ptr->rx_reorder_ptr[j] =
129 rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
130 rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
131 }
132 }
133 rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
134 &(MAX_TID_VALUE - 1);
135 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
136 return 0;
137}
138
139/*
140 * This function deletes the Rx reorder table and frees the memory.
141 *
142 * The function stops the associated timer and dispatches all the
143 * pending packets in the Rx reorder table before deletion.
144 */
145static void
146mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
147 struct mwifiex_rx_reorder_tbl
148 *rx_reor_tbl_ptr)
149{
150 unsigned long flags;
151
152 if (!rx_reor_tbl_ptr)
153 return;
154
155 mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
156 (rx_reor_tbl_ptr->start_win +
157 rx_reor_tbl_ptr->win_size)
158 &(MAX_TID_VALUE - 1));
159
160 del_timer(&rx_reor_tbl_ptr->timer_context.timer);
161
162 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
163 list_del(&rx_reor_tbl_ptr->list);
164 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
165
166 kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
167 kfree(rx_reor_tbl_ptr);
168}
169
170/*
171 * This function returns the pointer to an entry in Rx reordering
172 * table which matches the given TA/TID pair.
173 */
174static struct mwifiex_rx_reorder_tbl *
175mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
176{
177 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
178 unsigned long flags;
179
180 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
181 list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
182 if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
183 && (rx_reor_tbl_ptr->tid == tid)) {
184 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
185 flags);
186 return rx_reor_tbl_ptr;
187 }
188 }
189 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
190
191 return NULL;
192}
193
194/*
195 * This function finds the last sequence number used in the packets
196 * buffered in Rx reordering table.
197 */
198static int
199mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
200{
201 int i;
202
203 for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
204 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
205 return i;
206
207 return -1;
208}
209
210/*
211 * This function flushes all the packets in Rx reordering table.
212 *
213 * The function checks if any packets are currently buffered in the
214 * table or not. In case there are packets available, it dispatches
215 * them and then dumps the Rx reordering table.
216 */
217static void
218mwifiex_flush_data(unsigned long context)
219{
220 struct reorder_tmr_cnxt *reorder_cnxt =
221 (struct reorder_tmr_cnxt *) context;
222 int start_win;
223
224 start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
225 if (start_win >= 0) {
226 dev_dbg(reorder_cnxt->priv->adapter->dev,
227 "info: flush data %d\n", start_win);
228 mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
229 reorder_cnxt->ptr,
230 ((reorder_cnxt->ptr->start_win +
231 start_win + 1) & (MAX_TID_VALUE - 1)));
232 }
233}
234
235/*
236 * This function creates an entry in Rx reordering table for the
237 * given TA/TID.
238 *
239 * The function also initializes the entry with sequence number, window
240 * size as well as initializes the timer.
241 *
242 * If the received TA/TID pair is already present, all the packets are
243 * dispatched and the window size is moved until the SSN.
244 */
245static void
246mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
247 int tid, int win_size, int seq_num)
248{
249 int i;
250 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
251 u16 last_seq = 0;
252 unsigned long flags;
253
254 /*
255 * If we get a TID, ta pair which is already present dispatch all the
256 * the packets and move the window size until the ssn
257 */
258 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
259 if (rx_reor_tbl_ptr) {
260 mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
261 seq_num);
262 return;
263 }
264 /* if !rx_reor_tbl_ptr then create one */
265 new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
266 if (!new_node) {
267 dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
268 __func__);
269 return;
270 }
271
272 INIT_LIST_HEAD(&new_node->list);
273 new_node->tid = tid;
274 memcpy(new_node->ta, ta, ETH_ALEN);
275 new_node->start_win = seq_num;
276 if (mwifiex_queuing_ra_based(priv))
277 /* TODO for adhoc */
278 dev_dbg(priv->adapter->dev,
279 "info: ADHOC:last_seq=%d start_win=%d\n",
280 last_seq, new_node->start_win);
281 else
282 last_seq = priv->rx_seq[tid];
283
284 if (last_seq >= new_node->start_win)
285 new_node->start_win = last_seq + 1;
286
287 new_node->win_size = win_size;
288
289 new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
290 GFP_KERNEL);
291 if (!new_node->rx_reorder_ptr) {
292 kfree((u8 *) new_node);
293 dev_err(priv->adapter->dev,
294 "%s: failed to alloc reorder_ptr\n", __func__);
295 return;
296 }
297
298 new_node->timer_context.ptr = new_node;
299 new_node->timer_context.priv = priv;
300
301 init_timer(&new_node->timer_context.timer);
302 new_node->timer_context.timer.function = mwifiex_flush_data;
303 new_node->timer_context.timer.data =
304 (unsigned long) &new_node->timer_context;
305
306 for (i = 0; i < win_size; ++i)
307 new_node->rx_reorder_ptr[i] = NULL;
308
309 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
310 list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
311 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
312
313 return;
314}
315
316/*
317 * This function prepares command for adding a BA request.
318 *
319 * Preparation includes -
320 * - Setting command ID and proper size
321 * - Setting add BA request buffer
322 * - Ensuring correct endian-ness
323 */
324int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv,
325 struct host_cmd_ds_command *cmd, void *data_buf)
326{
327 struct host_cmd_ds_11n_addba_req *add_ba_req =
328 (struct host_cmd_ds_11n_addba_req *)
329 &cmd->params.add_ba_req;
330
331 cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
332 cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
333 memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
334
335 return 0;
336}
337
338/*
339 * This function prepares command for adding a BA response.
340 *
341 * Preparation includes -
342 * - Setting command ID and proper size
343 * - Setting add BA response buffer
344 * - Ensuring correct endian-ness
345 */
346int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
347 struct host_cmd_ds_command *cmd,
348 void *data_buf)
349{
350 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
351 (struct host_cmd_ds_11n_addba_rsp *)
352 &cmd->params.add_ba_rsp;
353 struct host_cmd_ds_11n_addba_req *cmd_addba_req =
354 (struct host_cmd_ds_11n_addba_req *) data_buf;
355 u8 tid = 0;
356 int win_size = 0;
357 uint16_t block_ack_param_set;
358
359 cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
360 cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
361
362 memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
363 ETH_ALEN);
364 add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
365 add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
366 add_ba_rsp->ssn = cmd_addba_req->ssn;
367
368 block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
369 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
370 >> BLOCKACKPARAM_TID_POS;
371 add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
372 block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
373 /* We donot support AMSDU inside AMPDU, hence reset the bit */
374 block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
375 block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
376 BLOCKACKPARAM_WINSIZE_POS);
377 add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
378 win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
379 & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
380 >> BLOCKACKPARAM_WINSIZE_POS;
381 cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
382
383 mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
384 tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
385 return 0;
386}
387
388/*
389 * This function prepares command for deleting a BA request.
390 *
391 * Preparation includes -
392 * - Setting command ID and proper size
393 * - Setting del BA request buffer
394 * - Ensuring correct endian-ness
395 */
396int mwifiex_cmd_11n_delba(struct mwifiex_private *priv,
397 struct host_cmd_ds_command *cmd, void *data_buf)
398{
399 struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
400 &cmd->params.del_ba;
401
402 cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
403 cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
404 memcpy(del_ba, data_buf, sizeof(*del_ba));
405
406 return 0;
407}
408
409/*
410 * This function identifies if Rx reordering is needed for a received packet.
411 *
412 * In case reordering is required, the function will do the reordering
413 * before sending it to kernel.
414 *
415 * The Rx reorder table is checked first with the received TID/TA pair. If
416 * not found, the received packet is dispatched immediately. But if found,
417 * the packet is reordered and all the packets in the updated Rx reordering
418 * table is dispatched until a hole is found.
419 *
420 * For sequence number less than the starting window, the packet is dropped.
421 */
422int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
423 u16 seq_num, u16 tid,
424 u8 *ta, u8 pkt_type, void *payload)
425{
426 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
427 int start_win, end_win, win_size;
428 int ret = 0;
429 u16 pkt_index = 0;
430
431 rx_reor_tbl_ptr =
432 mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
433 tid, ta);
434 if (!rx_reor_tbl_ptr) {
435 if (pkt_type != PKT_TYPE_BAR)
436 mwifiex_11n_dispatch_pkt(priv, payload);
437 return 0;
438 }
439 start_win = rx_reor_tbl_ptr->start_win;
440 win_size = rx_reor_tbl_ptr->win_size;
441 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
442 del_timer(&rx_reor_tbl_ptr->timer_context.timer);
443 mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
444 + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
445
446 /*
447 * If seq_num is less then starting win then ignore and drop the
448 * packet
449 */
450 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
451 if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
452 && (seq_num < start_win))
453 return -1;
454 } else if ((seq_num < start_win)
455 || (seq_num > (start_win + (TWOPOW11)))) {
456 return -1;
457 }
458
459 /*
460 * If this packet is a BAR we adjust seq_num as
461 * WinStart = seq_num
462 */
463 if (pkt_type == PKT_TYPE_BAR)
464 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
465
466 if (((end_win < start_win)
467 && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
468 && (seq_num > end_win)) || ((end_win > start_win)
469 && ((seq_num > end_win) || (seq_num < start_win)))) {
470 end_win = seq_num;
471 if (((seq_num - win_size) + 1) >= 0)
472 start_win = (end_win - win_size) + 1;
473 else
474 start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
475 ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
476 rx_reor_tbl_ptr, start_win);
477
478 if (ret)
479 return ret;
480 }
481
482 if (pkt_type != PKT_TYPE_BAR) {
483 if (seq_num >= start_win)
484 pkt_index = seq_num - start_win;
485 else
486 pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
487
488 if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
489 return -1;
490
491 rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
492 }
493
494 /*
495 * Dispatch all packets sequentially from start_win until a
496 * hole is found and adjust the start_win appropriately
497 */
498 ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
499
500 return ret;
501}
502
503/*
504 * This function deletes an entry for a given TID/TA pair.
505 *
506 * The TID/TA are taken from del BA event body.
507 */
508void
509mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid,
510 u8 *peer_mac, u8 type, int initiator)
511{
512 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
513 struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
514 u8 cleanup_rx_reorder_tbl;
515 unsigned long flags;
516
517 if (type == TYPE_DELBA_RECEIVE)
518 cleanup_rx_reorder_tbl = (initiator) ? true : false;
519 else
520 cleanup_rx_reorder_tbl = (initiator) ? false : true;
521
522 dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
523 "initiator=%d\n", peer_mac, tid, initiator);
524
525 if (cleanup_rx_reorder_tbl) {
526 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
527 peer_mac);
528 if (!rx_reor_tbl_ptr) {
529 dev_dbg(priv->adapter->dev,
530 "event: TID, TA not found in table\n");
531 return;
532 }
533 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
534 } else {
535 ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac);
536 if (!ptx_tbl) {
537 dev_dbg(priv->adapter->dev,
538 "event: TID, RA not found in table\n");
539 return;
540 }
541
542 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
543 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
544 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
545 }
546}
547
548/*
549 * This function handles the command response of an add BA response.
550 *
551 * Handling includes changing the header fields into CPU format and
552 * creating the stream, provided the add BA is accepted.
553 */
554int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
555 struct host_cmd_ds_command *resp)
556{
557 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
558 (struct host_cmd_ds_11n_addba_rsp *)
559 &resp->params.add_ba_rsp;
560 int tid, win_size;
561 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL;
562 uint16_t block_ack_param_set;
563
564 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
565
566 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
567 >> BLOCKACKPARAM_TID_POS;
568 /*
569 * Check if we had rejected the ADDBA, if yes then do not create
570 * the stream
571 */
572 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
573 win_size = (block_ack_param_set &
574 IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
575 >> BLOCKACKPARAM_WINSIZE_POS;
576
577 dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM"
578 " tid=%d ssn=%d win_size=%d\n",
579 add_ba_rsp->peer_mac_addr,
580 tid, add_ba_rsp->ssn, win_size);
581 } else {
582 dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
583 add_ba_rsp->peer_mac_addr, tid);
584
585 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv,
586 tid, add_ba_rsp->peer_mac_addr);
587 if (rx_reor_tbl_ptr)
588 mwifiex_11n_delete_rx_reorder_tbl_entry(priv,
589 rx_reor_tbl_ptr);
590 }
591
592 return 0;
593}
594
595/*
596 * This function handles BA stream timeout event by preparing and sending
597 * a command to the firmware.
598 */
599void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
600 struct host_cmd_ds_11n_batimeout *event)
601{
602 struct host_cmd_ds_11n_delba delba;
603
604 memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
605 memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
606
607 delba.del_ba_param_set |=
608 cpu_to_le16((u16) event->tid << DELBA_TID_POS);
609 delba.del_ba_param_set |= cpu_to_le16(
610 (u16) event->origninator << DELBA_INITIATOR_POS);
611 delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
612 mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba);
613
614 return;
615}
616
617/*
618 * This function cleans up the Rx reorder table by deleting all the entries
619 * and re-initializing.
620 */
621void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
622{
623 struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
624 unsigned long flags;
625
626 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
627 list_for_each_entry_safe(del_tbl_ptr, tmp_node,
628 &priv->rx_reorder_tbl_ptr, list) {
629 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
630 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr);
631 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
632 }
633 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
634
635 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
636 memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
637}
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
new file mode 100644
index 000000000000..42f569035745
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -0,0 +1,67 @@
1/*
2 * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_11N_RXREORDER_H_
21#define _MWIFIEX_11N_RXREORDER_H_
22
23#define MIN_FLUSH_TIMER_MS 50
24
25#define PKT_TYPE_BAR 0xE7
26#define MAX_TID_VALUE (2 << 11)
27#define TWOPOW11 (2 << 10)
28
29#define BLOCKACKPARAM_TID_POS 2
30#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
31#define BLOCKACKPARAM_WINSIZE_POS 6
32#define DELBA_TID_POS 12
33#define DELBA_INITIATOR_POS 11
34#define TYPE_DELBA_SENT 1
35#define TYPE_DELBA_RECEIVE 2
36#define IMMEDIATE_BLOCK_ACK 0x2
37
38#define ADDBA_RSP_STATUS_ACCEPT 0
39
40int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
41 u16 seqNum,
42 u16 tid, u8 *ta,
43 u8 pkttype, void *payload);
44void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid,
45 u8 *PeerMACAddr, u8 type,
46 int initiator);
47void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
48 struct host_cmd_ds_11n_batimeout *event);
49int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
50 struct host_cmd_ds_command
51 *resp);
52int mwifiex_cmd_11n_delba(struct mwifiex_private *priv,
53 struct host_cmd_ds_command *cmd,
54 void *data_buf);
55int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
56 struct host_cmd_ds_command
57 *cmd, void *data_buf);
58int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv,
59 struct host_cmd_ds_command *cmd,
60 void *data_buf);
61void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv);
62struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
63 mwifiex_private
64 *priv, int tid,
65 u8 *ta);
66
67#endif /* _MWIFIEX_11N_RXREORDER_H_ */
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
new file mode 100644
index 000000000000..86962920cef3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -0,0 +1,21 @@
1config MWIFIEX
2 tristate "Marvell WiFi-Ex Driver"
3 depends on CFG80211
4 select LIB80211
5 ---help---
6 This adds support for wireless adapters based on Marvell
7 802.11n chipsets.
8
9 If you choose to build it as a module, it will be called
10 mwifiex.
11
12config MWIFIEX_SDIO
13 tristate "Marvell WiFi-Ex Driver for SD8787"
14 depends on MWIFIEX && MMC
15 select FW_LOADER
16 ---help---
17 This adds support for wireless adapters based on Marvell
18 8787 chipset with SDIO interface.
19
20 If you choose to build it as a module, it will be called
21 mwifiex_sdio.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
new file mode 100644
index 000000000000..42cb733ea33a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -0,0 +1,41 @@
1#
2# Copyright (C) 2011, Marvell International Ltd.
3#
4# This software file (the "File") is distributed by Marvell International
5# Ltd. under the terms of the GNU General Public License Version 2, June 1991
6# (the "License"). You may use, redistribute and/or modify this File in
7# accordance with the terms and conditions of the License, a copy of which
8# is available by writing to the Free Software Foundation, Inc.,
9# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
10# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
11#
12# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
13# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
14# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
15# this warranty disclaimer.
16
17
18mwifiex-y += main.o
19mwifiex-y += init.o
20mwifiex-y += cfp.o
21mwifiex-y += cmdevt.o
22mwifiex-y += util.o
23mwifiex-y += txrx.o
24mwifiex-y += wmm.o
25mwifiex-y += 11n.o
26mwifiex-y += 11n_aggr.o
27mwifiex-y += 11n_rxreorder.o
28mwifiex-y += scan.o
29mwifiex-y += join.o
30mwifiex-y += sta_ioctl.o
31mwifiex-y += sta_cmd.o
32mwifiex-y += sta_cmdresp.o
33mwifiex-y += sta_event.o
34mwifiex-y += sta_tx.o
35mwifiex-y += sta_rx.o
36mwifiex-y += cfg80211.o
37mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
38obj-$(CONFIG_MWIFIEX) += mwifiex.o
39
40mwifiex_sdio-y += sdio.o
41obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
new file mode 100644
index 000000000000..338377f7093b
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/README
@@ -0,0 +1,204 @@
1# Copyright (C) 2011, Marvell International Ltd.
2#
3# This software file (the "File") is distributed by Marvell International
4# Ltd. under the terms of the GNU General Public License Version 2, June 1991
5# (the "License"). You may use, redistribute and/or modify this File in
6# accordance with the terms and conditions of the License, a copy of which
7# is available by writing to the Free Software Foundation, Inc.,
8# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
9# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
10#
11# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
12# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
13# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
14# this warranty disclaimer.
15
16
17===============================================================================
18 U S E R M A N U A L
19
201) FOR DRIVER INSTALL
21
22 a) Copy sd8787.bin to /lib/firmware/mrvl/ directory,
23 create the directory if it doesn't exist.
24 b) Install WLAN driver,
25 insmod mwifiex.ko
26 c) Uninstall WLAN driver,
27 ifconfig mlanX down
28 rmmod mwifiex
29
30
312) FOR DRIVER CONFIGURATION AND INFO
32 The configurations can be done either using the 'iw' user space
33 utility or debugfs.
34
35 a) 'iw' utility commands
36
37 Following are some useful iw commands:-
38
39iw dev mlan0 scan
40
41 This command will trigger a scan.
42 The command will then display the scan table entries
43
44iw dev mlan0 connect -w <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1123456789a]
45 The above command can be used to connect to an AP with a particular SSID.
46 Ap's operating frequency can be specified or even the bssid. If the AP is using
47 WEP encryption, wep keys can be specified in the command.
48 Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user.
49
50iw dev mlan0 disconnect
51 This command will be used to disconnect from an AP.
52
53
54iw dev mlan0 ibss join <SSID> <freq in MHz> [fixed-freq] [fixed-bssid] [key 0:abcde]
55 The command will be used to join or create an ibss. Optionally, operating frequency,
56 bssid and the security related parameters can be specified while joining/creating
57 and ibss.
58
59iw dev mlan0 ibss leave
60 The command will be used to leave an ibss network.
61
62iw dev mlan0 link
63 The command will be used to get the connection status. The command will return parameters
64 such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate.
65
66 Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported.
67
68 b) Debugfs interface
69
70 The debugfs interface can be used for configurations and for getting
71 some useful information from the driver.
72 The section below explains the configurations that can be
73 done.
74
75 Mount debugfs to /debugfs mount point:
76
77 mkdir /debugfs
78 mount -t debugfs debugfs /debugfs
79
80 The information is provided in /debugfs/mwifiex/mlanX/:
81
82iw reg set <country code>
83 The command will be used to change the regulatory domain.
84
85iw reg get
86 The command will be used to get current regulatory domain.
87
88info
89 This command is used to get driver info.
90
91 Usage:
92 cat info
93
94 driver_name = "mwifiex"
95 driver_version = <driver_name, driver_version, (firmware_version)>
96 interface_name = "mlanX"
97 bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
98 media_state = "Disconnected" | "Connected"
99 mac_address = <6-byte adapter MAC address>
100 multicase_count = <multicast address count>
101 essid = <current SSID>
102 bssid = <current BSSID>
103 channel = <current channel>
104 region_code = <current region code>
105 multicasr_address[n] = <multicast address>
106 num_tx_bytes = <number of bytes sent to device>
107 num_rx_bytes = <number of bytes received from device and sent to kernel>
108 num_tx_pkts = <number of packets sent to device>
109 num_rx_pkts = <number of packets received from device and sent to kernel>
110 num_tx_pkts_dropped = <number of Tx packets dropped by driver>
111 num_rx_pkts_dropped = <number of Rx packets dropped by driver>
112 num_tx_pkts_err = <number of Tx packets failed to send to device>
113 num_rx_pkts_err = <number of Rx packets failed to receive from device>
114 carrier "on" | "off"
115 tx queue "stopped" | "started"
116
117 The following debug info are provided in /debugfs/mwifiex/mlanX/debug:
118
119 int_counter = <interrupt count, cleared when interrupt handled>
120 wmm_ac_vo = <number of packets sent to device from WMM AcVo queue>
121 wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
122 wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
123 wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
124 max_tx_buf_size = <maximum Tx buffer size>
125 tx_buf_size = <current Tx buffer size>
126 curr_tx_buf_size = <current Tx buffer size>
127 ps_mode = <0/1, CAM mode/PS mode>
128 ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
129 is_deep_sleep = <0/1, not deep sleep state/deep sleep state>
130 wakeup_dev_req = <0/1, wakeup device not required/required>
131 wakeup_tries = <wakeup device count, cleared when device awake>
132 hs_configured = <0/1, host sleep not configured/configured>
133 hs_activated = <0/1, extended host sleep not activated/activated>
134 num_tx_timeout = <number of Tx timeout>
135 num_cmd_timeout = <number of timeout commands>
136 timeout_cmd_id = <command id of the last timeout command>
137 timeout_cmd_act = <command action of the last timeout command>
138 last_cmd_id = <command id of the last several commands sent to device>
139 last_cmd_act = <command action of the last several commands sent to device>
140 last_cmd_index = <0 based last command index>
141 last_cmd_resp_id = <command id of the last several command responses received from device>
142 last_cmd_resp_index = <0 based last command response index>
143 last_event = <event id of the last several events received from device>
144 last_event_index = <0 based last event index>
145 num_cmd_h2c_fail = <number of commands failed to send to device>
146 num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
147 num_tx_h2c_fail = <number of data packets failed to send to device>
148 num_evt_deauth = <number of deauthenticated events received from device>
149 num_evt_disassoc = <number of disassociated events received from device>
150 num_evt_link_lost = <number of link lost events received from device>
151 num_cmd_deauth = <number of deauthenticate commands sent to device>
152 num_cmd_assoc_ok = <number of associate commands with success return>
153 num_cmd_assoc_fail = <number of associate commands with failure return>
154 cmd_sent = <0/1, send command resources available/sending command to device>
155 data_sent = <0/1, send data resources available/sending data to device>
156 mp_rd_bitmap = <SDIO multi-port read bitmap>
157 mp_wr_bitmap = <SDIO multi-port write bitmap>
158 cmd_resp_received = <0/1, no cmd response to process/response received and yet to process>
159 event_received = <0/1, no event to process/event received and yet to process>
160 ioctl_pending = <number of ioctl pending>
161 tx_pending = <number of Tx packet pending>
162 rx_pending = <number of Rx packet pending>
163
164
1653) FOR DRIVER CONFIGURATION
166
167regrdwr
168 This command is used to read/write the adapter register.
169
170 Usage:
171 echo " <type> <offset> [value]" > regrdwr
172 cat regrdwr
173
174 where the parameters are,
175 <type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU
176 <offset>: offset of register
177 [value]: value to be written
178
179 Examples:
180 echo "1 0xa060" > regrdwr : Read the MAC register
181 echo "1 0xa060 0x12" > regrdwr : Write the MAC register
182 echo "1 0xa794 0x80000000" > regrdwr
183 : Write 0x80000000 to MAC register
184rdeeprom
185 This command is used to read the EEPROM contents of the card.
186
187 Usage:
188 echo "<offset> <length>" > rdeeprom
189 cat rdeeprom
190
191 where the parameters are,
192 <offset>: multiples of 4
193 <length>: 4-20, multiples of 4
194
195 Example:
196 echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0
197
198getlog
199 This command is used to get the statistics available in the station.
200 Usage:
201
202 cat getlog
203
204===============================================================================
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
new file mode 100644
index 000000000000..80f367f27efc
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -0,0 +1,1517 @@
1/*
2 * Marvell Wireless LAN device driver: CFG80211
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "cfg80211.h"
21#include "main.h"
22
23/*
24 * This function maps the nl802.11 channel type into driver channel type.
25 *
26 * The mapping is as follows -
27 * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL
28 * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL
29 * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE
30 * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW
31 * Others -> NO_SEC_CHANNEL
32 */
33static int
34mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type
35 channel_type)
36{
37 int channel;
38 switch (channel_type) {
39 case NL80211_CHAN_NO_HT:
40 case NL80211_CHAN_HT20:
41 channel = NO_SEC_CHANNEL;
42 break;
43 case NL80211_CHAN_HT40PLUS:
44 channel = SEC_CHANNEL_ABOVE;
45 break;
46 case NL80211_CHAN_HT40MINUS:
47 channel = SEC_CHANNEL_BELOW;
48 break;
49 default:
50 channel = NO_SEC_CHANNEL;
51 }
52 return channel;
53}
54
55/*
56 * This function maps the driver channel type into nl802.11 channel type.
57 *
58 * The mapping is as follows -
59 * NO_SEC_CHANNEL -> NL80211_CHAN_HT20
60 * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS
61 * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS
62 * Others -> NL80211_CHAN_HT20
63 */
64static enum nl80211_channel_type
65mwifiex_channels_to_cfg80211_channel_type(int channel_type)
66{
67 int channel;
68 switch (channel_type) {
69 case NO_SEC_CHANNEL:
70 channel = NL80211_CHAN_HT20;
71 break;
72 case SEC_CHANNEL_ABOVE:
73 channel = NL80211_CHAN_HT40PLUS;
74 break;
75 case SEC_CHANNEL_BELOW:
76 channel = NL80211_CHAN_HT40MINUS;
77 break;
78 default:
79 channel = NL80211_CHAN_HT20;
80 }
81 return channel;
82}
83
84/*
85 * This function checks whether WEP is set.
86 */
87static int
88mwifiex_is_alg_wep(u32 cipher)
89{
90 int alg = 0;
91
92 switch (cipher) {
93 case MWIFIEX_ENCRYPTION_MODE_WEP40:
94 case MWIFIEX_ENCRYPTION_MODE_WEP104:
95 alg = 1;
96 break;
97 default:
98 alg = 0;
99 break;
100 }
101 return alg;
102}
103
104/*
105 * This function maps the given cipher type into driver specific type.
106 *
107 * It also sets a flag to indicate whether WPA is enabled or not.
108 *
109 * The mapping table is -
110 * Input cipher Driver cipher type WPA enabled?
111 * ------------ ------------------ ------------
112 * IW_AUTH_CIPHER_NONE MWIFIEX_ENCRYPTION_MODE_NONE No
113 * WLAN_CIPHER_SUITE_WEP40 MWIFIEX_ENCRYPTION_MODE_WEP40 No
114 * WLAN_CIPHER_SUITE_WEP104 MWIFIEX_ENCRYPTION_MODE_WEP104 No
115 * WLAN_CIPHER_SUITE_TKIP MWIFIEX_ENCRYPTION_MODE_TKIP Yes
116 * WLAN_CIPHER_SUITE_CCMP MWIFIEX_ENCRYPTION_MODE_CCMP Yes
117 * Others -1 No
118 */
119static int
120mwifiex_get_mwifiex_cipher(u32 cipher, int *wpa_enabled)
121{
122 int encrypt_mode;
123
124 if (wpa_enabled)
125 *wpa_enabled = 0;
126 switch (cipher) {
127 case IW_AUTH_CIPHER_NONE:
128 encrypt_mode = MWIFIEX_ENCRYPTION_MODE_NONE;
129 break;
130 case WLAN_CIPHER_SUITE_WEP40:
131 encrypt_mode = MWIFIEX_ENCRYPTION_MODE_WEP40;
132 break;
133 case WLAN_CIPHER_SUITE_WEP104:
134 encrypt_mode = MWIFIEX_ENCRYPTION_MODE_WEP104;
135 break;
136 case WLAN_CIPHER_SUITE_TKIP:
137 encrypt_mode = MWIFIEX_ENCRYPTION_MODE_TKIP;
138 if (wpa_enabled)
139 *wpa_enabled = 1;
140 break;
141 case WLAN_CIPHER_SUITE_CCMP:
142 encrypt_mode = MWIFIEX_ENCRYPTION_MODE_CCMP;
143 if (wpa_enabled)
144 *wpa_enabled = 1;
145 break;
146 default:
147 encrypt_mode = -1;
148 }
149
150 return encrypt_mode;
151}
152
153/*
154 * This function retrieves the private structure from kernel wiphy structure.
155 */
156static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
157{
158 return (void *) (*(unsigned long *) wiphy_priv(wiphy));
159}
160
161/*
162 * CFG802.11 operation handler to delete a network key.
163 */
164static int
165mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
166 u8 key_index, bool pairwise, const u8 *mac_addr)
167{
168 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
169 int ret = 0;
170
171 ret = mwifiex_set_encode(priv, NULL, 0, key_index, 1);
172 if (ret) {
173 wiphy_err(wiphy, "deleting the crypto keys\n");
174 return -EFAULT;
175 }
176
177 wiphy_dbg(wiphy, "info: crypto keys deleted\n");
178 return 0;
179}
180
181/*
182 * CFG802.11 operation handler to set Tx power.
183 */
184static int
185mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
186 enum nl80211_tx_power_setting type,
187 int dbm)
188{
189 int ret = 0;
190 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
191
192 ret = mwifiex_set_tx_power(priv, type, dbm);
193
194 return ret;
195}
196
197/*
198 * CFG802.11 operation handler to set Power Save option.
199 *
200 * The timeout value, if provided, is currently ignored.
201 */
202static int
203mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
204 struct net_device *dev,
205 bool enabled, int timeout)
206{
207 int ret = 0;
208 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
209
210 if (timeout)
211 wiphy_dbg(wiphy,
212 "info: ignoring the timeout value"
213 " for IEEE power save\n");
214
215 ret = mwifiex_drv_set_power(priv, enabled);
216
217 return ret;
218}
219
220/*
221 * CFG802.11 operation handler to set the default network key.
222 */
223static int
224mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
225 u8 key_index, bool unicast,
226 bool multicast)
227{
228 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
229 int ret;
230
231 ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0);
232
233 wiphy_dbg(wiphy, "info: set default Tx key index\n");
234
235 if (ret)
236 return -EFAULT;
237
238 return 0;
239}
240
241/*
242 * CFG802.11 operation handler to add a network key.
243 */
244static int
245mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
246 u8 key_index, bool pairwise, const u8 *mac_addr,
247 struct key_params *params)
248{
249 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
250 int ret = 0;
251 int encrypt_mode;
252
253 encrypt_mode = mwifiex_get_mwifiex_cipher(params->cipher, NULL);
254
255 if (encrypt_mode != -1)
256 ret = mwifiex_set_encode(priv, params->key, params->key_len,
257 key_index, 0);
258
259 wiphy_dbg(wiphy, "info: crypto keys added\n");
260
261 if (ret)
262 return -EFAULT;
263
264 return 0;
265}
266
267/*
268 * This function sends domain information to the firmware.
269 *
270 * The following information are passed to the firmware -
271 * - Country codes
272 * - Sub bands (first channel, number of channels, maximum Tx power)
273 */
274static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
275{
276 u8 no_of_triplet = 0;
277 struct ieee80211_country_ie_triplet *t;
278 u8 no_of_parsed_chan = 0;
279 u8 first_chan = 0, next_chan = 0, max_pwr = 0;
280 u8 i, flag = 0;
281 enum ieee80211_band band;
282 struct ieee80211_supported_band *sband;
283 struct ieee80211_channel *ch;
284 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
285 struct mwifiex_adapter *adapter = priv->adapter;
286 struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
287 int ret = 0;
288
289 /* Set country code */
290 domain_info->country_code[0] = priv->country_code[0];
291 domain_info->country_code[1] = priv->country_code[1];
292 domain_info->country_code[2] = ' ';
293
294 band = mwifiex_band_to_radio_type(adapter->config_bands);
295 if (!wiphy->bands[band]) {
296 wiphy_err(wiphy, "11D: setting domain info in FW\n");
297 return -1;
298 }
299
300 sband = wiphy->bands[band];
301
302 for (i = 0; i < sband->n_channels ; i++) {
303 ch = &sband->channels[i];
304 if (ch->flags & IEEE80211_CHAN_DISABLED)
305 continue;
306
307 if (!flag) {
308 flag = 1;
309 first_chan = (u32) ch->hw_value;
310 next_chan = first_chan;
311 max_pwr = ch->max_power;
312 no_of_parsed_chan = 1;
313 continue;
314 }
315
316 if (ch->hw_value == next_chan + 1 &&
317 ch->max_power == max_pwr) {
318 next_chan++;
319 no_of_parsed_chan++;
320 } else {
321 t = &domain_info->triplet[no_of_triplet];
322 t->chans.first_channel = first_chan;
323 t->chans.num_channels = no_of_parsed_chan;
324 t->chans.max_power = max_pwr;
325 no_of_triplet++;
326 first_chan = (u32) ch->hw_value;
327 next_chan = first_chan;
328 max_pwr = ch->max_power;
329 no_of_parsed_chan = 1;
330 }
331 }
332
333 if (flag) {
334 t = &domain_info->triplet[no_of_triplet];
335 t->chans.first_channel = first_chan;
336 t->chans.num_channels = no_of_parsed_chan;
337 t->chans.max_power = max_pwr;
338 no_of_triplet++;
339 }
340
341 domain_info->no_of_triplet = no_of_triplet;
342 /* Send cmd to FW to set domain info */
343 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
344 HostCmd_ACT_GEN_SET, 0, NULL, NULL);
345 if (ret)
346 wiphy_err(wiphy, "11D: setting domain info in FW\n");
347
348 return ret;
349}
350
351/*
352 * CFG802.11 regulatory domain callback function.
353 *
354 * This function is called when the regulatory domain is changed due to the
355 * following reasons -
356 * - Set by driver
357 * - Set by system core
358 * - Set by user
359 * - Set bt Country IE
360 */
361static int mwifiex_reg_notifier(struct wiphy *wiphy,
362 struct regulatory_request *request)
363{
364 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
365
366 wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
367 " %c%c\n", request->alpha2[0], request->alpha2[1]);
368
369 memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
370
371 switch (request->initiator) {
372 case NL80211_REGDOM_SET_BY_DRIVER:
373 case NL80211_REGDOM_SET_BY_CORE:
374 case NL80211_REGDOM_SET_BY_USER:
375 break;
376 /* Todo: apply driver specific changes in channel flags based
377 on the request initiator if necessary. */
378 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
379 break;
380 }
381 mwifiex_send_domain_info_cmd_fw(wiphy);
382
383 return 0;
384}
385
386/*
387 * This function sets the RF channel.
388 *
389 * This function creates multiple IOCTL requests, populates them accordingly
390 * and issues them to set the band/channel and frequency.
391 */
392static int
393mwifiex_set_rf_channel(struct mwifiex_private *priv,
394 struct ieee80211_channel *chan,
395 enum nl80211_channel_type channel_type)
396{
397 struct mwifiex_chan_freq_power cfp;
398 int ret = 0;
399 int status = 0;
400 struct mwifiex_ds_band_cfg band_cfg;
401 int mode;
402 u8 wait_option = MWIFIEX_IOCTL_WAIT;
403 u32 config_bands = 0;
404 struct wiphy *wiphy = priv->wdev->wiphy;
405
406 mode = mwifiex_drv_get_mode(priv, wait_option);
407
408 if (chan) {
409 memset(&band_cfg, 0, sizeof(band_cfg));
410 /* Set appropriate bands */
411 if (chan->band == IEEE80211_BAND_2GHZ)
412 config_bands = BAND_B | BAND_G | BAND_GN;
413 else
414 config_bands = BAND_AN | BAND_A;
415 if (mode == MWIFIEX_BSS_MODE_INFRA
416 || mode == MWIFIEX_BSS_MODE_AUTO) {
417 band_cfg.config_bands = config_bands;
418 } else if (mode == MWIFIEX_BSS_MODE_IBSS) {
419 band_cfg.config_bands = config_bands;
420 band_cfg.adhoc_start_band = config_bands;
421 }
422 /* Set channel offset */
423 band_cfg.sec_chan_offset =
424 mwifiex_cfg80211_channel_type_to_mwifiex_channels
425 (channel_type);
426 status = mwifiex_radio_ioctl_band_cfg(priv, HostCmd_ACT_GEN_SET,
427 &band_cfg);
428
429 if (status)
430 return -EFAULT;
431 mwifiex_send_domain_info_cmd_fw(wiphy);
432 }
433
434 wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and "
435 "mode %d\n", config_bands, band_cfg.sec_chan_offset, mode);
436 if (!chan)
437 return ret;
438
439 memset(&cfp, 0, sizeof(cfp));
440 cfp.freq = chan->center_freq;
441 /* Convert frequency to channel */
442 cfp.channel = ieee80211_frequency_to_channel(chan->center_freq);
443
444 status = mwifiex_bss_ioctl_channel(priv, HostCmd_ACT_GEN_SET, &cfp);
445 if (status)
446 return -EFAULT;
447
448 ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
449
450 return ret;
451}
452
453/*
454 * CFG802.11 operation handler to set channel.
455 *
456 * This function can only be used when station is not connected.
457 */
458static int
459mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
460 struct ieee80211_channel *chan,
461 enum nl80211_channel_type channel_type)
462{
463 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
464
465 if (priv->media_connected) {
466 wiphy_err(wiphy, "This setting is valid only when station "
467 "is not connected\n");
468 return -EINVAL;
469 }
470
471 return mwifiex_set_rf_channel(priv, chan, channel_type);
472}
473
474/*
475 * This function sets the fragmentation threshold.
476 *
477 * This function creates an IOCTL request, populates it accordingly
478 * and issues an IOCTL.
479 *
480 * The fragmentation threshold value must lies between MWIFIEX_FRAG_MIN_VALUE
481 * and MWIFIEX_FRAG_MAX_VALUE.
482 */
483static int
484mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
485{
486 int ret = 0;
487 int status = 0;
488 struct mwifiex_wait_queue *wait = NULL;
489 u8 wait_option = MWIFIEX_IOCTL_WAIT;
490
491 if (frag_thr < MWIFIEX_FRAG_MIN_VALUE
492 || frag_thr > MWIFIEX_FRAG_MAX_VALUE)
493 return -EINVAL;
494
495 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
496 if (!wait)
497 return -ENOMEM;
498
499 status = mwifiex_snmp_mib_ioctl(priv, wait, FRAG_THRESH_I,
500 HostCmd_ACT_GEN_SET, &frag_thr);
501
502 if (mwifiex_request_ioctl(priv, wait, status, wait_option))
503 ret = -EFAULT;
504
505 kfree(wait);
506 return ret;
507}
508
509/*
510 * This function sets the RTS threshold.
511 *
512 * This function creates an IOCTL request, populates it accordingly
513 * and issues an IOCTL.
514 */
515static int
516mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
517{
518 int ret = 0;
519 struct mwifiex_wait_queue *wait = NULL;
520 int status = 0;
521 u8 wait_option = MWIFIEX_IOCTL_WAIT;
522
523 if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
524 rts_thr = MWIFIEX_RTS_MAX_VALUE;
525
526 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
527 if (!wait)
528 return -ENOMEM;
529
530 status = mwifiex_snmp_mib_ioctl(priv, wait, RTS_THRESH_I,
531 HostCmd_ACT_GEN_SET, &rts_thr);
532
533 if (mwifiex_request_ioctl(priv, wait, status, wait_option))
534 ret = -EFAULT;
535
536 kfree(wait);
537 return ret;
538}
539
540/*
541 * CFG802.11 operation handler to set wiphy parameters.
542 *
543 * This function can be used to set the RTS threshold and the
544 * Fragmentation threshold of the driver.
545 */
546static int
547mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
548{
549 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
550
551 int ret = 0;
552
553 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
554 ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
555
556 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
557 ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
558
559 return ret;
560}
561
562/*
563 * CFG802.11 operation handler to change interface type.
564 *
565 * This function creates an IOCTL request, populates it accordingly
566 * and issues an IOCTL.
567 *
568 * The function also maps the CFG802.11 mode type into driver mode type.
569 * NL80211_IFTYPE_ADHOC -> MWIFIEX_BSS_MODE_IBSS
570 * NL80211_IFTYPE_STATION -> MWIFIEX_BSS_MODE_INFRA
571 * NL80211_IFTYPE_UNSPECIFIED -> MWIFIEX_BSS_MODE_AUTO
572 */
573static int
574mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
575 struct net_device *dev,
576 enum nl80211_iftype type, u32 *flags,
577 struct vif_params *params)
578{
579 int ret = 0;
580 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
581 int mode = -1;
582 struct mwifiex_wait_queue *wait = NULL;
583 int status = 0;
584
585 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
586 if (!wait)
587 return -ENOMEM;
588
589 switch (type) {
590 case NL80211_IFTYPE_ADHOC:
591 mode = MWIFIEX_BSS_MODE_IBSS;
592 dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
593 wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
594 break;
595 case NL80211_IFTYPE_STATION:
596 mode = MWIFIEX_BSS_MODE_INFRA;
597 dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
598 wiphy_dbg(wiphy, "info: Setting interface type to managed\n");
599 break;
600 case NL80211_IFTYPE_UNSPECIFIED:
601 mode = MWIFIEX_BSS_MODE_AUTO;
602 dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
603 wiphy_dbg(wiphy, "info: setting interface type to auto\n");
604 break;
605 default:
606 ret = -EINVAL;
607 }
608 if (ret)
609 goto done;
610 status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_SET, &mode);
611
612 if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT))
613 ret = -EFAULT;
614
615done:
616 kfree(wait);
617 return ret;
618}
619
620/*
621 * This function dumps the station information on a buffer.
622 *
623 * The following information are shown -
624 * - Total bytes transmitted
625 * - Total bytes received
626 * - Total packets transmitted
627 * - Total packets received
628 * - Signal quality level
629 * - Transmission rate
630 */
631static int
632mwifiex_dump_station_info(struct mwifiex_private *priv,
633 struct station_info *sinfo)
634{
635 struct mwifiex_ds_get_signal signal;
636 struct mwifiex_rate_cfg rate;
637 int ret = 0;
638
639 sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
640 STATION_INFO_RX_PACKETS |
641 STATION_INFO_TX_PACKETS
642 | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
643
644 /* Get signal information from the firmware */
645 memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal));
646 if (mwifiex_get_signal_info(priv, MWIFIEX_IOCTL_WAIT, &signal)) {
647 dev_err(priv->adapter->dev, "getting signal information\n");
648 ret = -EFAULT;
649 }
650
651 if (mwifiex_drv_get_data_rate(priv, &rate)) {
652 dev_err(priv->adapter->dev, "getting data rate\n");
653 ret = -EFAULT;
654 }
655
656 sinfo->rx_bytes = priv->stats.rx_bytes;
657 sinfo->tx_bytes = priv->stats.tx_bytes;
658 sinfo->rx_packets = priv->stats.rx_packets;
659 sinfo->tx_packets = priv->stats.tx_packets;
660 sinfo->signal = priv->w_stats.qual.level;
661 sinfo->txrate.legacy = rate.rate;
662
663 return ret;
664}
665
666/*
667 * CFG802.11 operation handler to get station information.
668 *
669 * This function only works in connected mode, and dumps the
670 * requested station information, if available.
671 */
672static int
673mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
674 u8 *mac, struct station_info *sinfo)
675{
676 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
677 int ret = 0;
678
679 mwifiex_dump_station_info(priv, sinfo);
680
681 if (!priv->media_connected)
682 return -ENOENT;
683 if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
684 return -ENOENT;
685
686
687 ret = mwifiex_dump_station_info(priv, sinfo);
688
689 return ret;
690}
691
692/* Supported rates to be advertised to the cfg80211 */
693
694static struct ieee80211_rate mwifiex_rates[] = {
695 {.bitrate = 10, .hw_value = 2, },
696 {.bitrate = 20, .hw_value = 4, },
697 {.bitrate = 55, .hw_value = 11, },
698 {.bitrate = 110, .hw_value = 22, },
699 {.bitrate = 220, .hw_value = 44, },
700 {.bitrate = 60, .hw_value = 12, },
701 {.bitrate = 90, .hw_value = 18, },
702 {.bitrate = 120, .hw_value = 24, },
703 {.bitrate = 180, .hw_value = 36, },
704 {.bitrate = 240, .hw_value = 48, },
705 {.bitrate = 360, .hw_value = 72, },
706 {.bitrate = 480, .hw_value = 96, },
707 {.bitrate = 540, .hw_value = 108, },
708 {.bitrate = 720, .hw_value = 144, },
709};
710
711/* Channel definitions to be advertised to cfg80211 */
712
713static struct ieee80211_channel mwifiex_channels_2ghz[] = {
714 {.center_freq = 2412, .hw_value = 1, },
715 {.center_freq = 2417, .hw_value = 2, },
716 {.center_freq = 2422, .hw_value = 3, },
717 {.center_freq = 2427, .hw_value = 4, },
718 {.center_freq = 2432, .hw_value = 5, },
719 {.center_freq = 2437, .hw_value = 6, },
720 {.center_freq = 2442, .hw_value = 7, },
721 {.center_freq = 2447, .hw_value = 8, },
722 {.center_freq = 2452, .hw_value = 9, },
723 {.center_freq = 2457, .hw_value = 10, },
724 {.center_freq = 2462, .hw_value = 11, },
725 {.center_freq = 2467, .hw_value = 12, },
726 {.center_freq = 2472, .hw_value = 13, },
727 {.center_freq = 2484, .hw_value = 14, },
728};
729
730static struct ieee80211_supported_band mwifiex_band_2ghz = {
731 .channels = mwifiex_channels_2ghz,
732 .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz),
733 .bitrates = mwifiex_rates,
734 .n_bitrates = 14,
735};
736
737static struct ieee80211_channel mwifiex_channels_5ghz[] = {
738 {.center_freq = 5040, .hw_value = 8, },
739 {.center_freq = 5060, .hw_value = 12, },
740 {.center_freq = 5080, .hw_value = 16, },
741 {.center_freq = 5170, .hw_value = 34, },
742 {.center_freq = 5190, .hw_value = 38, },
743 {.center_freq = 5210, .hw_value = 42, },
744 {.center_freq = 5230, .hw_value = 46, },
745 {.center_freq = 5180, .hw_value = 36, },
746 {.center_freq = 5200, .hw_value = 40, },
747 {.center_freq = 5220, .hw_value = 44, },
748 {.center_freq = 5240, .hw_value = 48, },
749 {.center_freq = 5260, .hw_value = 52, },
750 {.center_freq = 5280, .hw_value = 56, },
751 {.center_freq = 5300, .hw_value = 60, },
752 {.center_freq = 5320, .hw_value = 64, },
753 {.center_freq = 5500, .hw_value = 100, },
754 {.center_freq = 5520, .hw_value = 104, },
755 {.center_freq = 5540, .hw_value = 108, },
756 {.center_freq = 5560, .hw_value = 112, },
757 {.center_freq = 5580, .hw_value = 116, },
758 {.center_freq = 5600, .hw_value = 120, },
759 {.center_freq = 5620, .hw_value = 124, },
760 {.center_freq = 5640, .hw_value = 128, },
761 {.center_freq = 5660, .hw_value = 132, },
762 {.center_freq = 5680, .hw_value = 136, },
763 {.center_freq = 5700, .hw_value = 140, },
764 {.center_freq = 5745, .hw_value = 149, },
765 {.center_freq = 5765, .hw_value = 153, },
766 {.center_freq = 5785, .hw_value = 157, },
767 {.center_freq = 5805, .hw_value = 161, },
768 {.center_freq = 5825, .hw_value = 165, },
769};
770
771static struct ieee80211_supported_band mwifiex_band_5ghz = {
772 .channels = mwifiex_channels_5ghz,
773 .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz),
774 .bitrates = mwifiex_rates - 4,
775 .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4,
776};
777
778
779/* Supported crypto cipher suits to be advertised to cfg80211 */
780
781static const u32 mwifiex_cipher_suites[] = {
782 WLAN_CIPHER_SUITE_WEP40,
783 WLAN_CIPHER_SUITE_WEP104,
784 WLAN_CIPHER_SUITE_TKIP,
785 WLAN_CIPHER_SUITE_CCMP,
786};
787
788/*
789 * CFG802.11 operation handler for disconnection request.
790 *
791 * This function does not work when there is already a disconnection
792 * procedure going on.
793 */
794static int
795mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
796 u16 reason_code)
797{
798 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
799
800 if (priv->disconnect)
801 return -EBUSY;
802
803 priv->disconnect = 1;
804 if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL))
805 return -EFAULT;
806
807 wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
808 " reason code %d\n", priv->cfg_bssid, reason_code);
809
810 queue_work(priv->workqueue, &priv->cfg_workqueue);
811
812 return 0;
813}
814
815/*
816 * This function informs the CFG802.11 subsystem of a new IBSS.
817 *
818 * The following information are sent to the CFG802.11 subsystem
819 * to register the new IBSS. If we do not register the new IBSS,
820 * a kernel panic will result.
821 * - SSID
822 * - SSID length
823 * - BSSID
824 * - Channel
825 */
826static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
827{
828 int ret = 0;
829 struct ieee80211_channel *chan;
830 struct mwifiex_bss_info bss_info;
831 int ie_len = 0;
832 u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
833
834 ret = mwifiex_get_bss_info(priv, &bss_info);
835 if (ret)
836 return ret;
837
838 ie_buf[0] = WLAN_EID_SSID;
839 ie_buf[1] = bss_info.ssid.ssid_len;
840
841 memcpy(&ie_buf[sizeof(struct ieee_types_header)],
842 &bss_info.ssid.ssid,
843 bss_info.ssid.ssid_len);
844 ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
845
846 chan = __ieee80211_get_channel(priv->wdev->wiphy,
847 ieee80211_channel_to_frequency(bss_info.bss_chan,
848 priv->curr_bss_params.band));
849
850 cfg80211_inform_bss(priv->wdev->wiphy, chan,
851 bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
852 0, ie_buf, ie_len, 0, GFP_KERNEL);
853 memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
854
855 return ret;
856}
857
858/*
859 * This function informs the CFG802.11 subsystem of a new BSS connection.
860 *
861 * The following information are sent to the CFG802.11 subsystem
862 * to register the new BSS connection. If we do not register the new BSS,
863 * a kernel panic will result.
864 * - MAC address
865 * - Capabilities
866 * - Beacon period
867 * - RSSI value
868 * - Channel
869 * - Supported rates IE
870 * - Extended capabilities IE
871 * - DS parameter set IE
872 * - HT Capability IE
873 * - Vendor Specific IE (221)
874 * - WPA IE
875 * - RSN IE
876 */
877static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
878 struct mwifiex_802_11_ssid *ssid)
879{
880 struct mwifiex_scan_resp scan_resp;
881 struct mwifiex_bssdescriptor *scan_table;
882 int i, j;
883 struct ieee80211_channel *chan;
884 u8 *ie, *tmp, *ie_buf;
885 u32 ie_len;
886 u64 ts = 0;
887 u8 *beacon;
888 int beacon_size;
889 u8 element_id, element_len;
890
891 memset(&scan_resp, 0, sizeof(scan_resp));
892 if (mwifiex_get_scan_table(priv, MWIFIEX_IOCTL_WAIT, &scan_resp))
893 return -EFAULT;
894
895#define MAX_IE_BUF 2048
896 ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
897 if (!ie_buf) {
898 dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n",
899 __func__);
900 return -ENOMEM;
901 }
902
903 scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table;
904 for (i = 0; i < scan_resp.num_in_scan_table; i++) {
905 if (ssid) {
906 /* Inform specific BSS only */
907 if (memcmp(ssid->ssid, scan_table[i].ssid.ssid,
908 ssid->ssid_len))
909 continue;
910 }
911 memset(ie_buf, 0, MAX_IE_BUF);
912 ie_buf[0] = WLAN_EID_SSID;
913 ie_buf[1] = scan_table[i].ssid.ssid_len;
914 memcpy(&ie_buf[sizeof(struct ieee_types_header)],
915 scan_table[i].ssid.ssid, ie_buf[1]);
916
917 ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header);
918 ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
919
920 ie[0] = WLAN_EID_SUPP_RATES;
921
922 for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
923 if (!scan_table[i].supported_rates[j])
924 break;
925 else
926 ie[j + sizeof(struct ieee_types_header)] =
927 scan_table[i].supported_rates[j];
928 }
929
930 ie[1] = j;
931 ie_len += ie[1] + sizeof(struct ieee_types_header);
932
933 beacon = scan_table[i].beacon_buf;
934 beacon_size = scan_table[i].beacon_buf_size;
935
936 /* Skip time stamp, beacon interval and capability */
937
938 if (beacon) {
939 beacon += sizeof(scan_table[i].beacon_period)
940 + sizeof(scan_table[i].time_stamp) +
941 +sizeof(scan_table[i].cap_info_bitmap);
942
943 beacon_size -= sizeof(scan_table[i].beacon_period)
944 + sizeof(scan_table[i].time_stamp)
945 + sizeof(scan_table[i].cap_info_bitmap);
946 }
947
948 while (beacon_size >= sizeof(struct ieee_types_header)) {
949 ie = ie_buf + ie_len;
950 element_id = *beacon;
951 element_len = *(beacon + 1);
952 if (beacon_size < (int) element_len +
953 sizeof(struct ieee_types_header)) {
954 dev_err(priv->adapter->dev, "%s: in processing"
955 " IE, bytes left < IE length\n",
956 __func__);
957 break;
958 }
959 switch (element_id) {
960 case WLAN_EID_EXT_CAPABILITY:
961 case WLAN_EID_DS_PARAMS:
962 case WLAN_EID_HT_CAPABILITY:
963 case WLAN_EID_VENDOR_SPECIFIC:
964 case WLAN_EID_RSN:
965 case WLAN_EID_BSS_AC_ACCESS_DELAY:
966 ie[0] = element_id;
967 ie[1] = element_len;
968 tmp = (u8 *) beacon;
969 memcpy(&ie[sizeof(struct ieee_types_header)],
970 tmp + sizeof(struct ieee_types_header),
971 element_len);
972 ie_len += ie[1] +
973 sizeof(struct ieee_types_header);
974 break;
975 default:
976 break;
977 }
978 beacon += element_len +
979 sizeof(struct ieee_types_header);
980 beacon_size -= element_len +
981 sizeof(struct ieee_types_header);
982 }
983 chan = ieee80211_get_channel(priv->wdev->wiphy,
984 scan_table[i].freq);
985 cfg80211_inform_bss(priv->wdev->wiphy, chan,
986 scan_table[i].mac_address,
987 ts, scan_table[i].cap_info_bitmap,
988 scan_table[i].beacon_period,
989 ie_buf, ie_len,
990 scan_table[i].rssi, GFP_KERNEL);
991 }
992
993 kfree(ie_buf);
994 return 0;
995}
996
997/*
998 * This function connects with a BSS.
999 *
1000 * This function handles both Infra and Ad-Hoc modes. It also performs
1001 * validity checking on the provided parameters, disconnects from the
1002 * current BSS (if any), sets up the association/scan parameters,
1003 * including security settings, and performs specific SSID scan before
1004 * trying to connect.
1005 *
1006 * For Infra mode, the function returns failure if the specified SSID
1007 * is not found in scan table. However, for Ad-Hoc mode, it can create
1008 * the IBSS if it does not exist. On successful completion in either case,
1009 * the function notifies the CFG802.11 subsystem of the new BSS connection,
1010 * otherwise the kernel will panic.
1011 */
1012static int
1013mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
1014 u8 *bssid, int mode, struct ieee80211_channel *channel,
1015 struct cfg80211_connect_params *sme, bool privacy)
1016{
1017 struct mwifiex_802_11_ssid req_ssid;
1018 struct mwifiex_ssid_bssid ssid_bssid;
1019 int ret = 0;
1020 int auth_type = 0, pairwise_encrypt_mode = 0, wpa_enabled = 0;
1021 int group_encrypt_mode = 0;
1022 int alg_is_wep = 0;
1023
1024 memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
1025 memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
1026
1027 req_ssid.ssid_len = ssid_len;
1028 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
1029 dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
1030 return -EINVAL;
1031 }
1032
1033 memcpy(req_ssid.ssid, ssid, ssid_len);
1034 if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
1035 dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
1036 return -EINVAL;
1037 }
1038
1039 /* disconnect before try to associate */
1040 mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL);
1041
1042 if (channel)
1043 ret = mwifiex_set_rf_channel(priv, channel,
1044 mwifiex_channels_to_cfg80211_channel_type
1045 (priv->adapter->chan_offset));
1046
1047 ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */
1048
1049 if (mode == MWIFIEX_BSS_MODE_IBSS) {
1050 /* "privacy" is set only for ad-hoc mode */
1051 if (privacy) {
1052 /*
1053 * Keep MWIFIEX_ENCRYPTION_MODE_WEP104 for now so that
1054 * the firmware can find a matching network from the
1055 * scan. The cfg80211 does not give us the encryption
1056 * mode at this stage so just setting it to WEP here.
1057 */
1058 wpa_enabled = 0;
1059 auth_type = MWIFIEX_AUTH_MODE_OPEN;
1060 ret = mwifiex_set_auth(priv,
1061 MWIFIEX_ENCRYPTION_MODE_WEP104,
1062 auth_type, wpa_enabled);
1063 }
1064
1065 goto done;
1066 }
1067
1068 /* Now handle infra mode. "sme" is valid for infra mode only */
1069 if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC
1070 || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
1071 auth_type = MWIFIEX_AUTH_MODE_OPEN;
1072 else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
1073 auth_type = MWIFIEX_AUTH_MODE_SHARED;
1074
1075 if (sme->crypto.n_ciphers_pairwise) {
1076 pairwise_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto.
1077 ciphers_pairwise[0], &wpa_enabled);
1078 ret = mwifiex_set_auth(priv, pairwise_encrypt_mode, auth_type,
1079 wpa_enabled);
1080 }
1081
1082 if (sme->crypto.cipher_group) {
1083 group_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto.
1084 cipher_group, &wpa_enabled);
1085 ret = mwifiex_set_auth(priv, group_encrypt_mode, auth_type,
1086 wpa_enabled);
1087 }
1088 if (sme->ie)
1089 ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);
1090
1091 if (sme->key) {
1092 alg_is_wep = mwifiex_is_alg_wep(pairwise_encrypt_mode)
1093 | mwifiex_is_alg_wep(group_encrypt_mode);
1094 if (alg_is_wep) {
1095 dev_dbg(priv->adapter->dev,
1096 "info: setting wep encryption"
1097 " with key len %d\n", sme->key_len);
1098 ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
1099 sme->key_idx, 0);
1100 }
1101 }
1102done:
1103 /* Do specific SSID scanning */
1104 if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &req_ssid)) {
1105 dev_err(priv->adapter->dev, "scan error\n");
1106 return -EFAULT;
1107 }
1108
1109
1110 memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid));
1111
1112 if (mode != MWIFIEX_BSS_MODE_IBSS) {
1113 if (mwifiex_find_best_bss(priv, MWIFIEX_IOCTL_WAIT,
1114 &ssid_bssid))
1115 return -EFAULT;
1116 /* Inform the BSS information to kernel, otherwise
1117 * kernel will give a panic after successful assoc */
1118 if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid))
1119 return -EFAULT;
1120 }
1121
1122 dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
1123 (char *) req_ssid.ssid, ssid_bssid.bssid);
1124
1125 memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6);
1126
1127 /* Connect to BSS by ESSID */
1128 memset(&ssid_bssid.bssid, 0, ETH_ALEN);
1129
1130 if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid))
1131 return -EFAULT;
1132
1133 if (mode == MWIFIEX_BSS_MODE_IBSS) {
1134 /* Inform the BSS information to kernel, otherwise
1135 * kernel will give a panic after successful assoc */
1136 if (mwifiex_cfg80211_inform_ibss_bss(priv))
1137 return -EFAULT;
1138 }
1139
1140 return ret;
1141}
1142
1143/*
1144 * CFG802.11 operation handler for association request.
1145 *
1146 * This function does not work when the current mode is set to Ad-Hoc, or
1147 * when there is already an association procedure going on. The given BSS
1148 * information is used to associate.
1149 */
1150static int
1151mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
1152 struct cfg80211_connect_params *sme)
1153{
1154 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
1155 int ret = 0;
1156 int mode = 0;
1157
1158 if (priv->assoc_request)
1159 return -EBUSY;
1160
1161 mode = mwifiex_drv_get_mode(priv, MWIFIEX_IOCTL_WAIT);
1162
1163 if (mode == MWIFIEX_BSS_MODE_IBSS) {
1164 wiphy_err(wiphy, "received infra assoc request "
1165 "when station is in ibss mode\n");
1166 goto done;
1167 }
1168
1169 priv->assoc_request = 1;
1170
1171 wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
1172 (char *) sme->ssid, sme->bssid);
1173
1174 ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
1175 mode, sme->channel, sme, 0);
1176
1177done:
1178 priv->assoc_result = ret;
1179 queue_work(priv->workqueue, &priv->cfg_workqueue);
1180 return ret;
1181}
1182
1183/*
1184 * CFG802.11 operation handler to join an IBSS.
1185 *
1186 * This function does not work in any mode other than Ad-Hoc, or if
1187 * a join operation is already in progress.
1188 */
1189static int
1190mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1191 struct cfg80211_ibss_params *params)
1192{
1193 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
1194 int ret = 0;
1195 int mode = 0;
1196
1197 if (priv->ibss_join_request)
1198 return -EBUSY;
1199
1200 mode = mwifiex_drv_get_mode(priv, MWIFIEX_IOCTL_WAIT);
1201 if (mode != MWIFIEX_BSS_MODE_IBSS) {
1202 wiphy_err(wiphy, "request to join ibss received "
1203 "when station is not in ibss mode\n");
1204 goto done;
1205 }
1206
1207 priv->ibss_join_request = 1;
1208
1209 wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
1210 (char *) params->ssid, params->bssid);
1211
1212 ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
1213 params->bssid, mode, params->channel, NULL,
1214 params->privacy);
1215done:
1216 priv->ibss_join_result = ret;
1217 queue_work(priv->workqueue, &priv->cfg_workqueue);
1218 return ret;
1219}
1220
1221/*
1222 * CFG802.11 operation handler to leave an IBSS.
1223 *
1224 * This function does not work if a leave operation is
1225 * already in progress.
1226 */
1227static int
1228mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
1229{
1230 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
1231
1232 if (priv->disconnect)
1233 return -EBUSY;
1234
1235 priv->disconnect = 1;
1236
1237 wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
1238 priv->cfg_bssid);
1239 if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL))
1240 return -EFAULT;
1241
1242 queue_work(priv->workqueue, &priv->cfg_workqueue);
1243
1244 return 0;
1245}
1246
1247/*
1248 * CFG802.11 operation handler for scan request.
1249 *
1250 * This function issues a scan request to the firmware based upon
1251 * the user specified scan configuration. On successfull completion,
1252 * it also informs the results.
1253 */
1254static int
1255mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
1256 struct cfg80211_scan_request *request)
1257{
1258 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
1259
1260 wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
1261
1262 if (priv->scan_request && priv->scan_request != request)
1263 return -EBUSY;
1264
1265 priv->scan_request = request;
1266
1267 queue_work(priv->workqueue, &priv->cfg_workqueue);
1268 return 0;
1269}
1270
1271/*
1272 * This function sets up the CFG802.11 specific HT capability fields
1273 * with default values.
1274 *
1275 * The following default values are set -
1276 * - HT Supported = True
1277 * - Maximum AMPDU length factor = 0x3
1278 * - Minimum AMPDU spacing = 0x6
1279 * - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002)
1280 * - MCS information, Rx mask = 0xff
1281 * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01)
1282 */
1283static void
1284mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
1285 struct mwifiex_private *priv)
1286{
1287 int rx_mcs_supp;
1288 struct ieee80211_mcs_info mcs_set;
1289 u8 *mcs = (u8 *)&mcs_set;
1290 struct mwifiex_adapter *adapter = priv->adapter;
1291
1292 ht_info->ht_supported = true;
1293 ht_info->ampdu_factor = 0x3;
1294 ht_info->ampdu_density = 0x6;
1295
1296 memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
1297 ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40;
1298
1299 rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support);
1300 /* Set MCS for 1x1 */
1301 memset(mcs, 0xff, rx_mcs_supp);
1302 /* Clear all the other values */
1303 memset(&mcs[rx_mcs_supp], 0,
1304 sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
1305 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA ||
1306 (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) &&
1307 ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap)))
1308 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
1309 SETHT_MCS32(mcs_set.rx_mask);
1310
1311 memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info));
1312
1313 ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
1314}
1315
1316/* station cfg80211 operations */
1317static struct cfg80211_ops mwifiex_cfg80211_ops = {
1318 .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
1319 .scan = mwifiex_cfg80211_scan,
1320 .connect = mwifiex_cfg80211_connect,
1321 .disconnect = mwifiex_cfg80211_disconnect,
1322 .get_station = mwifiex_cfg80211_get_station,
1323 .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
1324 .set_channel = mwifiex_cfg80211_set_channel,
1325 .join_ibss = mwifiex_cfg80211_join_ibss,
1326 .leave_ibss = mwifiex_cfg80211_leave_ibss,
1327 .add_key = mwifiex_cfg80211_add_key,
1328 .del_key = mwifiex_cfg80211_del_key,
1329 .set_default_key = mwifiex_cfg80211_set_default_key,
1330 .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
1331 .set_tx_power = mwifiex_cfg80211_set_tx_power,
1332};
1333
1334/*
1335 * This function registers the device with CFG802.11 subsystem.
1336 *
1337 * The function creates the wireless device/wiphy, populates it with
1338 * default parameters and handler function pointers, and finally
1339 * registers the device.
1340 */
1341int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
1342 struct mwifiex_private *priv)
1343{
1344 int ret = 0;
1345 void *wdev_priv = NULL;
1346 struct wireless_dev *wdev;
1347
1348 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1349 if (!wdev) {
1350 dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
1351 __func__);
1352 return -ENOMEM;
1353 }
1354 wdev->wiphy =
1355 wiphy_new(&mwifiex_cfg80211_ops,
1356 sizeof(struct mwifiex_private *));
1357 if (!wdev->wiphy)
1358 return -ENOMEM;
1359 wdev->iftype = NL80211_IFTYPE_STATION;
1360 wdev->wiphy->max_scan_ssids = 10;
1361 wdev->wiphy->interface_modes =
1362 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
1363 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
1364 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
1365
1366 /* Initialize cipher suits */
1367 wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
1368 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
1369
1370 /* Initialize parameters for 2GHz band */
1371
1372 mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap,
1373 priv);
1374 mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap,
1375 priv);
1376
1377 memcpy(wdev->wiphy->perm_addr, mac, 6);
1378 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1379
1380 /* We are using custom domains */
1381 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
1382
1383 wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
1384
1385 /* Set struct mwifiex_private pointer in wiphy_priv */
1386 wdev_priv = wiphy_priv(wdev->wiphy);
1387
1388 *(unsigned long *) wdev_priv = (unsigned long) priv;
1389
1390 ret = wiphy_register(wdev->wiphy);
1391 if (ret < 0) {
1392 dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
1393 __func__);
1394 wiphy_free(wdev->wiphy);
1395 return ret;
1396 } else {
1397 dev_dbg(priv->adapter->dev,
1398 "info: successfully registered wiphy device\n");
1399 }
1400
1401 dev_net_set(dev, wiphy_net(wdev->wiphy));
1402 dev->ieee80211_ptr = wdev;
1403 memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
1404 memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
1405 SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
1406 priv->wdev = wdev;
1407
1408 dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1409 dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
1410 dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
1411
1412 return ret;
1413}
1414
1415/*
1416 * This function handles the result of different pending network operations.
1417 *
1418 * The following operations are handled and CFG802.11 subsystem is
1419 * notified accordingly -
1420 * - Scan request completion
1421 * - Association request completion
1422 * - IBSS join request completion
1423 * - Disconnect request completion
1424 */
1425void
1426mwifiex_cfg80211_results(struct work_struct *work)
1427{
1428 struct mwifiex_private *priv =
1429 container_of(work, struct mwifiex_private, cfg_workqueue);
1430 struct mwifiex_user_scan_cfg *scan_req;
1431 int ret = 0, i;
1432 struct ieee80211_channel *chan;
1433
1434 if (priv->scan_request) {
1435 scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
1436 GFP_KERNEL);
1437 if (!scan_req) {
1438 dev_err(priv->adapter->dev, "failed to alloc "
1439 "scan_req\n");
1440 return;
1441 }
1442 for (i = 0; i < priv->scan_request->n_ssids; i++) {
1443 memcpy(scan_req->ssid_list[i].ssid,
1444 priv->scan_request->ssids[i].ssid,
1445 priv->scan_request->ssids[i].ssid_len);
1446 scan_req->ssid_list[i].max_len =
1447 priv->scan_request->ssids[i].ssid_len;
1448 }
1449 for (i = 0; i < priv->scan_request->n_channels; i++) {
1450 chan = priv->scan_request->channels[i];
1451 scan_req->chan_list[i].chan_number = chan->hw_value;
1452 scan_req->chan_list[i].radio_type = chan->band;
1453 if (chan->flags & IEEE80211_CHAN_DISABLED)
1454 scan_req->chan_list[i].scan_type =
1455 MWIFIEX_SCAN_TYPE_PASSIVE;
1456 else
1457 scan_req->chan_list[i].scan_type =
1458 MWIFIEX_SCAN_TYPE_ACTIVE;
1459 scan_req->chan_list[i].scan_time = 0;
1460 }
1461 if (mwifiex_set_user_scan_ioctl(priv, scan_req)) {
1462 ret = -EFAULT;
1463 goto done;
1464 }
1465 if (mwifiex_inform_bss_from_scan_result(priv, NULL))
1466 ret = -EFAULT;
1467done:
1468 priv->scan_result_status = ret;
1469 dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n",
1470 __func__);
1471 cfg80211_scan_done(priv->scan_request,
1472 (priv->scan_result_status < 0));
1473 priv->scan_request = NULL;
1474 kfree(scan_req);
1475 }
1476
1477 if (priv->assoc_request) {
1478 if (!priv->assoc_result) {
1479 cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
1480 NULL, 0, NULL, 0,
1481 WLAN_STATUS_SUCCESS,
1482 GFP_KERNEL);
1483 dev_dbg(priv->adapter->dev,
1484 "info: associated to bssid %pM successfully\n",
1485 priv->cfg_bssid);
1486 } else {
1487 dev_dbg(priv->adapter->dev,
1488 "info: association to bssid %pM failed\n",
1489 priv->cfg_bssid);
1490 memset(priv->cfg_bssid, 0, ETH_ALEN);
1491 }
1492 priv->assoc_request = 0;
1493 priv->assoc_result = 0;
1494 }
1495
1496 if (priv->ibss_join_request) {
1497 if (!priv->ibss_join_result) {
1498 cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
1499 GFP_KERNEL);
1500 dev_dbg(priv->adapter->dev,
1501 "info: joined/created adhoc network with bssid"
1502 " %pM successfully\n", priv->cfg_bssid);
1503 } else {
1504 dev_dbg(priv->adapter->dev,
1505 "info: failed creating/joining adhoc network\n");
1506 }
1507 priv->ibss_join_request = 0;
1508 priv->ibss_join_result = 0;
1509 }
1510
1511 if (priv->disconnect) {
1512 memset(priv->cfg_bssid, 0, ETH_ALEN);
1513 priv->disconnect = 0;
1514 }
1515
1516 return;
1517}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h
new file mode 100644
index 000000000000..c4db8f36aa16
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.h
@@ -0,0 +1,31 @@
1/*
2 * Marvell Wireless LAN device driver: CFG80211
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef __MWIFIEX_CFG80211__
21#define __MWIFIEX_CFG80211__
22
23#include <net/cfg80211.h>
24
25#include "main.h"
26
27int mwifiex_register_cfg80211(struct net_device *, u8 *,
28 struct mwifiex_private *);
29
30void mwifiex_cfg80211_results(struct work_struct *work);
31#endif
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
new file mode 100644
index 000000000000..999ed81512fa
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -0,0 +1,368 @@
1/*
2 * Marvell Wireless LAN device driver: Channel, Frequence and Power
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "cfg80211.h"
26
27/* 100mW */
28#define MWIFIEX_TX_PWR_DEFAULT 20
29/* 100mW */
30#define MWIFIEX_TX_PWR_US_DEFAULT 20
31/* 50mW */
32#define MWIFIEX_TX_PWR_JP_DEFAULT 16
33/* 100mW */
34#define MWIFIEX_TX_PWR_FR_100MW 20
35/* 10mW */
36#define MWIFIEX_TX_PWR_FR_10MW 10
37/* 100mW */
38#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20
39
40static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
41
42static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
43 0xb0, 0x48, 0x60, 0x6c, 0 };
44
45static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
46 0x0c, 0x12, 0x18, 0x24,
47 0x30, 0x48, 0x60, 0x6c, 0 };
48
49static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
50 0xb0, 0x48, 0x60, 0x6c, 0 };
51u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
52 0xb0, 0x48, 0x60, 0x6c, 0 };
53static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
54 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
55 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
56 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
57 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
58 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
59
60u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
61
62u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
63 0x30, 0x48, 0x60, 0x6c, 0 };
64
65u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
66 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
67 0x60, 0x6c, 0 };
68
69u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
70 0x32, 0x40, 0x41, 0xff };
71
72u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
73
74/*
75 * This function maps an index in supported rates table into
76 * the corresponding data rate.
77 */
78u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
79 u8 ht_info)
80{
81 u16 mcs_rate[4][8] = {
82 {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
83 , /* LG 40M */
84 {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c}
85 , /* SG 40M */
86 {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82}
87 , /* LG 20M */
88 {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90}
89 }; /* SG 20M */
90
91 u32 rate;
92
93 if (ht_info & BIT(0)) {
94 if (index == MWIFIEX_RATE_BITMAP_MCS0) {
95 if (ht_info & BIT(2))
96 rate = 0x0D; /* MCS 32 SGI rate */
97 else
98 rate = 0x0C; /* MCS 32 LGI rate */
99 } else if (index < 8) {
100 if (ht_info & BIT(1)) {
101 if (ht_info & BIT(2))
102 /* SGI, 40M */
103 rate = mcs_rate[1][index];
104 else
105 /* LGI, 40M */
106 rate = mcs_rate[0][index];
107 } else {
108 if (ht_info & BIT(2))
109 /* SGI, 20M */
110 rate = mcs_rate[3][index];
111 else
112 /* LGI, 20M */
113 rate = mcs_rate[2][index];
114 }
115 } else
116 rate = mwifiex_data_rates[0];
117 } else {
118 if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
119 index = 0;
120 rate = mwifiex_data_rates[index];
121 }
122 return rate;
123}
124
125/*
126 * This function maps a data rate value into corresponding index in supported
127 * rates table.
128 */
129u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate)
130{
131 u16 *ptr;
132
133 if (rate) {
134 ptr = memchr(mwifiex_data_rates, rate,
135 sizeof(mwifiex_data_rates));
136 if (ptr)
137 return (u8) (ptr - mwifiex_data_rates);
138 }
139 return 0;
140}
141
142/*
143 * This function returns the current active data rates.
144 *
145 * The result may vary depending upon connection status.
146 */
147u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
148{
149 u32 k;
150
151 if (!priv->media_connected)
152 k = mwifiex_get_supported_rates(priv, rates);
153 else
154 k = mwifiex_copy_rates(rates, 0,
155 priv->curr_bss_params.data_rates,
156 priv->curr_bss_params.num_of_rates);
157
158 return k;
159}
160
161/*
162 * This function locates the Channel-Frequency-Power triplet based upon
163 * band and channel parameters.
164 */
165struct mwifiex_chan_freq_power *
166mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private
167 *priv, u8 band, u16 channel)
168{
169 struct mwifiex_chan_freq_power *cfp = NULL;
170 struct ieee80211_supported_band *sband;
171 struct ieee80211_channel *ch;
172 int i;
173
174 if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
175 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
176 else
177 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
178
179 if (!sband) {
180 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
181 " & channel %d\n", __func__, band, channel);
182 return cfp;
183 }
184
185 for (i = 0; i < sband->n_channels; i++) {
186 ch = &sband->channels[i];
187 if (((ch->hw_value == channel) ||
188 (channel == FIRST_VALID_CHANNEL))
189 && !(ch->flags & IEEE80211_CHAN_DISABLED)) {
190 priv->cfp.channel = channel;
191 priv->cfp.freq = ch->center_freq;
192 priv->cfp.max_tx_power = ch->max_power;
193 cfp = &priv->cfp;
194 break;
195 }
196 }
197 if (i == sband->n_channels)
198 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
199 " & channel %d\n", __func__, band, channel);
200
201 return cfp;
202}
203
204/*
205 * This function locates the Channel-Frequency-Power triplet based upon
206 * band and frequency parameters.
207 */
208struct mwifiex_chan_freq_power *
209mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv,
210 u8 band, u32 freq)
211{
212 struct mwifiex_chan_freq_power *cfp = NULL;
213 struct ieee80211_supported_band *sband;
214 struct ieee80211_channel *ch;
215 int i;
216
217 if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
218 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
219 else
220 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
221
222 if (!sband) {
223 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
224 " & freq %d\n", __func__, band, freq);
225 return cfp;
226 }
227
228 for (i = 0; i < sband->n_channels; i++) {
229 ch = &sband->channels[i];
230 if ((ch->center_freq == freq) &&
231 !(ch->flags & IEEE80211_CHAN_DISABLED)) {
232 priv->cfp.channel = ch->hw_value;
233 priv->cfp.freq = freq;
234 priv->cfp.max_tx_power = ch->max_power;
235 cfp = &priv->cfp;
236 break;
237 }
238 }
239 if (i == sband->n_channels)
240 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
241 " & freq %d\n", __func__, band, freq);
242
243 return cfp;
244}
245
246/*
247 * This function checks if the data rate is set to auto.
248 */
249u8
250mwifiex_is_rate_auto(struct mwifiex_private *priv)
251{
252 u32 i;
253 int rate_num = 0;
254
255 for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
256 if (priv->bitmap_rates[i])
257 rate_num++;
258
259 if (rate_num > 1)
260 return true;
261 else
262 return false;
263}
264
265/*
266 * This function converts rate bitmap into rate index.
267 */
268int
269mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap,
270 int size)
271{
272 int i;
273
274 for (i = 0; i < size * 8; i++)
275 if (rate_bitmap[i / 16] & (1 << (i % 16)))
276 return i;
277
278 return 0;
279}
280
281/*
282 * This function gets the supported data rates.
283 *
284 * The function works in both Ad-Hoc and infra mode by printing the
285 * band and returning the data rates.
286 */
287u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
288{
289 u32 k = 0;
290 struct mwifiex_adapter *adapter = priv->adapter;
291 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) {
292 /* Infra. mode */
293 switch (adapter->config_bands) {
294 case BAND_B:
295 dev_dbg(adapter->dev, "info: infra band=%d "
296 "supported_rates_b\n", adapter->config_bands);
297 k = mwifiex_copy_rates(rates, k, supported_rates_b,
298 sizeof(supported_rates_b));
299 break;
300 case BAND_G:
301 case BAND_G | BAND_GN:
302 dev_dbg(adapter->dev, "info: infra band=%d "
303 "supported_rates_g\n", adapter->config_bands);
304 k = mwifiex_copy_rates(rates, k, supported_rates_g,
305 sizeof(supported_rates_g));
306 break;
307 case BAND_B | BAND_G:
308 case BAND_A | BAND_B | BAND_G:
309 case BAND_A | BAND_B:
310 case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
311 case BAND_B | BAND_G | BAND_GN:
312 dev_dbg(adapter->dev, "info: infra band=%d "
313 "supported_rates_bg\n", adapter->config_bands);
314 k = mwifiex_copy_rates(rates, k, supported_rates_bg,
315 sizeof(supported_rates_bg));
316 break;
317 case BAND_A:
318 case BAND_A | BAND_G:
319 dev_dbg(adapter->dev, "info: infra band=%d "
320 "supported_rates_a\n", adapter->config_bands);
321 k = mwifiex_copy_rates(rates, k, supported_rates_a,
322 sizeof(supported_rates_a));
323 break;
324 case BAND_A | BAND_AN:
325 case BAND_A | BAND_G | BAND_AN | BAND_GN:
326 dev_dbg(adapter->dev, "info: infra band=%d "
327 "supported_rates_a\n", adapter->config_bands);
328 k = mwifiex_copy_rates(rates, k, supported_rates_a,
329 sizeof(supported_rates_a));
330 break;
331 case BAND_GN:
332 dev_dbg(adapter->dev, "info: infra band=%d "
333 "supported_rates_n\n", adapter->config_bands);
334 k = mwifiex_copy_rates(rates, k, supported_rates_n,
335 sizeof(supported_rates_n));
336 break;
337 }
338 } else {
339 /* Ad-hoc mode */
340 switch (adapter->adhoc_start_band) {
341 case BAND_B:
342 dev_dbg(adapter->dev, "info: adhoc B\n");
343 k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
344 sizeof(adhoc_rates_b));
345 break;
346 case BAND_G:
347 case BAND_G | BAND_GN:
348 dev_dbg(adapter->dev, "info: adhoc G only\n");
349 k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
350 sizeof(adhoc_rates_g));
351 break;
352 case BAND_B | BAND_G:
353 case BAND_B | BAND_G | BAND_GN:
354 dev_dbg(adapter->dev, "info: adhoc BG\n");
355 k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
356 sizeof(adhoc_rates_bg));
357 break;
358 case BAND_A:
359 case BAND_A | BAND_AN:
360 dev_dbg(adapter->dev, "info: adhoc A\n");
361 k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
362 sizeof(adhoc_rates_a));
363 break;
364 }
365 }
366
367 return k;
368}
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
new file mode 100644
index 000000000000..3a8fe1e122fb
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -0,0 +1,1463 @@
1/*
2 * Marvell Wireless LAN device driver: commands and events
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * This function initializes a command node.
30 *
31 * The actual allocation of the node is not done by this function. It only
32 * initiates a node by filling it with default parameters. Similarly,
33 * allocation of the different buffers used (IOCTL buffer, data buffer) are
34 * not done by this function either.
35 */
36static void
37mwifiex_init_cmd_node(struct mwifiex_private *priv,
38 struct cmd_ctrl_node *cmd_node,
39 u32 cmd_oid, void *wait_queue, void *data_buf)
40{
41 cmd_node->priv = priv;
42 cmd_node->cmd_oid = cmd_oid;
43 cmd_node->wq_buf = wait_queue;
44 cmd_node->data_buf = data_buf;
45 cmd_node->cmd_skb = cmd_node->skb;
46}
47
48/*
49 * This function returns a command node from the free queue depending upon
50 * availability.
51 */
52static struct cmd_ctrl_node *
53mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
54{
55 struct cmd_ctrl_node *cmd_node;
56 unsigned long flags;
57
58 spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
59 if (list_empty(&adapter->cmd_free_q)) {
60 dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n");
61 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
62 return NULL;
63 }
64 cmd_node = list_first_entry(&adapter->cmd_free_q,
65 struct cmd_ctrl_node, list);
66 list_del(&cmd_node->list);
67 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
68
69 return cmd_node;
70}
71
72/*
73 * This function cleans up a command node.
74 *
75 * The function resets the fields including the buffer pointers.
76 * This function does not try to free the buffers. They must be
77 * freed before calling this function.
78 *
79 * This function will however call the receive completion callback
80 * in case a response buffer is still available before resetting
81 * the pointer.
82 */
83static void
84mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
85 struct cmd_ctrl_node *cmd_node)
86{
87 cmd_node->cmd_oid = 0;
88 cmd_node->cmd_flag = 0;
89 cmd_node->wq_buf = NULL;
90 cmd_node->data_buf = NULL;
91
92 if (cmd_node->resp_skb) {
93 mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0);
94 cmd_node->resp_skb = NULL;
95 }
96
97 return;
98}
99
100/*
101 * This function returns a command node from the pending queue which
102 * matches the given IOCTL request.
103 */
104static struct cmd_ctrl_node *
105mwifiex_get_pending_ioctl_cmd(struct mwifiex_adapter *adapter,
106 struct mwifiex_wait_queue *wait_queue)
107{
108 unsigned long flags;
109 struct cmd_ctrl_node *cmd_node;
110
111 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
112 list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
113 if (cmd_node->wq_buf == wait_queue) {
114 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
115 flags);
116 return cmd_node;
117 }
118 }
119 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
120
121 return NULL;
122}
123
124/*
125 * This function sends a host command to the firmware.
126 *
127 * The function copies the host command into the driver command
128 * buffer, which will be transferred to the firmware later by the
129 * main thread.
130 */
131static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv,
132 struct host_cmd_ds_command *cmd, void *data_buf)
133{
134 struct mwifiex_ds_misc_cmd *pcmd_ptr =
135 (struct mwifiex_ds_misc_cmd *) data_buf;
136
137 /* Copy the HOST command to command buffer */
138 memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
139 dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len);
140 return 0;
141}
142
143/*
144 * This function downloads a command to the firmware.
145 *
146 * The function performs sanity tests, sets the command sequence
147 * number and size, converts the header fields to CPU format before
148 * sending. Afterwards, it logs the command ID and action for debugging
149 * and sets up the command timeout timer.
150 */
151static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
152 struct cmd_ctrl_node *cmd_node)
153{
154
155 struct mwifiex_adapter *adapter = priv->adapter;
156 int ret = 0;
157 struct host_cmd_ds_command *host_cmd;
158 struct mwifiex_wait_queue *wait_queue = NULL;
159 uint16_t cmd_code;
160 uint16_t cmd_size;
161 struct timeval tstamp;
162 unsigned long flags;
163
164 if (!adapter || !cmd_node)
165 return -1;
166
167 host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
168 if (cmd_node->wq_buf)
169 wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf;
170
171 /* Sanity test */
172 if (host_cmd == NULL || host_cmd->size == 0) {
173 dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
174 " or cmd size is 0, not sending\n");
175 if (wait_queue)
176 wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL;
177 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
178 return -1;
179 }
180
181 /* Set command sequence number */
182 adapter->seq_num++;
183 host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
184 (adapter->seq_num, cmd_node->priv->bss_num,
185 cmd_node->priv->bss_type));
186
187 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
188 adapter->curr_cmd = cmd_node;
189 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
190
191 cmd_code = le16_to_cpu(host_cmd->command);
192 cmd_size = le16_to_cpu(host_cmd->size);
193
194 skb_trim(cmd_node->cmd_skb, cmd_size);
195
196 do_gettimeofday(&tstamp);
197 dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
198 " seqno %#x\n",
199 tstamp.tv_sec, tstamp.tv_usec, cmd_code,
200 le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
201 le16_to_cpu(host_cmd->seq_num));
202
203 skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
204
205 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
206 cmd_node->cmd_skb->data,
207 cmd_node->cmd_skb->len, NULL);
208
209 if (ret == -1) {
210 dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
211 if (wait_queue)
212 wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL;
213 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
214
215 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
216 adapter->curr_cmd = NULL;
217 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
218
219 adapter->dbg.num_cmd_host_to_card_failure++;
220 return -1;
221 }
222
223 /* Save the last command id and action to debug log */
224 adapter->dbg.last_cmd_index =
225 (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
226 adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code;
227 adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] =
228 le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN));
229
230 /* Clear BSS_NO_BITS from HostCmd */
231 cmd_code &= HostCmd_CMD_ID_MASK;
232
233 /* Setup the timer after transmit command */
234 mod_timer(&adapter->cmd_timer,
235 jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000);
236
237 return 0;
238}
239
240/*
241 * This function downloads a sleep confirm command to the firmware.
242 *
243 * The function performs sanity tests, sets the command sequence
244 * number and size, converts the header fields to CPU format before
245 * sending.
246 *
247 * No responses are needed for sleep confirm command.
248 */
249static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
250{
251 int ret = 0;
252 u16 cmd_len = 0;
253 struct mwifiex_private *priv;
254 struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf =
255 (struct mwifiex_opt_sleep_confirm_buffer *)
256 adapter->sleep_cfm->data;
257 cmd_len = sizeof(struct mwifiex_opt_sleep_confirm);
258 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
259
260 sleep_cfm_buf->ps_cfm_sleep.seq_num =
261 cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
262 (adapter->seq_num, priv->bss_num,
263 priv->bss_type)));
264 adapter->seq_num++;
265
266 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
267 adapter->sleep_cfm->data,
268 adapter->sleep_cfm->len +
269 INTF_HEADER_LEN, NULL);
270
271 if (ret == -1) {
272 dev_err(adapter->dev, "SLEEP_CFM: failed\n");
273 adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
274 return -1;
275 }
276 if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
277 == MWIFIEX_BSS_ROLE_STA) {
278 if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl)
279 /* Response is not needed for sleep
280 confirm command */
281 adapter->ps_state = PS_STATE_SLEEP;
282 else
283 adapter->ps_state = PS_STATE_SLEEP_CFM;
284
285 if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl
286 && (adapter->is_hs_configured
287 && !adapter->sleep_period.period)) {
288 adapter->pm_wakeup_card_req = true;
289 mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
290 MWIFIEX_BSS_ROLE_STA), true);
291 }
292 }
293
294 return ret;
295}
296
297/*
298 * This function allocates the command buffers and links them to
299 * the command free queue.
300 *
301 * The driver uses a pre allocated number of command buffers, which
302 * are created at driver initializations and freed at driver cleanup.
303 * Every command needs to obtain a command buffer from this pool before
304 * it can be issued. The command free queue lists the command buffers
305 * currently free to use, while the command pending queue lists the
306 * command buffers already in use and awaiting handling. Command buffers
307 * are returned to the free queue after use.
308 */
309int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
310{
311 struct cmd_ctrl_node *cmd_array;
312 u32 buf_size;
313 u32 i;
314
315 /* Allocate and initialize struct cmd_ctrl_node */
316 buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER;
317 cmd_array = kzalloc(buf_size, GFP_KERNEL);
318 if (!cmd_array) {
319 dev_err(adapter->dev, "%s: failed to alloc cmd_array\n",
320 __func__);
321 return -1;
322 }
323
324 adapter->cmd_pool = cmd_array;
325 memset(adapter->cmd_pool, 0, buf_size);
326
327 /* Allocate and initialize command buffers */
328 for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
329 cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
330 if (!cmd_array[i].skb) {
331 dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
332 return -1;
333 }
334 }
335
336 for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++)
337 mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]);
338
339 return 0;
340}
341
342/*
343 * This function frees the command buffers.
344 *
345 * The function calls the completion callback for all the command
346 * buffers that still have response buffers associated with them.
347 */
348int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
349{
350 struct cmd_ctrl_node *cmd_array;
351 u32 i;
352
353 /* Need to check if cmd pool is allocated or not */
354 if (!adapter->cmd_pool) {
355 dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n");
356 return 0;
357 }
358
359 cmd_array = adapter->cmd_pool;
360
361 /* Release shared memory buffers */
362 for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
363 if (cmd_array[i].skb) {
364 dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i);
365 dev_kfree_skb_any(cmd_array[i].skb);
366 }
367 if (!cmd_array[i].resp_skb)
368 continue;
369 mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0);
370 }
371 /* Release struct cmd_ctrl_node */
372 if (adapter->cmd_pool) {
373 dev_dbg(adapter->dev, "cmd: free cmd pool\n");
374 kfree(adapter->cmd_pool);
375 adapter->cmd_pool = NULL;
376 }
377
378 return 0;
379}
380
381/*
382 * This function handles events generated by firmware.
383 *
384 * Event body of events received from firmware are not used (though they are
385 * saved), only the event ID is used. Some events are re-invoked by
386 * the driver, with a new event body.
387 *
388 * After processing, the function calls the completion callback
389 * for cleanup.
390 */
391int mwifiex_process_event(struct mwifiex_adapter *adapter)
392{
393 int ret = 0;
394 struct mwifiex_private *priv =
395 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
396 struct sk_buff *skb = adapter->event_skb;
397 u32 eventcause = adapter->event_cause;
398 struct timeval tstamp;
399 struct mwifiex_rxinfo *rx_info = NULL;
400
401 /* Save the last event to debug log */
402 adapter->dbg.last_event_index =
403 (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
404 adapter->dbg.last_event[adapter->dbg.last_event_index] =
405 (u16) eventcause;
406
407 /* Get BSS number and corresponding priv */
408 priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause),
409 EVENT_GET_BSS_TYPE(eventcause));
410 if (!priv)
411 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
412 /* Clear BSS_NO_BITS from event */
413 eventcause &= EVENT_ID_MASK;
414 adapter->event_cause = eventcause;
415
416 if (skb) {
417 rx_info = MWIFIEX_SKB_RXCB(skb);
418 rx_info->bss_index = priv->bss_index;
419 }
420
421 if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
422 do_gettimeofday(&tstamp);
423 dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
424 tstamp.tv_sec, tstamp.tv_usec, eventcause);
425 }
426
427 ret = mwifiex_process_sta_event(priv);
428
429 adapter->event_cause = 0;
430 adapter->event_skb = NULL;
431
432 mwifiex_recv_complete(adapter, skb, 0);
433
434 return ret;
435}
436
437/*
438 * This function prepares a command before sending it to the firmware.
439 *
440 * Preparation includes -
441 * - Sanity tests to make sure the card is still present or the FW
442 * is not reset
443 * - Getting a new command node from the command free queue
444 * - Initializing the command node for default parameters
445 * - Fill up the non-default parameters and buffer pointers
446 * - Add the command to pending queue
447 */
448int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
449 u16 cmd_action, u32 cmd_oid,
450 void *wait_queue, void *data_buf)
451{
452 int ret = 0;
453 struct mwifiex_adapter *adapter = priv->adapter;
454 struct cmd_ctrl_node *cmd_node = NULL;
455 struct host_cmd_ds_command *cmd_ptr = NULL;
456
457 if (!adapter) {
458 pr_err("PREP_CMD: adapter is NULL\n");
459 return -1;
460 }
461
462 if (adapter->is_suspended) {
463 dev_err(adapter->dev, "PREP_CMD: device in suspended state\n");
464 return -1;
465 }
466
467 if (adapter->surprise_removed) {
468 dev_err(adapter->dev, "PREP_CMD: card is removed\n");
469 return -1;
470 }
471
472 if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
473 if (cmd_no != HostCmd_CMD_FUNC_INIT) {
474 dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
475 return -1;
476 }
477 }
478
479 /* Get a new command node */
480 cmd_node = mwifiex_get_cmd_node(adapter);
481
482 if (!cmd_node) {
483 dev_err(adapter->dev, "PREP_CMD: no free cmd node\n");
484 return -1;
485 }
486
487 /* Initialize the command node */
488 mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf);
489
490 if (!cmd_node->cmd_skb) {
491 dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
492 return -1;
493 }
494
495 memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)),
496 0, sizeof(struct host_cmd_ds_command));
497
498 cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
499 cmd_ptr->command = cpu_to_le16(cmd_no);
500 cmd_ptr->result = 0;
501
502 /* Prepare command */
503 if (cmd_no) {
504 ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
505 cmd_oid, data_buf, cmd_ptr);
506 } else {
507 ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
508 cmd_node->cmd_flag |= CMD_F_HOSTCMD;
509 }
510
511 /* Return error, since the command preparation failed */
512 if (ret) {
513 dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n",
514 cmd_no);
515 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
516 return -1;
517 }
518
519 /* Send command */
520 if (cmd_no == HostCmd_CMD_802_11_SCAN)
521 mwifiex_queue_scan_cmd(priv, cmd_node);
522 else
523 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
524
525 return ret;
526}
527
528/*
529 * This function returns a command to the command free queue.
530 *
531 * The function also calls the completion callback if required, before
532 * cleaning the command node and re-inserting it into the free queue.
533 */
534void
535mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
536 struct cmd_ctrl_node *cmd_node)
537{
538 struct mwifiex_wait_queue *wait_queue = NULL;
539 unsigned long flags;
540
541 if (cmd_node == NULL)
542 return;
543 if (cmd_node->wq_buf) {
544 wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf;
545 if (wait_queue->status != MWIFIEX_ERROR_NO_ERROR)
546 mwifiex_ioctl_complete(adapter, wait_queue, -1);
547 else
548 mwifiex_ioctl_complete(adapter, wait_queue, 0);
549 }
550 /* Clean the node */
551 mwifiex_clean_cmd_node(adapter, cmd_node);
552
553 /* Insert node into cmd_free_q */
554 spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
555 list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
556 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
557
558 return;
559}
560
561/*
562 * This function queues a command to the command pending queue.
563 *
564 * This in effect adds the command to the command list to be executed.
565 * Exit PS command is handled specially, by placing it always to the
566 * front of the command queue.
567 */
568void
569mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
570 struct cmd_ctrl_node *cmd_node, u32 add_tail)
571{
572 struct host_cmd_ds_command *host_cmd = NULL;
573 u16 command;
574 unsigned long flags;
575
576 host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
577 if (!host_cmd) {
578 dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n");
579 return;
580 }
581
582 command = le16_to_cpu(host_cmd->command);
583
584 /* Exit_PS command needs to be queued in the header always. */
585 if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
586 struct host_cmd_ds_802_11_ps_mode_enh *pm =
587 &host_cmd->params.psmode_enh;
588 if ((le16_to_cpu(pm->action) == DIS_PS)
589 || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) {
590 if (adapter->ps_state != PS_STATE_AWAKE)
591 add_tail = false;
592 }
593 }
594
595 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
596 if (add_tail)
597 list_add_tail(&cmd_node->list, &adapter->cmd_pending_q);
598 else
599 list_add(&cmd_node->list, &adapter->cmd_pending_q);
600 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
601
602 dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
603
604 return;
605}
606
607/*
608 * This function executes the next command in command pending queue.
609 *
610 * This function will fail if a command is already in processing stage,
611 * otherwise it will dequeue the first command from the command pending
612 * queue and send to the firmware.
613 *
614 * If the device is currently in host sleep mode, any commands, except the
615 * host sleep configuration command will de-activate the host sleep. For PS
616 * mode, the function will put the firmware back to sleep if applicable.
617 */
618int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
619{
620 struct mwifiex_private *priv = NULL;
621 struct cmd_ctrl_node *cmd_node = NULL;
622 int ret = 0;
623 struct host_cmd_ds_command *host_cmd;
624 unsigned long cmd_flags;
625 unsigned long cmd_pending_q_flags;
626
627 /* Check if already in processing */
628 if (adapter->curr_cmd) {
629 dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n");
630 return -1;
631 }
632
633 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
634 /* Check if any command is pending */
635 spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
636 if (list_empty(&adapter->cmd_pending_q)) {
637 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
638 cmd_pending_q_flags);
639 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
640 return 0;
641 }
642 cmd_node = list_first_entry(&adapter->cmd_pending_q,
643 struct cmd_ctrl_node, list);
644 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
645 cmd_pending_q_flags);
646
647 host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
648 priv = cmd_node->priv;
649
650 if (adapter->ps_state != PS_STATE_AWAKE) {
651 dev_err(adapter->dev, "%s: cannot send cmd in sleep state,"
652 " this should not happen\n", __func__);
653 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
654 return ret;
655 }
656
657 spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
658 list_del(&cmd_node->list);
659 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
660 cmd_pending_q_flags);
661
662 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
663 ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node);
664 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
665 /* Any command sent to the firmware when host is in sleep
666 * mode should de-configure host sleep. We should skip the
667 * host sleep configuration command itself though
668 */
669 if (priv && (host_cmd->command !=
670 cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
671 if (adapter->hs_activated) {
672 adapter->is_hs_configured = false;
673 mwifiex_hs_activated_event(priv, false);
674 }
675 }
676
677 return ret;
678}
679
680/*
681 * This function handles the command response.
682 *
683 * After processing, the function cleans the command node and puts
684 * it back to the command free queue.
685 */
686int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
687{
688 struct host_cmd_ds_command *resp = NULL;
689 struct mwifiex_private *priv =
690 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
691 int ret = 0;
692 uint16_t orig_cmdresp_no;
693 uint16_t cmdresp_no;
694 uint16_t cmdresp_result;
695 struct mwifiex_wait_queue *wait_queue = NULL;
696 struct timeval tstamp;
697 unsigned long flags;
698
699 /* Now we got response from FW, cancel the command timer */
700 del_timer(&adapter->cmd_timer);
701
702 if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
703 resp = (struct host_cmd_ds_command *) adapter->upld_buf;
704 dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n",
705 le16_to_cpu(resp->command));
706 return -1;
707 }
708
709 if (adapter->curr_cmd->wq_buf)
710 wait_queue = (struct mwifiex_wait_queue *)
711 adapter->curr_cmd->wq_buf;
712
713 adapter->num_cmd_timeout = 0;
714
715 resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
716 if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
717 dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
718 le16_to_cpu(resp->command));
719 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
720 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
721 adapter->curr_cmd = NULL;
722 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
723 return -1;
724 }
725
726 if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
727 /* Copy original response back to response buffer */
728 struct mwifiex_ds_misc_cmd *hostcmd = NULL;
729 uint16_t size = le16_to_cpu(resp->size);
730 dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size);
731 size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER);
732 if (adapter->curr_cmd->data_buf) {
733 hostcmd = (struct mwifiex_ds_misc_cmd *)
734 adapter->curr_cmd->data_buf;
735 hostcmd->len = size;
736 memcpy(hostcmd->cmd, (void *) resp, size);
737 }
738 }
739 orig_cmdresp_no = le16_to_cpu(resp->command);
740
741 /* Get BSS number and corresponding priv */
742 priv = mwifiex_get_priv_by_id(adapter,
743 HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)),
744 HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num)));
745 if (!priv)
746 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
747 /* Clear RET_BIT from HostCmd */
748 resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK);
749
750 cmdresp_no = le16_to_cpu(resp->command);
751 cmdresp_result = le16_to_cpu(resp->result);
752
753 /* Save the last command response to debug log */
754 adapter->dbg.last_cmd_resp_index =
755 (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
756 adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
757 orig_cmdresp_no;
758
759 do_gettimeofday(&tstamp);
760 dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d,"
761 " len %d, seqno 0x%x\n",
762 tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result,
763 le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
764
765 if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
766 dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
767 if (wait_queue)
768 wait_queue->status = MWIFIEX_ERROR_FW_CMDRESP;
769
770 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
771 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
772 adapter->curr_cmd = NULL;
773 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
774 return -1;
775 }
776
777 if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
778 adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
779 if ((cmdresp_result == HostCmd_RESULT_OK)
780 && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
781 ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
782 } else {
783 /* handle response */
784 ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp,
785 wait_queue);
786 }
787
788 /* Check init command response */
789 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
790 if (ret == -1) {
791 dev_err(adapter->dev, "%s: cmd %#x failed during "
792 "initialization\n", __func__, cmdresp_no);
793 mwifiex_init_fw_complete(adapter);
794 return -1;
795 } else if (adapter->last_init_cmd == cmdresp_no)
796 adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE;
797 }
798
799 if (adapter->curr_cmd) {
800 if (wait_queue && (!ret))
801 wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
802 else if (wait_queue && (ret == -1))
803 wait_queue->status = MWIFIEX_ERROR_CMD_RESP_FAIL;
804
805 /* Clean up and put current command back to cmd_free_q */
806 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
807
808 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
809 adapter->curr_cmd = NULL;
810 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
811 }
812
813 return ret;
814}
815
816/*
817 * This function handles the timeout of command sending.
818 *
819 * It will re-send the same command again.
820 */
821void
822mwifiex_cmd_timeout_func(unsigned long function_context)
823{
824 struct mwifiex_adapter *adapter =
825 (struct mwifiex_adapter *) function_context;
826 struct cmd_ctrl_node *cmd_node = NULL;
827 struct mwifiex_wait_queue *wait_queue = NULL;
828 struct timeval tstamp;
829
830 adapter->num_cmd_timeout++;
831 adapter->dbg.num_cmd_timeout++;
832 if (!adapter->curr_cmd) {
833 dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
834 return;
835 }
836 cmd_node = adapter->curr_cmd;
837 if (cmd_node->wq_buf) {
838 wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf;
839 wait_queue->status = MWIFIEX_ERROR_CMD_TIMEOUT;
840 }
841
842 if (cmd_node) {
843 adapter->dbg.timeout_cmd_id =
844 adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
845 adapter->dbg.timeout_cmd_act =
846 adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
847 do_gettimeofday(&tstamp);
848 dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x,"
849 " act = %#x\n", __func__,
850 tstamp.tv_sec, tstamp.tv_usec,
851 adapter->dbg.timeout_cmd_id,
852 adapter->dbg.timeout_cmd_act);
853
854 dev_err(adapter->dev, "num_data_h2c_failure = %d\n",
855 adapter->dbg.num_tx_host_to_card_failure);
856 dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
857 adapter->dbg.num_cmd_host_to_card_failure);
858
859 dev_err(adapter->dev, "num_cmd_timeout = %d\n",
860 adapter->dbg.num_cmd_timeout);
861 dev_err(adapter->dev, "num_tx_timeout = %d\n",
862 adapter->dbg.num_tx_timeout);
863
864 dev_err(adapter->dev, "last_cmd_index = %d\n",
865 adapter->dbg.last_cmd_index);
866 print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET,
867 adapter->dbg.last_cmd_id, DBG_CMD_NUM);
868 print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET,
869 adapter->dbg.last_cmd_act, DBG_CMD_NUM);
870
871 dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
872 adapter->dbg.last_cmd_resp_index);
873 print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET,
874 adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM);
875
876 dev_err(adapter->dev, "last_event_index = %d\n",
877 adapter->dbg.last_event_index);
878 print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET,
879 adapter->dbg.last_event, DBG_CMD_NUM);
880
881 dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
882 adapter->data_sent, adapter->cmd_sent);
883
884 dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
885 adapter->ps_mode, adapter->ps_state);
886 }
887 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
888 mwifiex_init_fw_complete(adapter);
889
890 return;
891}
892
893/*
894 * This function cancels all the pending commands.
895 *
896 * The current command, all commands in command pending queue and all scan
897 * commands in scan pending queue are cancelled. All the completion callbacks
898 * are called with failure status to ensure cleanup.
899 */
900void
901mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
902{
903 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
904 struct mwifiex_wait_queue *wait_queue = NULL;
905 unsigned long flags;
906
907 /* Cancel current cmd */
908 if ((adapter->curr_cmd) && (adapter->curr_cmd->wq_buf)) {
909 wait_queue =
910 (struct mwifiex_wait_queue *) adapter->curr_cmd->wq_buf;
911 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
912 adapter->curr_cmd->wq_buf = NULL;
913 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
914 wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
915 mwifiex_ioctl_complete(adapter, wait_queue, -1);
916 }
917 /* Cancel all pending command */
918 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
919 list_for_each_entry_safe(cmd_node, tmp_node,
920 &adapter->cmd_pending_q, list) {
921 list_del(&cmd_node->list);
922 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
923
924 if (cmd_node->wq_buf) {
925 wait_queue =
926 (struct mwifiex_wait_queue *) cmd_node->wq_buf;
927 wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
928 mwifiex_ioctl_complete(adapter, wait_queue, -1);
929 cmd_node->wq_buf = NULL;
930 }
931 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
932 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
933 }
934 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
935
936 /* Cancel all pending scan command */
937 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
938 list_for_each_entry_safe(cmd_node, tmp_node,
939 &adapter->scan_pending_q, list) {
940 list_del(&cmd_node->list);
941 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
942
943 cmd_node->wq_buf = NULL;
944 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
945 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
946 }
947 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
948
949 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
950 adapter->scan_processing = false;
951 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
952}
953
954/*
955 * This function cancels all pending commands that matches with
956 * the given IOCTL request.
957 *
958 * Both the current command buffer and the pending command queue are
959 * searched for matching IOCTL request. The completion callback of
960 * the matched command is called with failure status to ensure cleanup.
961 * In case of scan commands, all pending commands in scan pending queue
962 * are cancelled.
963 */
964void
965mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
966 struct mwifiex_wait_queue *wait_queue)
967{
968 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
969 unsigned long cmd_flags;
970 unsigned long cmd_pending_q_flags;
971 unsigned long scan_pending_q_flags;
972 uint16_t cancel_scan_cmd = false;
973
974 if ((adapter->curr_cmd) &&
975 (adapter->curr_cmd->wq_buf == wait_queue)) {
976 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
977 cmd_node = adapter->curr_cmd;
978 cmd_node->wq_buf = NULL;
979 cmd_node->cmd_flag |= CMD_F_CANCELED;
980 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
981 }
982
983 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
984 while (1) {
985 cmd_node = mwifiex_get_pending_ioctl_cmd(adapter, wait_queue);
986 if (!cmd_node)
987 break;
988
989 spin_lock_irqsave(&adapter->cmd_pending_q_lock,
990 cmd_pending_q_flags);
991 list_del(&cmd_node->list);
992 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
993 cmd_pending_q_flags);
994
995 cmd_node->wq_buf = NULL;
996 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
997 }
998 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
999 /* Cancel all pending scan command */
1000 spin_lock_irqsave(&adapter->scan_pending_q_lock,
1001 scan_pending_q_flags);
1002 list_for_each_entry_safe(cmd_node, tmp_node,
1003 &adapter->scan_pending_q, list) {
1004 if (cmd_node->wq_buf == wait_queue) {
1005 list_del(&cmd_node->list);
1006 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
1007 scan_pending_q_flags);
1008 cmd_node->wq_buf = NULL;
1009 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
1010 spin_lock_irqsave(&adapter->scan_pending_q_lock,
1011 scan_pending_q_flags);
1012 cancel_scan_cmd = true;
1013 }
1014 }
1015 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
1016 scan_pending_q_flags);
1017
1018 if (cancel_scan_cmd) {
1019 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
1020 adapter->scan_processing = false;
1021 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
1022 }
1023 wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL;
1024 mwifiex_ioctl_complete(adapter, wait_queue, -1);
1025
1026 return;
1027}
1028
1029/*
1030 * This function sends the sleep confirm command to firmware, if
1031 * possible.
1032 *
1033 * The sleep confirm command cannot be issued if command response,
1034 * data response or event response is awaiting handling, or if we
1035 * are in the middle of sending a command, or expecting a command
1036 * response.
1037 */
1038void
1039mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
1040{
1041 if (!adapter->cmd_sent &&
1042 !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
1043 mwifiex_dnld_sleep_confirm_cmd(adapter);
1044 else
1045 dev_dbg(adapter->dev,
1046 "cmd: Delay Sleep Confirm (%s%s%s)\n",
1047 (adapter->cmd_sent) ? "D" : "",
1048 (adapter->curr_cmd) ? "C" : "",
1049 (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
1050}
1051
1052/*
1053 * This function sends a Host Sleep activated event to applications.
1054 *
1055 * This event is generated by the driver, with a blank event body.
1056 */
1057void
1058mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
1059{
1060 if (activated) {
1061 if (priv->adapter->is_hs_configured) {
1062 priv->adapter->hs_activated = true;
1063 dev_dbg(priv->adapter->dev, "event: hs_activated\n");
1064 priv->adapter->hs_activate_wait_q_woken = true;
1065 wake_up_interruptible(
1066 &priv->adapter->hs_activate_wait_q);
1067 } else {
1068 dev_dbg(priv->adapter->dev, "event: HS not configured\n");
1069 }
1070 } else {
1071 dev_dbg(priv->adapter->dev, "event: hs_deactivated\n");
1072 priv->adapter->hs_activated = false;
1073 }
1074}
1075
1076/*
1077 * This function handles the command response of a Host Sleep configuration
1078 * command.
1079 *
1080 * Handling includes changing the header fields into CPU format
1081 * and setting the current host sleep activation status in driver.
1082 *
1083 * In case host sleep status change, the function generates an event to
1084 * notify the applications.
1085 */
1086int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
1087 struct host_cmd_ds_command *resp)
1088{
1089 struct mwifiex_adapter *adapter = priv->adapter;
1090 struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg =
1091 &resp->params.opt_hs_cfg;
1092 uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
1093
1094 if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
1095 mwifiex_hs_activated_event(priv, true);
1096 return 0;
1097 } else {
1098 dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply"
1099 " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
1100 resp->result, conditions,
1101 phs_cfg->params.hs_config.gpio,
1102 phs_cfg->params.hs_config.gap);
1103 }
1104 if (conditions != HOST_SLEEP_CFG_CANCEL) {
1105 adapter->is_hs_configured = true;
1106 } else {
1107 adapter->is_hs_configured = false;
1108 if (adapter->hs_activated)
1109 mwifiex_hs_activated_event(priv, false);
1110 }
1111
1112 return 0;
1113}
1114
1115/*
1116 * This function wakes up the adapter and generates a Host Sleep
1117 * cancel event on receiving the power up interrupt.
1118 */
1119void
1120mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
1121{
1122 dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep"
1123 " since there is interrupt from the firmware\n", __func__);
1124
1125 adapter->if_ops.wakeup(adapter);
1126 adapter->hs_activated = false;
1127 adapter->is_hs_configured = false;
1128 mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
1129 MWIFIEX_BSS_ROLE_ANY), false);
1130 return;
1131}
1132
1133/*
1134 * This function handles the command response of a sleep confirm command.
1135 *
1136 * The function sets the card state to SLEEP if the response indicates success.
1137 */
1138void
1139mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
1140 u8 *pbuf, u32 upld_len)
1141{
1142 struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf;
1143 struct mwifiex_private *priv =
1144 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
1145 uint16_t result = le16_to_cpu(cmd->result);
1146 uint16_t command = le16_to_cpu(cmd->command);
1147 uint16_t seq_num = le16_to_cpu(cmd->seq_num);
1148
1149 if (!upld_len) {
1150 dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
1151 return;
1152 }
1153
1154 /* Get BSS number and corresponding priv */
1155 priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
1156 HostCmd_GET_BSS_TYPE(seq_num));
1157 if (!priv)
1158 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
1159
1160 /* Update sequence number */
1161 seq_num = HostCmd_GET_SEQ_NO(seq_num);
1162 /* Clear RET_BIT from HostCmd */
1163 command &= HostCmd_CMD_ID_MASK;
1164
1165 if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
1166 dev_err(adapter->dev, "%s: received unexpected response for"
1167 " cmd %x, result = %x\n", __func__, command, result);
1168 return;
1169 }
1170
1171 if (result) {
1172 dev_err(adapter->dev, "%s: sleep confirm cmd failed\n",
1173 __func__);
1174 adapter->pm_wakeup_card_req = false;
1175 adapter->ps_state = PS_STATE_AWAKE;
1176 return;
1177 }
1178 adapter->pm_wakeup_card_req = true;
1179 if (adapter->is_hs_configured)
1180 mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
1181 MWIFIEX_BSS_ROLE_ANY), true);
1182 adapter->ps_state = PS_STATE_SLEEP;
1183 cmd->command = cpu_to_le16(command);
1184 cmd->seq_num = cpu_to_le16(seq_num);
1185}
1186EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp);
1187
1188/*
1189 * This function prepares an enhanced power mode command.
1190 *
1191 * This function can be used to disable power save or to configure
1192 * power save with auto PS or STA PS or auto deep sleep.
1193 *
1194 * Preparation includes -
1195 * - Setting command ID, action and proper size
1196 * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV,
1197 * auto deep sleep TLV (as required)
1198 * - Ensuring correct endian-ness
1199 */
1200int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
1201 struct host_cmd_ds_command *cmd,
1202 u16 cmd_action, uint16_t ps_bitmap,
1203 void *data_buf)
1204{
1205 struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh =
1206 &cmd->params.psmode_enh;
1207 u8 *tlv = NULL;
1208 u16 cmd_size = 0;
1209
1210 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
1211 if (cmd_action == DIS_AUTO_PS) {
1212 psmode_enh->action = cpu_to_le16(DIS_AUTO_PS);
1213 psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
1214 cmd->size = cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
1215 } else if (cmd_action == GET_PS) {
1216 psmode_enh->action = cpu_to_le16(GET_PS);
1217 psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
1218 cmd->size = cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE);
1219 } else if (cmd_action == EN_AUTO_PS) {
1220 psmode_enh->action = cpu_to_le16(EN_AUTO_PS);
1221 psmode_enh->params.auto_ps.ps_bitmap = cpu_to_le16(ps_bitmap);
1222 cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE;
1223 tlv = (u8 *) cmd + cmd_size;
1224 if (ps_bitmap & BITMAP_STA_PS) {
1225 struct mwifiex_adapter *adapter = priv->adapter;
1226 struct mwifiex_ie_types_ps_param *ps_tlv =
1227 (struct mwifiex_ie_types_ps_param *) tlv;
1228 struct mwifiex_ps_param *ps_mode = &ps_tlv->param;
1229 ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM);
1230 ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) -
1231 sizeof(struct mwifiex_ie_types_header));
1232 cmd_size += sizeof(*ps_tlv);
1233 tlv += sizeof(*ps_tlv);
1234 dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n");
1235 ps_mode->null_pkt_interval =
1236 cpu_to_le16(adapter->null_pkt_interval);
1237 ps_mode->multiple_dtims =
1238 cpu_to_le16(adapter->multiple_dtim);
1239 ps_mode->bcn_miss_timeout =
1240 cpu_to_le16(adapter->bcn_miss_time_out);
1241 ps_mode->local_listen_interval =
1242 cpu_to_le16(adapter->local_listen_interval);
1243 ps_mode->adhoc_wake_period =
1244 cpu_to_le16(adapter->adhoc_awake_period);
1245 ps_mode->delay_to_ps =
1246 cpu_to_le16(adapter->delay_to_ps);
1247 ps_mode->mode =
1248 cpu_to_le16(adapter->enhanced_ps_mode);
1249
1250 }
1251 if (ps_bitmap & BITMAP_AUTO_DS) {
1252 struct mwifiex_ie_types_auto_ds_param *auto_ps_tlv =
1253 (struct mwifiex_ie_types_auto_ds_param *) tlv;
1254 struct mwifiex_auto_ds_param *auto_ds =
1255 &auto_ps_tlv->param;
1256 u16 idletime = 0;
1257 auto_ps_tlv->header.type =
1258 cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
1259 auto_ps_tlv->header.len =
1260 cpu_to_le16(sizeof(*auto_ps_tlv) -
1261 sizeof(struct mwifiex_ie_types_header));
1262 cmd_size += sizeof(*auto_ps_tlv);
1263 tlv += sizeof(*auto_ps_tlv);
1264 if (data_buf)
1265 idletime = ((struct mwifiex_ds_auto_ds *)
1266 data_buf)->idle_time;
1267 dev_dbg(priv->adapter->dev,
1268 "cmd: PS Command: Enter Auto Deep Sleep\n");
1269 auto_ds->deep_sleep_timeout = cpu_to_le16(idletime);
1270 }
1271 cmd->size = cpu_to_le16(cmd_size);
1272 }
1273 return 0;
1274}
1275
1276/*
1277 * This function handles the command response of an enhanced power mode
1278 * command.
1279 *
1280 * Handling includes changing the header fields into CPU format
1281 * and setting the current enhanced power mode in driver.
1282 */
1283int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
1284 struct host_cmd_ds_command *resp,
1285 void *data_buf)
1286{
1287 struct mwifiex_adapter *adapter = priv->adapter;
1288 struct host_cmd_ds_802_11_ps_mode_enh *ps_mode =
1289 &resp->params.psmode_enh;
1290 uint16_t action = le16_to_cpu(ps_mode->action);
1291 uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap);
1292 uint16_t auto_ps_bitmap =
1293 le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap);
1294
1295 dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
1296 __func__, resp->result, action);
1297 if (action == EN_AUTO_PS) {
1298 if (auto_ps_bitmap & BITMAP_AUTO_DS) {
1299 dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n");
1300 priv->adapter->is_deep_sleep = true;
1301 }
1302 if (auto_ps_bitmap & BITMAP_STA_PS) {
1303 dev_dbg(adapter->dev, "cmd: Enabled STA power save\n");
1304 if (adapter->sleep_period.period)
1305 dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n");
1306 }
1307 } else if (action == DIS_AUTO_PS) {
1308 if (ps_bitmap & BITMAP_AUTO_DS) {
1309 priv->adapter->is_deep_sleep = false;
1310 dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n");
1311 }
1312 if (ps_bitmap & BITMAP_STA_PS) {
1313 dev_dbg(adapter->dev, "cmd: Disabled STA power save\n");
1314 if (adapter->sleep_period.period) {
1315 adapter->delay_null_pkt = false;
1316 adapter->tx_lock_flag = false;
1317 adapter->pps_uapsd_mode = false;
1318 }
1319 }
1320 } else if (action == GET_PS) {
1321 if (ps_bitmap & (BITMAP_STA_PS | BITMAP_UAP_INACT_PS
1322 | BITMAP_UAP_DTIM_PS))
1323 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1324 else
1325 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
1326
1327 dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap);
1328
1329 if (data_buf) {
1330 /* This section is for get power save mode */
1331 struct mwifiex_ds_pm_cfg *pm_cfg =
1332 (struct mwifiex_ds_pm_cfg *)data_buf;
1333 if (ps_bitmap & BITMAP_STA_PS)
1334 pm_cfg->param.ps_mode = 1;
1335 else
1336 pm_cfg->param.ps_mode = 0;
1337 }
1338 }
1339 return 0;
1340}
1341
1342/*
1343 * This function prepares command to get hardware specifications.
1344 *
1345 * Preparation includes -
1346 * - Setting command ID, action and proper size
1347 * - Setting permanent address parameter
1348 * - Ensuring correct endian-ness
1349 */
1350int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
1351 struct host_cmd_ds_command *cmd)
1352{
1353 struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec;
1354
1355 cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
1356 cmd->size =
1357 cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN);
1358 memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN);
1359
1360 return 0;
1361}
1362
1363/*
1364 * This function handles the command response of get hardware
1365 * specifications.
1366 *
1367 * Handling includes changing the header fields into CPU format
1368 * and saving/updating the following parameters in driver -
1369 * - Firmware capability information
1370 * - Firmware band settings
1371 * - Ad-hoc start band and channel
1372 * - Ad-hoc 11n activation status
1373 * - Firmware release number
1374 * - Number of antennas
1375 * - Hardware address
1376 * - Hardware interface version
1377 * - Firmware version
1378 * - Region code
1379 * - 11n capabilities
1380 * - MCS support fields
1381 * - MP end port
1382 */
1383int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
1384 struct host_cmd_ds_command *resp)
1385{
1386 struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
1387 struct mwifiex_adapter *adapter = priv->adapter;
1388 int i;
1389
1390 adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info);
1391
1392 if (IS_SUPPORT_MULTI_BANDS(adapter))
1393 adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter);
1394 else
1395 adapter->fw_bands = BAND_B;
1396
1397 adapter->config_bands = adapter->fw_bands;
1398
1399 if (adapter->fw_bands & BAND_A) {
1400 if (adapter->fw_bands & BAND_GN) {
1401 adapter->config_bands |= BAND_AN;
1402 adapter->fw_bands |= BAND_AN;
1403 }
1404 if (adapter->fw_bands & BAND_AN) {
1405 adapter->adhoc_start_band = BAND_A | BAND_AN;
1406 adapter->adhoc_11n_enabled = true;
1407 } else {
1408 adapter->adhoc_start_band = BAND_A;
1409 }
1410 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
1411 } else if (adapter->fw_bands & BAND_GN) {
1412 adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
1413 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
1414 adapter->adhoc_11n_enabled = true;
1415 } else if (adapter->fw_bands & BAND_G) {
1416 adapter->adhoc_start_band = BAND_G | BAND_B;
1417 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
1418 } else if (adapter->fw_bands & BAND_B) {
1419 adapter->adhoc_start_band = BAND_B;
1420 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
1421 }
1422
1423 adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
1424 adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
1425
1426 dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
1427 adapter->fw_release_number);
1428 dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
1429 hw_spec->permanent_addr);
1430 dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
1431 le16_to_cpu(hw_spec->hw_if_version),
1432 le16_to_cpu(hw_spec->version));
1433
1434 if (priv->curr_addr[0] == 0xff)
1435 memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN);
1436
1437 adapter->region_code = le16_to_cpu(hw_spec->region_code);
1438
1439 for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++)
1440 /* Use the region code to search for the index */
1441 if (adapter->region_code == region_code_index[i])
1442 break;
1443
1444 /* If it's unidentified region code, use the default (USA) */
1445 if (i >= MWIFIEX_MAX_REGION_CODE) {
1446 adapter->region_code = 0x10;
1447 dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n");
1448 }
1449
1450 adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
1451 adapter->usr_dot_11n_dev_cap = adapter->hw_dot_11n_dev_cap &
1452 DEFAULT_11N_CAP_MASK;
1453 adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
1454 adapter->usr_dev_mcs_support = adapter->hw_dev_mcs_support;
1455 mwifiex_show_dot_11n_dev_cap(adapter, adapter->hw_dot_11n_dev_cap);
1456 mwifiex_show_dev_mcs_support(adapter, adapter->hw_dev_mcs_support);
1457
1458 if (adapter->if_ops.update_mp_end_port)
1459 adapter->if_ops.update_mp_end_port(adapter,
1460 le16_to_cpu(hw_spec->mp_end_port));
1461
1462 return 0;
1463}
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
new file mode 100644
index 000000000000..63b09692f27d
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -0,0 +1,773 @@
1/*
2 * Marvell Wireless LAN device driver: debugfs
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include <linux/debugfs.h>
21
22#include "main.h"
23#include "11n.h"
24
25
26static struct dentry *mwifiex_dfs_dir;
27
28static char *bss_modes[] = {
29 "Unknown",
30 "Managed",
31 "Ad-hoc",
32 "Auto"
33};
34
35/* size/addr for mwifiex_debug_info */
36#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n))
37#define item_addr(n) (offsetof(struct mwifiex_debug_info, n))
38
39/* size/addr for struct mwifiex_adapter */
40#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n))
41#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n))
42
43struct mwifiex_debug_data {
44 char name[32]; /* variable/array name */
45 u32 size; /* size of the variable/array */
46 size_t addr; /* address of the variable/array */
47 int num; /* number of variables in an array */
48};
49
50static struct mwifiex_debug_data items[] = {
51 {"int_counter", item_size(int_counter),
52 item_addr(int_counter), 1},
53 {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
54 item_addr(packets_out[WMM_AC_VO]), 1},
55 {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
56 item_addr(packets_out[WMM_AC_VI]), 1},
57 {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
58 item_addr(packets_out[WMM_AC_BE]), 1},
59 {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
60 item_addr(packets_out[WMM_AC_BK]), 1},
61 {"max_tx_buf_size", item_size(max_tx_buf_size),
62 item_addr(max_tx_buf_size), 1},
63 {"tx_buf_size", item_size(tx_buf_size),
64 item_addr(tx_buf_size), 1},
65 {"curr_tx_buf_size", item_size(curr_tx_buf_size),
66 item_addr(curr_tx_buf_size), 1},
67 {"ps_mode", item_size(ps_mode),
68 item_addr(ps_mode), 1},
69 {"ps_state", item_size(ps_state),
70 item_addr(ps_state), 1},
71 {"is_deep_sleep", item_size(is_deep_sleep),
72 item_addr(is_deep_sleep), 1},
73 {"wakeup_dev_req", item_size(pm_wakeup_card_req),
74 item_addr(pm_wakeup_card_req), 1},
75 {"wakeup_tries", item_size(pm_wakeup_fw_try),
76 item_addr(pm_wakeup_fw_try), 1},
77 {"hs_configured", item_size(is_hs_configured),
78 item_addr(is_hs_configured), 1},
79 {"hs_activated", item_size(hs_activated),
80 item_addr(hs_activated), 1},
81 {"num_tx_timeout", item_size(num_tx_timeout),
82 item_addr(num_tx_timeout), 1},
83 {"num_cmd_timeout", item_size(num_cmd_timeout),
84 item_addr(num_cmd_timeout), 1},
85 {"timeout_cmd_id", item_size(timeout_cmd_id),
86 item_addr(timeout_cmd_id), 1},
87 {"timeout_cmd_act", item_size(timeout_cmd_act),
88 item_addr(timeout_cmd_act), 1},
89 {"last_cmd_id", item_size(last_cmd_id),
90 item_addr(last_cmd_id), DBG_CMD_NUM},
91 {"last_cmd_act", item_size(last_cmd_act),
92 item_addr(last_cmd_act), DBG_CMD_NUM},
93 {"last_cmd_index", item_size(last_cmd_index),
94 item_addr(last_cmd_index), 1},
95 {"last_cmd_resp_id", item_size(last_cmd_resp_id),
96 item_addr(last_cmd_resp_id), DBG_CMD_NUM},
97 {"last_cmd_resp_index", item_size(last_cmd_resp_index),
98 item_addr(last_cmd_resp_index), 1},
99 {"last_event", item_size(last_event),
100 item_addr(last_event), DBG_CMD_NUM},
101 {"last_event_index", item_size(last_event_index),
102 item_addr(last_event_index), 1},
103 {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
104 item_addr(num_cmd_host_to_card_failure), 1},
105 {"num_cmd_sleep_cfm_fail",
106 item_size(num_cmd_sleep_cfm_host_to_card_failure),
107 item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
108 {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
109 item_addr(num_tx_host_to_card_failure), 1},
110 {"num_evt_deauth", item_size(num_event_deauth),
111 item_addr(num_event_deauth), 1},
112 {"num_evt_disassoc", item_size(num_event_disassoc),
113 item_addr(num_event_disassoc), 1},
114 {"num_evt_link_lost", item_size(num_event_link_lost),
115 item_addr(num_event_link_lost), 1},
116 {"num_cmd_deauth", item_size(num_cmd_deauth),
117 item_addr(num_cmd_deauth), 1},
118 {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
119 item_addr(num_cmd_assoc_success), 1},
120 {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
121 item_addr(num_cmd_assoc_failure), 1},
122 {"cmd_sent", item_size(cmd_sent),
123 item_addr(cmd_sent), 1},
124 {"data_sent", item_size(data_sent),
125 item_addr(data_sent), 1},
126 {"cmd_resp_received", item_size(cmd_resp_received),
127 item_addr(cmd_resp_received), 1},
128 {"event_received", item_size(event_received),
129 item_addr(event_received), 1},
130
131 /* variables defined in struct mwifiex_adapter */
132 {"ioctl_pending", adapter_item_size(ioctl_pending),
133 adapter_item_addr(ioctl_pending), 1},
134 {"tx_pending", adapter_item_size(tx_pending),
135 adapter_item_addr(tx_pending), 1},
136 {"rx_pending", adapter_item_size(rx_pending),
137 adapter_item_addr(rx_pending), 1},
138};
139
140static int num_of_items = ARRAY_SIZE(items);
141
142/*
143 * Generic proc file open handler.
144 *
145 * This function is called every time a file is accessed for read or write.
146 */
147static int
148mwifiex_open_generic(struct inode *inode, struct file *file)
149{
150 file->private_data = inode->i_private;
151 return 0;
152}
153
154/*
155 * Proc info file read handler.
156 *
157 * This function is called when the 'info' file is opened for reading.
158 * It prints the following driver related information -
159 * - Driver name
160 * - Driver version
161 * - Driver extended version
162 * - Interface name
163 * - BSS mode
164 * - Media state (connected or disconnected)
165 * - MAC address
166 * - Total number of Tx bytes
167 * - Total number of Rx bytes
168 * - Total number of Tx packets
169 * - Total number of Rx packets
170 * - Total number of dropped Tx packets
171 * - Total number of dropped Rx packets
172 * - Total number of corrupted Tx packets
173 * - Total number of corrupted Rx packets
174 * - Carrier status (on or off)
175 * - Tx queue status (started or stopped)
176 *
177 * For STA mode drivers, it also prints the following extra -
178 * - ESSID
179 * - BSSID
180 * - Channel
181 * - Region code
182 * - Multicast count
183 * - Multicast addresses
184 */
185static ssize_t
186mwifiex_info_read(struct file *file, char __user *ubuf,
187 size_t count, loff_t *ppos)
188{
189 struct mwifiex_private *priv =
190 (struct mwifiex_private *) file->private_data;
191 struct net_device *netdev = priv->netdev;
192 struct netdev_hw_addr *ha;
193 unsigned long page = get_zeroed_page(GFP_KERNEL);
194 char *p = (char *) page, fmt[64];
195 struct mwifiex_bss_info info;
196 ssize_t ret = 0;
197 int i = 0;
198
199 if (!p)
200 return -ENOMEM;
201
202 memset(&info, 0, sizeof(info));
203 ret = mwifiex_get_bss_info(priv, &info);
204 if (ret)
205 goto free_and_exit;
206
207 mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
208
209 if (!priv->version_str[0])
210 mwifiex_get_ver_ext(priv);
211
212 p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
213 p += sprintf(p, "driver_version = %s", fmt);
214 p += sprintf(p, "\nverext = %s", priv->version_str);
215 p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
216 p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
217 p += sprintf(p, "media_state=\"%s\"\n",
218 (!priv->media_connected ? "Disconnected" : "Connected"));
219 p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
220 netdev->dev_addr[0], netdev->dev_addr[1],
221 netdev->dev_addr[2], netdev->dev_addr[3],
222 netdev->dev_addr[4], netdev->dev_addr[5]);
223
224 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
225 p += sprintf(p, "multicast_count=\"%d\"\n",
226 netdev_mc_count(netdev));
227 p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
228 p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
229 info.bssid[0], info.bssid[1],
230 info.bssid[2], info.bssid[3],
231 info.bssid[4], info.bssid[5]);
232 p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
233 p += sprintf(p, "region_code = \"%02x\"\n", info.region_code);
234
235 netdev_for_each_mc_addr(ha, netdev)
236 p += sprintf(p, "multicast_address[%d]="
237 "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++,
238 ha->addr[0], ha->addr[1],
239 ha->addr[2], ha->addr[3],
240 ha->addr[4], ha->addr[5]);
241 }
242
243 p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
244 p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
245 p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
246 p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
247 p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
248 p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
249 p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
250 p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
251 p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
252 ? "on" : "off"));
253 p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev))
254 ? "stopped" : "started"));
255
256 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
257 (unsigned long) p - page);
258
259free_and_exit:
260 free_page(page);
261 return ret;
262}
263
264/*
265 * Proc getlog file read handler.
266 *
267 * This function is called when the 'getlog' file is opened for reading
268 * It prints the following log information -
269 * - Number of multicast Tx frames
270 * - Number of failed packets
271 * - Number of Tx retries
272 * - Number of multicast Tx retries
273 * - Number of duplicate frames
274 * - Number of RTS successes
275 * - Number of RTS failures
276 * - Number of ACK failures
277 * - Number of fragmented Rx frames
278 * - Number of multicast Rx frames
279 * - Number of FCS errors
280 * - Number of Tx frames
281 * - WEP ICV error counts
282 */
283static ssize_t
284mwifiex_getlog_read(struct file *file, char __user *ubuf,
285 size_t count, loff_t *ppos)
286{
287 struct mwifiex_private *priv =
288 (struct mwifiex_private *) file->private_data;
289 unsigned long page = get_zeroed_page(GFP_KERNEL);
290 char *p = (char *) page;
291 ssize_t ret = 0;
292 struct mwifiex_ds_get_stats stats;
293
294 if (!p)
295 return -ENOMEM;
296
297 memset(&stats, 0, sizeof(stats));
298 ret = mwifiex_get_stats_info(priv, &stats);
299 if (ret)
300 goto free_and_exit;
301
302 p += sprintf(p, "\n"
303 "mcasttxframe %u\n"
304 "failed %u\n"
305 "retry %u\n"
306 "multiretry %u\n"
307 "framedup %u\n"
308 "rtssuccess %u\n"
309 "rtsfailure %u\n"
310 "ackfailure %u\n"
311 "rxfrag %u\n"
312 "mcastrxframe %u\n"
313 "fcserror %u\n"
314 "txframe %u\n"
315 "wepicverrcnt-1 %u\n"
316 "wepicverrcnt-2 %u\n"
317 "wepicverrcnt-3 %u\n"
318 "wepicverrcnt-4 %u\n",
319 stats.mcast_tx_frame,
320 stats.failed,
321 stats.retry,
322 stats.multi_retry,
323 stats.frame_dup,
324 stats.rts_success,
325 stats.rts_failure,
326 stats.ack_failure,
327 stats.rx_frag,
328 stats.mcast_rx_frame,
329 stats.fcs_error,
330 stats.tx_frame,
331 stats.wep_icv_error[0],
332 stats.wep_icv_error[1],
333 stats.wep_icv_error[2],
334 stats.wep_icv_error[3]);
335
336
337 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
338 (unsigned long) p - page);
339
340free_and_exit:
341 free_page(page);
342 return ret;
343}
344
345static struct mwifiex_debug_info info;
346
347/*
348 * Proc debug file read handler.
349 *
350 * This function is called when the 'debug' file is opened for reading
351 * It prints the following log information -
352 * - Interrupt count
353 * - WMM AC VO packets count
354 * - WMM AC VI packets count
355 * - WMM AC BE packets count
356 * - WMM AC BK packets count
357 * - Maximum Tx buffer size
358 * - Tx buffer size
359 * - Current Tx buffer size
360 * - Power Save mode
361 * - Power Save state
362 * - Deep Sleep status
363 * - Device wakeup required status
364 * - Number of wakeup tries
365 * - Host Sleep configured status
366 * - Host Sleep activated status
367 * - Number of Tx timeouts
368 * - Number of command timeouts
369 * - Last timed out command ID
370 * - Last timed out command action
371 * - Last command ID
372 * - Last command action
373 * - Last command index
374 * - Last command response ID
375 * - Last command response index
376 * - Last event
377 * - Last event index
378 * - Number of host to card command failures
379 * - Number of sleep confirm command failures
380 * - Number of host to card data failure
381 * - Number of deauthentication events
382 * - Number of disassociation events
383 * - Number of link lost events
384 * - Number of deauthentication commands
385 * - Number of association success commands
386 * - Number of association failure commands
387 * - Number of commands sent
388 * - Number of data packets sent
389 * - Number of command responses received
390 * - Number of events received
391 * - Tx BA stream table (TID, RA)
392 * - Rx reorder table (TID, TA, Start window, Window size, Buffer)
393 */
394static ssize_t
395mwifiex_debug_read(struct file *file, char __user *ubuf,
396 size_t count, loff_t *ppos)
397{
398 struct mwifiex_private *priv =
399 (struct mwifiex_private *) file->private_data;
400 struct mwifiex_debug_data *d = &items[0];
401 unsigned long page = get_zeroed_page(GFP_KERNEL);
402 char *p = (char *) page;
403 ssize_t ret = 0;
404 size_t size, addr;
405 long val;
406 int i, j;
407
408 if (!p)
409 return -ENOMEM;
410
411 ret = mwifiex_get_debug_info(priv, &info);
412 if (ret)
413 goto free_and_exit;
414
415 for (i = 0; i < num_of_items; i++) {
416 p += sprintf(p, "%s=", d[i].name);
417
418 size = d[i].size / d[i].num;
419
420 if (i < (num_of_items - 3))
421 addr = d[i].addr + (size_t) &info;
422 else /* The last 3 items are struct mwifiex_adapter variables */
423 addr = d[i].addr + (size_t) priv->adapter;
424
425 for (j = 0; j < d[i].num; j++) {
426 switch (size) {
427 case 1:
428 val = *((u8 *) addr);
429 break;
430 case 2:
431 val = *((u16 *) addr);
432 break;
433 case 4:
434 val = *((u32 *) addr);
435 break;
436 case 8:
437 val = *((long long *) addr);
438 break;
439 default:
440 val = -1;
441 break;
442 }
443
444 p += sprintf(p, "%#lx ", val);
445 addr += size;
446 }
447
448 p += sprintf(p, "\n");
449 }
450
451 if (info.tx_tbl_num) {
452 p += sprintf(p, "Tx BA stream table:\n");
453 for (i = 0; i < info.tx_tbl_num; i++)
454 p += sprintf(p, "tid = %d, "
455 "ra = %02x:%02x:%02x:%02x:%02x:%02x\n",
456 info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
457 info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
458 info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
459 info.tx_tbl[i].ra[5]);
460 }
461
462 if (info.rx_tbl_num) {
463 p += sprintf(p, "Rx reorder table:\n");
464 for (i = 0; i < info.rx_tbl_num; i++) {
465
466 p += sprintf(p, "tid = %d, "
467 "ta = %02x:%02x:%02x:%02x:%02x:%02x, "
468 "start_win = %d, "
469 "win_size = %d, buffer: ",
470 info.rx_tbl[i].tid,
471 info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
472 info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
473 info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
474 info.rx_tbl[i].start_win,
475 info.rx_tbl[i].win_size);
476
477 for (j = 0; j < info.rx_tbl[i].win_size; j++)
478 p += sprintf(p, "%c ",
479 info.rx_tbl[i].buffer[j] ?
480 '1' : '0');
481
482 p += sprintf(p, "\n");
483 }
484 }
485
486 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
487 (unsigned long) p - page);
488
489free_and_exit:
490 free_page(page);
491 return ret;
492}
493
494static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
495
496/*
497 * Proc regrdwr file write handler.
498 *
499 * This function is called when the 'regrdwr' file is opened for writing
500 *
501 * This function can be used to write to a register.
502 */
503static ssize_t
504mwifiex_regrdwr_write(struct file *file,
505 const char __user *ubuf, size_t count, loff_t *ppos)
506{
507 unsigned long addr = get_zeroed_page(GFP_KERNEL);
508 char *buf = (char *) addr;
509 size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
510 int ret = 0;
511 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
512
513 if (!buf)
514 return -ENOMEM;
515
516
517 if (copy_from_user(buf, ubuf, buf_size)) {
518 ret = -EFAULT;
519 goto done;
520 }
521
522 sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
523
524 if (reg_type == 0 || reg_offset == 0) {
525 ret = -EINVAL;
526 goto done;
527 } else {
528 saved_reg_type = reg_type;
529 saved_reg_offset = reg_offset;
530 saved_reg_value = reg_value;
531 ret = count;
532 }
533done:
534 free_page(addr);
535 return ret;
536}
537
538/*
539 * Proc regrdwr file read handler.
540 *
541 * This function is called when the 'regrdwr' file is opened for reading
542 *
543 * This function can be used to read from a register.
544 */
545static ssize_t
546mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
547 size_t count, loff_t *ppos)
548{
549 struct mwifiex_private *priv =
550 (struct mwifiex_private *) file->private_data;
551 unsigned long addr = get_zeroed_page(GFP_KERNEL);
552 char *buf = (char *) addr;
553 int pos = 0, ret = 0;
554 u32 reg_value;
555
556 if (!buf)
557 return -ENOMEM;
558
559 if (!saved_reg_type) {
560 /* No command has been given */
561 pos += snprintf(buf, PAGE_SIZE, "0");
562 goto done;
563 }
564 /* Set command has been given */
565 if (saved_reg_value != UINT_MAX) {
566 ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
567 saved_reg_value);
568
569 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
570 saved_reg_type, saved_reg_offset,
571 saved_reg_value);
572
573 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
574
575 goto done;
576 }
577 /* Get command has been given */
578 ret = mwifiex_reg_read(priv, saved_reg_type,
579 saved_reg_offset, &reg_value);
580 if (ret) {
581 ret = -EINVAL;
582 goto done;
583 }
584
585 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
586 saved_reg_offset, reg_value);
587
588 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
589
590done:
591 free_page(addr);
592 return ret;
593}
594
595static u32 saved_offset = -1, saved_bytes = -1;
596
597/*
598 * Proc rdeeprom file write handler.
599 *
600 * This function is called when the 'rdeeprom' file is opened for writing
601 *
602 * This function can be used to write to a RDEEPROM location.
603 */
604static ssize_t
605mwifiex_rdeeprom_write(struct file *file,
606 const char __user *ubuf, size_t count, loff_t *ppos)
607{
608 unsigned long addr = get_zeroed_page(GFP_KERNEL);
609 char *buf = (char *) addr;
610 size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
611 int ret = 0;
612 int offset = -1, bytes = -1;
613
614 if (!buf)
615 return -ENOMEM;
616
617
618 if (copy_from_user(buf, ubuf, buf_size)) {
619 ret = -EFAULT;
620 goto done;
621 }
622
623 sscanf(buf, "%d %d", &offset, &bytes);
624
625 if (offset == -1 || bytes == -1) {
626 ret = -EINVAL;
627 goto done;
628 } else {
629 saved_offset = offset;
630 saved_bytes = bytes;
631 ret = count;
632 }
633done:
634 free_page(addr);
635 return ret;
636}
637
638/*
639 * Proc rdeeprom read write handler.
640 *
641 * This function is called when the 'rdeeprom' file is opened for reading
642 *
643 * This function can be used to read from a RDEEPROM location.
644 */
645static ssize_t
646mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
647 size_t count, loff_t *ppos)
648{
649 struct mwifiex_private *priv =
650 (struct mwifiex_private *) file->private_data;
651 unsigned long addr = get_zeroed_page(GFP_KERNEL);
652 char *buf = (char *) addr;
653 int pos = 0, ret = 0, i = 0;
654 u8 value[MAX_EEPROM_DATA];
655
656 if (!buf)
657 return -ENOMEM;
658
659 if (saved_offset == -1) {
660 /* No command has been given */
661 pos += snprintf(buf, PAGE_SIZE, "0");
662 goto done;
663 }
664
665 /* Get command has been given */
666 ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
667 (u16) saved_bytes, value);
668 if (ret) {
669 ret = -EINVAL;
670 goto done;
671 }
672
673 pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
674
675 for (i = 0; i < saved_bytes; i++)
676 pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
677
678 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
679
680done:
681 free_page(addr);
682 return ret;
683}
684
685
686#define MWIFIEX_DFS_ADD_FILE(name) do { \
687 if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \
688 priv, &mwifiex_dfs_##name##_fops)) \
689 return; \
690} while (0);
691
692#define MWIFIEX_DFS_FILE_OPS(name) \
693static const struct file_operations mwifiex_dfs_##name##_fops = { \
694 .read = mwifiex_##name##_read, \
695 .write = mwifiex_##name##_write, \
696 .open = mwifiex_open_generic, \
697};
698
699#define MWIFIEX_DFS_FILE_READ_OPS(name) \
700static const struct file_operations mwifiex_dfs_##name##_fops = { \
701 .read = mwifiex_##name##_read, \
702 .open = mwifiex_open_generic, \
703};
704
705#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \
706static const struct file_operations mwifiex_dfs_##name##_fops = { \
707 .write = mwifiex_##name##_write, \
708 .open = mwifiex_open_generic, \
709};
710
711
712MWIFIEX_DFS_FILE_READ_OPS(info);
713MWIFIEX_DFS_FILE_READ_OPS(debug);
714MWIFIEX_DFS_FILE_READ_OPS(getlog);
715MWIFIEX_DFS_FILE_OPS(regrdwr);
716MWIFIEX_DFS_FILE_OPS(rdeeprom);
717
718/*
719 * This function creates the debug FS directory structure and the files.
720 */
721void
722mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
723{
724 if (!mwifiex_dfs_dir || !priv)
725 return;
726
727 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
728 mwifiex_dfs_dir);
729
730 if (!priv->dfs_dev_dir)
731 return;
732
733 MWIFIEX_DFS_ADD_FILE(info);
734 MWIFIEX_DFS_ADD_FILE(debug);
735 MWIFIEX_DFS_ADD_FILE(getlog);
736 MWIFIEX_DFS_ADD_FILE(regrdwr);
737 MWIFIEX_DFS_ADD_FILE(rdeeprom);
738
739 return;
740}
741
742/*
743 * This function removes the debug FS directory structure and the files.
744 */
745void
746mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
747{
748 if (!priv)
749 return;
750
751 debugfs_remove_recursive(priv->dfs_dev_dir);
752 return;
753}
754
755/*
756 * This function creates the top level proc directory.
757 */
758void
759mwifiex_debugfs_init(void)
760{
761 if (!mwifiex_dfs_dir)
762 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
763}
764
765/*
766 * This function removes the top level proc directory.
767 */
768void
769mwifiex_debugfs_remove(void)
770{
771 if (mwifiex_dfs_dir)
772 debugfs_remove(mwifiex_dfs_dir);
773}
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
new file mode 100644
index 000000000000..4e1f115d3ec3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -0,0 +1,177 @@
1/*
2 * Marvell Wireless LAN device driver: generic data structures and APIs
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_DECL_H_
21#define _MWIFIEX_DECL_H_
22
23#undef pr_fmt
24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
26#include <linux/wait.h>
27#include <linux/timer.h>
28#include <linux/ieee80211.h>
29
30
31#define MWIFIEX_MAX_BSS_NUM (1)
32
33#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */
34
35#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
36#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
37
38#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32
39#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16
40#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
41
42#define MWIFIEX_RATE_INDEX_HRDSSS0 0
43#define MWIFIEX_RATE_INDEX_HRDSSS3 3
44#define MWIFIEX_RATE_INDEX_OFDM0 4
45#define MWIFIEX_RATE_INDEX_OFDM7 11
46#define MWIFIEX_RATE_INDEX_MCS0 12
47
48#define MWIFIEX_RATE_BITMAP_OFDM0 16
49#define MWIFIEX_RATE_BITMAP_OFDM7 23
50#define MWIFIEX_RATE_BITMAP_MCS0 32
51#define MWIFIEX_RATE_BITMAP_MCS127 159
52
53#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024)
54#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024)
55
56#define MWIFIEX_RTS_MIN_VALUE (0)
57#define MWIFIEX_RTS_MAX_VALUE (2347)
58#define MWIFIEX_FRAG_MIN_VALUE (256)
59#define MWIFIEX_FRAG_MAX_VALUE (2346)
60
61#define MWIFIEX_SDIO_BLOCK_SIZE 256
62
63#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
64
65enum mwifiex_error_code {
66 MWIFIEX_ERROR_NO_ERROR = 0,
67 MWIFIEX_ERROR_FW_NOT_READY = 0x00000001,
68 MWIFIEX_ERROR_FW_BUSY,
69 MWIFIEX_ERROR_FW_CMDRESP,
70 MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001,
71 MWIFIEX_ERROR_PKT_TIMEOUT,
72 MWIFIEX_ERROR_CMD_INVALID,
73 MWIFIEX_ERROR_CMD_TIMEOUT,
74 MWIFIEX_ERROR_CMD_DNLD_FAIL,
75 MWIFIEX_ERROR_CMD_CANCEL,
76 MWIFIEX_ERROR_CMD_RESP_FAIL,
77 MWIFIEX_ERROR_ASSOC_FAIL,
78 MWIFIEX_ERROR_EVENT_UNKNOWN,
79 MWIFIEX_ERROR_INVALID_PARAMETER,
80};
81
82enum mwifiex_bss_type {
83 MWIFIEX_BSS_TYPE_STA = 0,
84 MWIFIEX_BSS_TYPE_UAP = 1,
85 MWIFIEX_BSS_TYPE_ANY = 0xff,
86};
87
88enum mwifiex_bss_role {
89 MWIFIEX_BSS_ROLE_STA = 0,
90 MWIFIEX_BSS_ROLE_UAP = 1,
91 MWIFIEX_BSS_ROLE_ANY = 0xff,
92};
93
94#define BSS_ROLE_BIT_MASK BIT(0)
95
96#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
97
98enum mwifiex_data_frame_type {
99 MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0,
100 MWIFIEX_DATA_FRAME_TYPE_802_11,
101};
102
103struct mwifiex_fw_image {
104 u8 *helper_buf;
105 u32 helper_len;
106 u8 *fw_buf;
107 u32 fw_len;
108};
109
110struct mwifiex_802_11_ssid {
111 u32 ssid_len;
112 u8 ssid[IEEE80211_MAX_SSID_LEN];
113};
114
115struct mwifiex_wait_queue {
116 u32 bss_index;
117 wait_queue_head_t *wait;
118 u16 *condition;
119 u32 start_time;
120 int status;
121 u32 enabled;
122};
123
124struct mwifiex_rxinfo {
125 u8 bss_index;
126 struct sk_buff *parent;
127 u8 use_count;
128};
129
130struct mwifiex_txinfo {
131 u32 status_code;
132 u8 flags;
133 u8 bss_index;
134};
135
136struct mwifiex_bss_attr {
137 u32 bss_type;
138 u32 frame_type;
139 u32 active;
140 u32 bss_priority;
141 u32 bss_num;
142};
143
144enum mwifiex_cmd_result_e {
145 MWIFIEX_CMD_RESULT_SUCCESS = 0,
146 MWIFIEX_CMD_RESULT_FAILURE = 1,
147 MWIFIEX_CMD_RESULT_TIMEOUT = 2,
148 MWIFIEX_CMD_RESULT_INVALID_DATA = 3
149} __packed;
150
151enum mwifiex_wmm_ac_e {
152 WMM_AC_BK,
153 WMM_AC_BE,
154 WMM_AC_VI,
155 WMM_AC_VO
156} __packed;
157
158enum mwifiex_wmm_queue_config_action_e {
159 MWIFIEX_WMM_QUEUE_CONFIG_ACTION_GET = 0,
160 MWIFIEX_WMM_QUEUE_CONFIG_ACTION_SET = 1,
161 MWIFIEX_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
162 MWIFIEX_WMM_QUEUE_CONFIG_ACTION_MAX
163} __packed;
164
165enum mwifiex_wmm_queue_stats_action_e {
166 MWIFIEX_WMM_STATS_ACTION_START = 0,
167 MWIFIEX_WMM_STATS_ACTION_STOP = 1,
168 MWIFIEX_WMM_STATS_ACTION_GET_CLR = 2,
169 MWIFIEX_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
170 MWIFIEX_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
171 MWIFIEX_WMM_STATS_ACTION_MAX
172} __packed;
173
174struct mwifiex_device {
175 struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM];
176};
177#endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
new file mode 100644
index 000000000000..e5dae45b11d2
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -0,0 +1,1376 @@
1/*
2 * Marvell Wireless LAN device driver: Firmware specific macros & structures
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_FW_H_
21#define _MWIFIEX_FW_H_
22
23#include <linux/if_ether.h>
24
25
26#define INTF_HEADER_LEN 4
27
28struct rfc_1042_hdr {
29 u8 llc_dsap;
30 u8 llc_ssap;
31 u8 llc_ctrl;
32 u8 snap_oui[3];
33 u16 snap_type;
34};
35
36struct rx_packet_hdr {
37 struct ethhdr eth803_hdr;
38 struct rfc_1042_hdr rfc1042_hdr;
39};
40
41struct tx_packet_hdr {
42 struct ethhdr eth803_hdr;
43 struct rfc_1042_hdr rfc1042_hdr;
44};
45
46#define B_SUPPORTED_RATES 5
47#define G_SUPPORTED_RATES 9
48#define BG_SUPPORTED_RATES 13
49#define A_SUPPORTED_RATES 9
50#define HOSTCMD_SUPPORTED_RATES 14
51#define N_SUPPORTED_RATES 3
52#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN)
53
54#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11))
55#define IS_SUPPORT_MULTI_BANDS(adapter) \
56 (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
57#define GET_FW_DEFAULT_BANDS(adapter) \
58 ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
59
60#define SHORT_SLOT_TIME_DISABLED(CapInfo) (CapInfo &= ~BIT(10))
61#define SHORT_SLOT_TIME_ENABLED(CapInfo) (CapInfo |= BIT(10))
62
63extern u8 supported_rates_b[B_SUPPORTED_RATES];
64extern u8 supported_rates_g[G_SUPPORTED_RATES];
65extern u8 supported_rates_bg[BG_SUPPORTED_RATES];
66extern u8 supported_rates_a[A_SUPPORTED_RATES];
67extern u8 supported_rates_n[N_SUPPORTED_RATES];
68
69#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
70
71#define KEY_INFO_ENABLED 0x01
72enum KEY_TYPE_ID {
73 KEY_TYPE_ID_WEP = 0,
74 KEY_TYPE_ID_TKIP,
75 KEY_TYPE_ID_AES,
76 KEY_TYPE_ID_WAPI,
77};
78
79enum KEY_INFO_WEP {
80 KEY_INFO_WEP_MCAST = 0x01,
81 KEY_INFO_WEP_UNICAST = 0x02,
82 KEY_INFO_WEP_ENABLED = 0x04
83};
84
85enum KEY_INFO_TKIP {
86 KEY_INFO_TKIP_MCAST = 0x01,
87 KEY_INFO_TKIP_UNICAST = 0x02,
88 KEY_INFO_TKIP_ENABLED = 0x04
89};
90
91enum KEY_INFO_AES {
92 KEY_INFO_AES_MCAST = 0x01,
93 KEY_INFO_AES_UNICAST = 0x02,
94 KEY_INFO_AES_ENABLED = 0x04
95};
96
97#define WAPI_KEY_LEN 50
98
99enum KEY_INFO_WAPI {
100 KEY_INFO_WAPI_MCAST = 0x01,
101 KEY_INFO_WAPI_UNICAST = 0x02,
102 KEY_INFO_WAPI_ENABLED = 0x04
103};
104
105#define MAX_POLL_TRIES 100
106
107#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
108
109#define MAX_FIRMWARE_POLL_TRIES 100
110
111#define FIRMWARE_READY 0xfedc
112
113#define FIRMWARE_TRANSFER_NBLOCK 2
114
115enum MWIFIEX_802_11_PRIVACY_FILTER {
116 MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
117 MWIFIEX_802_11_PRIV_FILTER_8021X_WEP
118};
119
120enum MWIFIEX_802_11_WEP_STATUS {
121 MWIFIEX_802_11_WEP_ENABLED,
122 MWIFIEX_802_11_WEP_DISABLED,
123};
124
125#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
126
127#define PROPRIETARY_TLV_BASE_ID 0x0100
128#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
129#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
130#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
131#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
132#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
133#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
134#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
135#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
136#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
137#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
138#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
139#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
140#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
141#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
142#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
143#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
144
145#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 30)
146#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
147#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 36)
148#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 38)
149#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 39)
150#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 40)
151#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 41)
152
153#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
154#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
155#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35)
156
157#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
158
159#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 74)
160#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 75)
161#define TLV_SECONDARY_CHANNEL_OFFSET (PROPRIETARY_TLV_BASE_ID + 76)
162#define TLV_TYPE_2040BSS_COEXISTENCE (PROPRIETARY_TLV_BASE_ID + 77)
163#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM (PROPRIETARY_TLV_BASE_ID + 78)
164#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 79)
165#define TLV_TYPE_HT_OPERATIONAL_MCS_SET (PROPRIETARY_TLV_BASE_ID + 80)
166
167#define ADDBA_TID_MASK (BIT(2) | BIT(3) | BIT(4) | BIT(5))
168#define DELBA_TID_MASK (BIT(12) | BIT(13) | BIT(14) | BIT(15))
169#define SSN_MASK 0xfff0
170
171#define BA_RESULT_SUCCESS 0x0
172#define BA_RESULT_FAILURE 0x1
173#define BA_RESULT_TIMEOUT 0x2
174#define BA_RESULT_DATA_INVALID 0x3
175
176#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
177
178#define BA_STREAM_NOT_ALLOWED 0xff
179
180#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \
181 priv->adapter->config_bands & BAND_AN) \
182 && priv->curr_bss_params.bss_descriptor.bcn_ht_cap)
183#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\
184 BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
185
186#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096
187#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192
188#define MAX_RX_AMPDU_SIZE_64K 0x03
189#define NON_GREENFIELD_STAS 0x04
190
191#define HWSPEC_GREENFIELD_SUPP BIT(29)
192#define HWSPEC_RXSTBC_SUPP BIT(26)
193#define HWSPEC_SHORTGI40_SUPP BIT(24)
194#define HWSPEC_SHORTGI20_SUPP BIT(23)
195#define HWSPEC_CHANBW40_SUPP BIT(17)
196
197#define DEFAULT_11N_CAP_MASK (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP)
198#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
199#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & BIT(31))
200#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30))
201#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29))
202#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & BIT(28))
203#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & BIT(27))
204#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26))
205#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25))
206#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24))
207#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23))
208#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22))
209#define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03))
210#define GET_IMMEDIATEBACK(Dot11nDevCap) (((Dot11nDevCap >> 18) & 0x03))
211#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17))
212#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & BIT(16))
213#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & BIT(15))
214#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & BIT(8))
215#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & BIT(7))
216#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & BIT(6))
217#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & BIT(5))
218#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & BIT(4))
219#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & BIT(3))
220#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & BIT(2))
221#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & BIT(1))
222#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & BIT(0))
223#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= BIT(17))
224#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~BIT(17))
225#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4)
226#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
227#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & BIT(1))
228#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & BIT(4))
229#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & BIT(5))
230#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & BIT(6))
231#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & BIT(7))
232#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03)
233#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & BIT(10))
234#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & BIT(11))
235#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= BIT(1))
236#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= BIT(4))
237#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= BIT(5))
238#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= BIT(6))
239#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= BIT(7))
240#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8))
241#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= BIT(10))
242#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= BIT(11))
243#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= BIT(12))
244#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= BIT(14))
245#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~BIT(1))
246#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~BIT(4))
247#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~BIT(5))
248#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~BIT(6))
249#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~BIT(7))
250#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8))
251#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~BIT(10))
252#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~BIT(11))
253#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~BIT(14))
254#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11))
255#define SETHT_MCS32(x) (x[4] |= 1)
256#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1)
257#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(u16 *) (x + 10)) = y)
258#define AMPDU_FACTOR_64K 0x03
259#define SETAMPDU_SIZE(x, y) do { \
260 x = x & ~0x03; \
261 x |= y & 0x03; \
262} while (0) \
263
264#define SETAMPDU_SPACING(x, y) do { \
265 x = x & ~0x1c; \
266 x |= (y & 0x07) << 2; \
267} while (0) \
268
269#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & BIT(10))
270#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & BIT(2))
271#define SET_CHANWIDTH40(Field2) (Field2 |= BIT(2))
272#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(BIT(0) | BIT(1) | BIT(2)))
273#define GET_SECONDARYCHAN(Field2) (Field2 & (BIT(0) | BIT(1)))
274#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
275
276#define LLC_SNAP_LEN 8
277
278#define TLV_TYPE_RATE_DROP_PATTERN (PROPRIETARY_TLV_BASE_ID + 81)
279#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
280#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
281
282#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
283
284#define MOD_CLASS_HR_DSSS 0x03
285#define MOD_CLASS_OFDM 0x07
286#define MOD_CLASS_HT 0x08
287#define HT_BW_20 0
288#define HT_BW_40 1
289
290#define HostCmd_CMD_GET_HW_SPEC 0x0003
291#define HostCmd_CMD_802_11_SCAN 0x0006
292#define HostCmd_CMD_802_11_GET_LOG 0x000b
293#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
294#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
295#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
296#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
297#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
298#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
299#define HostCmd_CMD_RF_REG_ACCESS 0x001b
300#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad
301#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
302#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
303#define HostCmd_CMD_MAC_CONTROL 0x0028
304#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
305#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
306#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
307#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
308#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
309#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
310#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
311#define HostCmd_CMD_WMM_GET_STATUS 0x0071
312#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
313#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
314#define HostCmd_CMD_VERSION_EXT 0x0097
315#define HostCmd_CMD_RSSI_INFO 0x00a4
316#define HostCmd_CMD_FUNC_INIT 0x00a9
317#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
318#define HostCmd_CMD_11N_CFG 0x00cd
319#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
320#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
321#define HostCmd_CMD_11N_DELBA 0x00d0
322#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
323#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
324#define HostCmd_CMD_TXPWR_CFG 0x00d1
325#define HostCmd_CMD_TX_RATE_CFG 0x00d6
326#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
327#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
328#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
329#define HostCmd_CMD_SET_BSS_MODE 0x00f7
330
331
332enum ENH_PS_MODES {
333 EN_PS = 1,
334 DIS_PS = 2,
335 EN_AUTO_DS = 3,
336 DIS_AUTO_DS = 4,
337 SLEEP_CONFIRM = 5,
338 GET_PS = 0,
339 EN_AUTO_PS = 0xff,
340 DIS_AUTO_PS = 0xfe,
341};
342
343#define HostCmd_RET_BIT 0x8000
344#define HostCmd_ACT_GEN_GET 0x0000
345#define HostCmd_ACT_GEN_SET 0x0001
346#define HostCmd_ACT_GEN_REMOVE 0x0004
347#define HostCmd_ACT_SET_BOTH 0x0003
348#define HostCmd_ACT_GET_BOTH 0x000c
349#define HostCmd_RESULT_OK 0x0000
350#define HostCmd_RESULT_ERROR 0x0001
351#define HostCmd_RESULT_NOT_SUPPORT 0x0002
352#define HostCmd_RESULT_PENDING 0x0003
353#define HostCmd_RESULT_BUSY 0x0004
354#define HostCmd_RESULT_PARTIAL_DATA 0x0005
355
356#define HostCmd_ACT_MAC_RX_ON 0x0001
357#define HostCmd_ACT_MAC_TX_ON 0x0002
358#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
359#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
360#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
361#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
362#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200
363#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
364#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
365
366#define HostCmd_BSS_MODE_BSS 0x0001
367#define HostCmd_BSS_MODE_IBSS 0x0002
368#define HostCmd_BSS_MODE_ANY 0x0003
369
370#define HostCmd_SCAN_RADIO_TYPE_BG 0
371#define HostCmd_SCAN_RADIO_TYPE_A 1
372
373#define HOST_SLEEP_CFG_CANCEL 0xffffffff
374#define HOST_SLEEP_CFG_COND_DEF 0x0000000f
375#define HOST_SLEEP_CFG_GPIO_DEF 0xff
376#define HOST_SLEEP_CFG_GAP_DEF 0
377
378#define CMD_F_HOSTCMD (1 << 0)
379#define CMD_F_CANCELED (1 << 1)
380
381#define HostCmd_CMD_ID_MASK 0x0fff
382
383#define HostCmd_SEQ_NUM_MASK 0x00ff
384
385#define HostCmd_BSS_NUM_MASK 0x0f00
386
387#define HostCmd_BSS_TYPE_MASK 0xf000
388
389#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \
390 (((seq) & 0x00ff) | \
391 (((num) & 0x000f) << 8)) | \
392 (((type) & 0x000f) << 12); }
393
394#define HostCmd_GET_SEQ_NO(seq) \
395 ((seq) & HostCmd_SEQ_NUM_MASK)
396
397#define HostCmd_GET_BSS_NO(seq) \
398 (((seq) & HostCmd_BSS_NUM_MASK) >> 8)
399
400#define HostCmd_GET_BSS_TYPE(seq) \
401 (((seq) & HostCmd_BSS_TYPE_MASK) >> 12)
402
403#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
404#define EVENT_LINK_LOST 0x00000003
405#define EVENT_LINK_SENSED 0x00000004
406#define EVENT_MIB_CHANGED 0x00000006
407#define EVENT_INIT_DONE 0x00000007
408#define EVENT_DEAUTHENTICATED 0x00000008
409#define EVENT_DISASSOCIATED 0x00000009
410#define EVENT_PS_AWAKE 0x0000000a
411#define EVENT_PS_SLEEP 0x0000000b
412#define EVENT_MIC_ERR_MULTICAST 0x0000000d
413#define EVENT_MIC_ERR_UNICAST 0x0000000e
414#define EVENT_DEEP_SLEEP_AWAKE 0x00000010
415#define EVENT_ADHOC_BCN_LOST 0x00000011
416
417#define EVENT_WMM_STATUS_CHANGE 0x00000017
418#define EVENT_BG_SCAN_REPORT 0x00000018
419#define EVENT_RSSI_LOW 0x00000019
420#define EVENT_SNR_LOW 0x0000001a
421#define EVENT_MAX_FAIL 0x0000001b
422#define EVENT_RSSI_HIGH 0x0000001c
423#define EVENT_SNR_HIGH 0x0000001d
424#define EVENT_IBSS_COALESCED 0x0000001e
425#define EVENT_DATA_RSSI_LOW 0x00000024
426#define EVENT_DATA_SNR_LOW 0x00000025
427#define EVENT_DATA_RSSI_HIGH 0x00000026
428#define EVENT_DATA_SNR_HIGH 0x00000027
429#define EVENT_LINK_QUALITY 0x00000028
430#define EVENT_PORT_RELEASE 0x0000002b
431#define EVENT_PRE_BEACON_LOST 0x00000031
432#define EVENT_ADDBA 0x00000033
433#define EVENT_DELBA 0x00000034
434#define EVENT_BA_STREAM_TIEMOUT 0x00000037
435#define EVENT_AMSDU_AGGR_CTRL 0x00000042
436#define EVENT_WEP_ICV_ERR 0x00000046
437#define EVENT_HS_ACT_REQ 0x00000047
438#define EVENT_BW_CHANGE 0x00000048
439
440#define EVENT_HOSTWAKE_STAIE 0x0000004d
441
442#define EVENT_ID_MASK 0xffff
443#define BSS_NUM_MASK 0xf
444
445#define EVENT_GET_BSS_NUM(event_cause) \
446 (((event_cause) >> 16) & BSS_NUM_MASK)
447
448#define EVENT_GET_BSS_TYPE(event_cause) \
449 (((event_cause) >> 24) & 0x00ff)
450
451struct mwifiex_event_wep_icv_err {
452 u16 reason_code;
453 u8 src_mac_addr[ETH_ALEN];
454 u8 wep_key_index;
455 u8 wep_key_length;
456 u8 key[WLAN_KEY_LEN_WEP104];
457};
458
459struct mwifiex_802_11_fixed_ies {
460 u8 time_stamp[8];
461 __le16 beacon_interval;
462 __le16 capabilities;
463};
464
465struct mwifiex_ie_types_header {
466 __le16 type;
467 __le16 len;
468} __packed;
469
470struct mwifiex_ie_types_data {
471 struct mwifiex_ie_types_header header;
472 u8 data[1];
473} __packed;
474
475#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01
476#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08
477
478struct txpd {
479 u8 bss_type;
480 u8 bss_num;
481 __le16 tx_pkt_length;
482 __le16 tx_pkt_offset;
483 __le16 tx_pkt_type;
484 __le32 tx_control;
485 u8 priority;
486 u8 flags;
487 u8 pkt_delay_2ms;
488 u8 reserved1;
489} __packed;
490
491struct rxpd {
492 u8 bss_type;
493 u8 bss_num;
494 u16 rx_pkt_length;
495 u16 rx_pkt_offset;
496 u16 rx_pkt_type;
497 u16 seq_num;
498 u8 priority;
499 u8 rx_rate;
500 s8 snr;
501 s8 nf;
502 /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
503 * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
504 * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
505 u8 ht_info;
506 u8 reserved;
507} __packed;
508
509enum mwifiex_chan_scan_mode_bitmasks {
510 MWIFIEX_PASSIVE_SCAN = BIT(0),
511 MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
512};
513
514#define SECOND_CHANNEL_BELOW 0x30
515#define SECOND_CHANNEL_ABOVE 0x10
516struct mwifiex_chan_scan_param_set {
517 u8 radio_type;
518 u8 chan_number;
519 u8 chan_scan_mode_bitmap;
520 __le16 min_scan_time;
521 __le16 max_scan_time;
522} __packed;
523
524struct mwifiex_ie_types_chan_list_param_set {
525 struct mwifiex_ie_types_header header;
526 struct mwifiex_chan_scan_param_set chan_scan_param[1];
527} __packed;
528
529struct chan_band_param_set {
530 u8 radio_type;
531 u8 chan_number;
532};
533
534struct mwifiex_ie_types_chan_band_list_param_set {
535 struct mwifiex_ie_types_header header;
536 struct chan_band_param_set chan_band_param[1];
537} __packed;
538
539struct mwifiex_ie_types_rates_param_set {
540 struct mwifiex_ie_types_header header;
541 u8 rates[1];
542} __packed;
543
544struct mwifiex_ie_types_ssid_param_set {
545 struct mwifiex_ie_types_header header;
546 u8 ssid[1];
547} __packed;
548
549struct mwifiex_ie_types_num_probes {
550 struct mwifiex_ie_types_header header;
551 __le16 num_probes;
552} __packed;
553
554struct mwifiex_ie_types_wildcard_ssid_params {
555 struct mwifiex_ie_types_header header;
556 u8 max_ssid_length;
557 u8 ssid[1];
558} __packed;
559
560#define TSF_DATA_SIZE 8
561struct mwifiex_ie_types_tsf_timestamp {
562 struct mwifiex_ie_types_header header;
563 u8 tsf_data[1];
564} __packed;
565
566struct mwifiex_cf_param_set {
567 u8 cfp_cnt;
568 u8 cfp_period;
569 u16 cfp_max_duration;
570 u16 cfp_duration_remaining;
571} __packed;
572
573struct mwifiex_ibss_param_set {
574 u16 atim_window;
575} __packed;
576
577struct mwifiex_ie_types_ss_param_set {
578 struct mwifiex_ie_types_header header;
579 union {
580 struct mwifiex_cf_param_set cf_param_set[1];
581 struct mwifiex_ibss_param_set ibss_param_set[1];
582 } cf_ibss;
583} __packed;
584
585struct mwifiex_fh_param_set {
586 u16 dwell_time;
587 u8 hop_set;
588 u8 hop_pattern;
589 u8 hop_index;
590} __packed;
591
592struct mwifiex_ds_param_set {
593 u8 current_chan;
594} __packed;
595
596struct mwifiex_ie_types_phy_param_set {
597 struct mwifiex_ie_types_header header;
598 union {
599 struct mwifiex_fh_param_set fh_param_set[1];
600 struct mwifiex_ds_param_set ds_param_set[1];
601 } fh_ds;
602} __packed;
603
604struct mwifiex_ie_types_auth_type {
605 struct mwifiex_ie_types_header header;
606 __le16 auth_type;
607} __packed;
608
609struct mwifiex_ie_types_vendor_param_set {
610 struct mwifiex_ie_types_header header;
611 u8 ie[MWIFIEX_MAX_VSIE_LEN];
612};
613
614struct mwifiex_ie_types_rsn_param_set {
615 struct mwifiex_ie_types_header header;
616 u8 rsn_ie[1];
617} __packed;
618
619#define KEYPARAMSET_FIXED_LEN 6
620
621struct mwifiex_ie_type_key_param_set {
622 __le16 type;
623 __le16 length;
624 __le16 key_type_id;
625 __le16 key_info;
626 __le16 key_len;
627 u8 key[50];
628} __packed;
629
630struct host_cmd_ds_802_11_key_material {
631 __le16 action;
632 struct mwifiex_ie_type_key_param_set key_param_set;
633} __packed;
634
635struct host_cmd_ds_gen {
636 u16 command;
637 u16 size;
638 u16 seq_num;
639 u16 result;
640};
641
642#define S_DS_GEN sizeof(struct host_cmd_ds_gen)
643
644enum sleep_resp_ctrl {
645 RESP_NOT_NEEDED = 0,
646 RESP_NEEDED,
647};
648
649struct mwifiex_ps_param {
650 __le16 null_pkt_interval;
651 __le16 multiple_dtims;
652 __le16 bcn_miss_timeout;
653 __le16 local_listen_interval;
654 __le16 adhoc_wake_period;
655 __le16 mode;
656 __le16 delay_to_ps;
657};
658
659struct mwifiex_auto_ds_param {
660 __le16 deep_sleep_timeout;
661};
662
663struct sleep_confirm_param {
664 __le16 resp_ctrl;
665};
666
667#define BITMAP_AUTO_DS 0x01
668#define BITMAP_STA_PS 0x10
669#define BITMAP_UAP_INACT_PS 0x100
670#define BITMAP_UAP_DTIM_PS 0x200
671struct auto_ps_param {
672 __le16 ps_bitmap;
673 /* auto deep sleep parameter,
674 * sta power save parameter
675 * uap inactivity parameter
676 * uap DTIM parameter */
677};
678
679#define AUTO_PS_FIX_SIZE 4
680
681#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
682#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
683
684struct mwifiex_ie_types_auto_ds_param {
685 struct mwifiex_ie_types_header header;
686 struct mwifiex_auto_ds_param param;
687} __packed;
688
689struct mwifiex_ie_types_ps_param {
690 struct mwifiex_ie_types_header header;
691 struct mwifiex_ps_param param;
692} __packed;
693
694struct host_cmd_ds_802_11_ps_mode_enh {
695 __le16 action;
696
697 union {
698 struct mwifiex_ps_param opt_ps;
699 struct mwifiex_auto_ds_param auto_ds;
700 struct sleep_confirm_param sleep_cfm;
701 __le16 ps_bitmap;
702 struct auto_ps_param auto_ps;
703 } params;
704} __packed;
705
706struct host_cmd_ds_get_hw_spec {
707 __le16 hw_if_version;
708 __le16 version;
709 __le16 reserved;
710 __le16 num_of_mcast_adr;
711 u8 permanent_addr[ETH_ALEN];
712 __le16 region_code;
713 __le16 number_of_antenna;
714 __le32 fw_release_number;
715 __le32 reserved_1;
716 __le32 reserved_2;
717 __le32 reserved_3;
718 __le32 fw_cap_info;
719 __le32 dot_11n_dev_cap;
720 u8 dev_mcs_support;
721 __le16 mp_end_port; /* SDIO only, reserved for other interfacces */
722 __le16 reserved_4;
723} __packed;
724
725struct host_cmd_ds_802_11_rssi_info {
726 __le16 action;
727 __le16 ndata;
728 __le16 nbcn;
729 __le16 reserved[9];
730 long long reserved_1;
731};
732
733struct host_cmd_ds_802_11_rssi_info_rsp {
734 __le16 action;
735 __le16 ndata;
736 __le16 nbcn;
737 __le16 data_rssi_last;
738 __le16 data_nf_last;
739 __le16 data_rssi_avg;
740 __le16 data_nf_avg;
741 __le16 bcn_rssi_last;
742 __le16 bcn_nf_last;
743 __le16 bcn_rssi_avg;
744 __le16 bcn_nf_avg;
745 long long tsf_bcn;
746};
747
748struct host_cmd_ds_802_11_mac_address {
749 __le16 action;
750 u8 mac_addr[ETH_ALEN];
751};
752
753struct host_cmd_ds_mac_control {
754 __le16 action;
755 __le16 reserved;
756};
757
758struct host_cmd_ds_mac_multicast_adr {
759 __le16 action;
760 __le16 num_of_adrs;
761 u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
762} __packed;
763
764struct host_cmd_ds_802_11_deauthenticate {
765 u8 mac_addr[ETH_ALEN];
766 __le16 reason_code;
767} __packed;
768
769struct host_cmd_ds_802_11_associate {
770 u8 peer_sta_addr[ETH_ALEN];
771 __le16 cap_info_bitmap;
772 __le16 listen_interval;
773 __le16 beacon_period;
774 u8 dtim_period;
775} __packed;
776
777struct ieee_types_assoc_rsp {
778 __le16 cap_info_bitmap;
779 __le16 status_code;
780 __le16 a_id;
781 u8 ie_buffer[1];
782} __packed;
783
784struct host_cmd_ds_802_11_associate_rsp {
785 struct ieee_types_assoc_rsp assoc_rsp;
786} __packed;
787
788struct ieee_types_cf_param_set {
789 u8 element_id;
790 u8 len;
791 u8 cfp_cnt;
792 u8 cfp_period;
793 u16 cfp_max_duration;
794 u16 cfp_duration_remaining;
795} __packed;
796
797struct ieee_types_ibss_param_set {
798 u8 element_id;
799 u8 len;
800 __le16 atim_window;
801} __packed;
802
803union ieee_types_ss_param_set {
804 struct ieee_types_cf_param_set cf_param_set;
805 struct ieee_types_ibss_param_set ibss_param_set;
806} __packed;
807
808struct ieee_types_fh_param_set {
809 u8 element_id;
810 u8 len;
811 __le16 dwell_time;
812 u8 hop_set;
813 u8 hop_pattern;
814 u8 hop_index;
815} __packed;
816
817struct ieee_types_ds_param_set {
818 u8 element_id;
819 u8 len;
820 u8 current_chan;
821} __packed;
822
823union ieee_types_phy_param_set {
824 struct ieee_types_fh_param_set fh_param_set;
825 struct ieee_types_ds_param_set ds_param_set;
826} __packed;
827
828struct host_cmd_ds_802_11_ad_hoc_start {
829 u8 ssid[IEEE80211_MAX_SSID_LEN];
830 u8 bss_mode;
831 __le16 beacon_period;
832 u8 dtim_period;
833 union ieee_types_ss_param_set ss_param_set;
834 union ieee_types_phy_param_set phy_param_set;
835 u16 reserved1;
836 __le16 cap_info_bitmap;
837 u8 DataRate[HOSTCMD_SUPPORTED_RATES];
838} __packed;
839
840struct host_cmd_ds_802_11_ad_hoc_result {
841 u8 pad[3];
842 u8 bssid[ETH_ALEN];
843} __packed;
844
845struct adhoc_bss_desc {
846 u8 bssid[ETH_ALEN];
847 u8 ssid[IEEE80211_MAX_SSID_LEN];
848 u8 bss_mode;
849 __le16 beacon_period;
850 u8 dtim_period;
851 u8 time_stamp[8];
852 u8 local_time[8];
853 union ieee_types_phy_param_set phy_param_set;
854 union ieee_types_ss_param_set ss_param_set;
855 __le16 cap_info_bitmap;
856 u8 data_rates[HOSTCMD_SUPPORTED_RATES];
857
858 /*
859 * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
860 * It is used in the Adhoc join command and will cause a
861 * binary layout mismatch with the firmware
862 */
863} __packed;
864
865struct host_cmd_ds_802_11_ad_hoc_join {
866 struct adhoc_bss_desc bss_descriptor;
867 u16 reserved1;
868 u16 reserved2;
869} __packed;
870
871struct host_cmd_ds_802_11_get_log {
872 __le32 mcast_tx_frame;
873 __le32 failed;
874 __le32 retry;
875 __le32 multi_retry;
876 __le32 frame_dup;
877 __le32 rts_success;
878 __le32 rts_failure;
879 __le32 ack_failure;
880 __le32 rx_frag;
881 __le32 mcast_rx_frame;
882 __le32 fcs_error;
883 __le32 tx_frame;
884 __le32 reserved;
885 __le32 wep_icv_err_cnt[4];
886};
887
888struct host_cmd_ds_tx_rate_query {
889 u8 tx_rate;
890 /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
891 * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
892 * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
893 u8 ht_info;
894} __packed;
895
896enum Host_Sleep_Action {
897 HS_CONFIGURE = 0x0001,
898 HS_ACTIVATE = 0x0002,
899};
900
901struct mwifiex_hs_config_param {
902 __le32 conditions;
903 u8 gpio;
904 u8 gap;
905} __packed;
906
907struct hs_activate_param {
908 u16 resp_ctrl;
909} __packed;
910
911struct host_cmd_ds_802_11_hs_cfg_enh {
912 __le16 action;
913
914 union {
915 struct mwifiex_hs_config_param hs_config;
916 struct hs_activate_param hs_activate;
917 } params;
918} __packed;
919
920enum SNMP_MIB_INDEX {
921 OP_RATE_SET_I = 1,
922 DTIM_PERIOD_I = 3,
923 RTS_THRESH_I = 5,
924 SHORT_RETRY_LIM_I = 6,
925 LONG_RETRY_LIM_I = 7,
926 FRAG_THRESH_I = 8,
927 DOT11D_I = 9,
928};
929
930#define MAX_SNMP_BUF_SIZE 128
931
932struct host_cmd_ds_802_11_snmp_mib {
933 __le16 query_type;
934 __le16 oid;
935 __le16 buf_size;
936 u8 value[1];
937} __packed;
938
939#define RADIO_ON 0x01
940#define RADIO_OFF 0x00
941
942struct mwifiex_rate_scope {
943 __le16 type;
944 __le16 length;
945 __le16 hr_dsss_rate_bitmap;
946 __le16 ofdm_rate_bitmap;
947 __le16 ht_mcs_rate_bitmap[8];
948} __packed;
949
950struct mwifiex_rate_drop_pattern {
951 __le16 type;
952 __le16 length;
953 __le32 rate_drop_mode;
954} __packed;
955
956struct host_cmd_ds_tx_rate_cfg {
957 __le16 action;
958 __le16 cfg_index;
959} __packed;
960
961struct mwifiex_power_group {
962 u8 modulation_class;
963 u8 first_rate_code;
964 u8 last_rate_code;
965 s8 power_step;
966 s8 power_min;
967 s8 power_max;
968 u8 ht_bandwidth;
969 u8 reserved;
970} __packed;
971
972struct mwifiex_types_power_group {
973 u16 type;
974 u16 length;
975} __packed;
976
977struct host_cmd_ds_txpwr_cfg {
978 __le16 action;
979 __le16 cfg_index;
980 __le32 mode;
981} __packed;
982
983#define MWIFIEX_USER_SCAN_CHAN_MAX 50
984
985#define MWIFIEX_MAX_SSID_LIST_LENGTH 10
986
987struct mwifiex_scan_cmd_config {
988 /*
989 * BSS Type to be sent in the firmware command
990 *
991 * Field can be used to restrict the types of networks returned in the
992 * scan. Valid settings are:
993 *
994 * - MWIFIEX_SCAN_MODE_BSS (infrastructure)
995 * - MWIFIEX_SCAN_MODE_IBSS (adhoc)
996 * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
997 */
998 u8 bss_mode;
999
1000 /* Specific BSSID used to filter scan results in the firmware */
1001 u8 specific_bssid[ETH_ALEN];
1002
1003 /* Length of TLVs sent in command starting at tlvBuffer */
1004 u32 tlv_buf_len;
1005
1006 /*
1007 * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
1008 *
1009 * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set
1010 * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set
1011 */
1012 u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
1013 here */
1014} __packed;
1015
1016struct mwifiex_user_scan_chan {
1017 u8 chan_number;
1018 u8 radio_type;
1019 u8 scan_type;
1020 u8 reserved;
1021 u32 scan_time;
1022} __packed;
1023
1024struct mwifiex_user_scan_ssid {
1025 u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
1026 u8 max_len;
1027} __packed;
1028
1029struct mwifiex_user_scan_cfg {
1030 /*
1031 * Flag set to keep the previous scan table intact
1032 *
1033 * If set, the scan results will accumulate, replacing any previous
1034 * matched entries for a BSS with the new scan data
1035 */
1036 u8 keep_previous_scan;
1037 /*
1038 * BSS mode to be sent in the firmware command
1039 *
1040 * Field can be used to restrict the types of networks returned in the
1041 * scan. Valid settings are:
1042 *
1043 * - MWIFIEX_SCAN_MODE_BSS (infrastructure)
1044 * - MWIFIEX_SCAN_MODE_IBSS (adhoc)
1045 * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
1046 */
1047 u8 bss_mode;
1048 /* Configure the number of probe requests for active chan scans */
1049 u8 num_probes;
1050 u8 reserved;
1051 /* BSSID filter sent in the firmware command to limit the results */
1052 u8 specific_bssid[ETH_ALEN];
1053 /* SSID filter list used in the to limit the scan results */
1054 struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH];
1055 /* Variable number (fixed maximum) of channels to scan up */
1056 struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
1057} __packed;
1058
1059struct ie_body {
1060 u8 grp_key_oui[4];
1061 u8 ptk_cnt[2];
1062 u8 ptk_body[4];
1063} __packed;
1064
1065struct host_cmd_ds_802_11_scan {
1066 u8 bss_mode;
1067 u8 bssid[ETH_ALEN];
1068 u8 tlv_buffer[1];
1069} __packed;
1070
1071struct host_cmd_ds_802_11_scan_rsp {
1072 __le16 bss_descript_size;
1073 u8 number_of_sets;
1074 u8 bss_desc_and_tlv_buffer[1];
1075} __packed;
1076
1077struct host_cmd_ds_802_11_bg_scan_query {
1078 u8 flush;
1079} __packed;
1080
1081struct host_cmd_ds_802_11_bg_scan_query_rsp {
1082 u32 report_condition;
1083 struct host_cmd_ds_802_11_scan_rsp scan_resp;
1084} __packed;
1085
1086struct mwifiex_ietypes_domain_param_set {
1087 struct mwifiex_ie_types_header header;
1088 u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
1089 struct ieee80211_country_ie_triplet triplet[1];
1090} __packed;
1091
1092struct host_cmd_ds_802_11d_domain_info {
1093 __le16 action;
1094 struct mwifiex_ietypes_domain_param_set domain;
1095} __packed;
1096
1097struct host_cmd_ds_802_11d_domain_info_rsp {
1098 __le16 action;
1099 struct mwifiex_ietypes_domain_param_set domain;
1100} __packed;
1101
1102struct host_cmd_ds_11n_addba_req {
1103 u8 add_req_result;
1104 u8 peer_mac_addr[ETH_ALEN];
1105 u8 dialog_token;
1106 __le16 block_ack_param_set;
1107 __le16 block_ack_tmo;
1108 __le16 ssn;
1109} __packed;
1110
1111struct host_cmd_ds_11n_addba_rsp {
1112 u8 add_rsp_result;
1113 u8 peer_mac_addr[ETH_ALEN];
1114 u8 dialog_token;
1115 __le16 status_code;
1116 __le16 block_ack_param_set;
1117 __le16 block_ack_tmo;
1118 __le16 ssn;
1119} __packed;
1120
1121struct host_cmd_ds_11n_delba {
1122 u8 del_result;
1123 u8 peer_mac_addr[ETH_ALEN];
1124 __le16 del_ba_param_set;
1125 __le16 reason_code;
1126 u8 reserved;
1127} __packed;
1128
1129struct host_cmd_ds_11n_batimeout {
1130 u8 tid;
1131 u8 peer_mac_addr[ETH_ALEN];
1132 u8 origninator;
1133} __packed;
1134
1135struct host_cmd_ds_11n_cfg {
1136 __le16 action;
1137 __le16 ht_tx_cap;
1138 __le16 ht_tx_info;
1139} __packed;
1140
1141struct host_cmd_ds_txbuf_cfg {
1142 __le16 action;
1143 __le16 buff_size;
1144 __le16 mp_end_port; /* SDIO only, reserved for other interfacces */
1145 __le16 reserved3;
1146} __packed;
1147
1148struct host_cmd_ds_amsdu_aggr_ctrl {
1149 __le16 action;
1150 __le16 enable;
1151 __le16 curr_buf_size;
1152} __packed;
1153
1154struct mwifiex_ie_types_wmm_param_set {
1155 struct mwifiex_ie_types_header header;
1156 u8 wmm_ie[1];
1157};
1158
1159struct mwifiex_ie_types_wmm_queue_status {
1160 struct mwifiex_ie_types_header header;
1161 u8 queue_index;
1162 u8 disabled;
1163 u16 medium_time;
1164 u8 flow_required;
1165 u8 flow_created;
1166 u32 reserved;
1167};
1168
1169struct ieee_types_vendor_header {
1170 u8 element_id;
1171 u8 len;
1172 u8 oui[3];
1173 u8 oui_type;
1174 u8 oui_subtype;
1175 u8 version;
1176} __packed;
1177
1178struct ieee_types_wmm_ac_parameters {
1179 u8 aci_aifsn_bitmap;
1180 u8 ecw_bitmap;
1181 __le16 tx_op_limit;
1182} __packed;
1183
1184struct ieee_types_wmm_parameter {
1185 /*
1186 * WMM Parameter IE - Vendor Specific Header:
1187 * element_id [221/0xdd]
1188 * Len [24]
1189 * Oui [00:50:f2]
1190 * OuiType [2]
1191 * OuiSubType [1]
1192 * Version [1]
1193 */
1194 struct ieee_types_vendor_header vend_hdr;
1195 u8 qos_info_bitmap;
1196 u8 reserved;
1197 struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES];
1198} __packed;
1199
1200struct ieee_types_wmm_info {
1201
1202 /*
1203 * WMM Info IE - Vendor Specific Header:
1204 * element_id [221/0xdd]
1205 * Len [7]
1206 * Oui [00:50:f2]
1207 * OuiType [2]
1208 * OuiSubType [0]
1209 * Version [1]
1210 */
1211 struct ieee_types_vendor_header vend_hdr;
1212
1213 u8 qos_info_bitmap;
1214} __packed;
1215
1216struct host_cmd_ds_wmm_get_status {
1217 u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) *
1218 IEEE80211_MAX_QUEUES];
1219 u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2];
1220} __packed;
1221
1222struct mwifiex_wmm_ac_status {
1223 u8 disabled;
1224 u8 flow_required;
1225 u8 flow_created;
1226};
1227
1228struct mwifiex_ie_types_htcap {
1229 struct mwifiex_ie_types_header header;
1230 struct ieee80211_ht_cap ht_cap;
1231} __packed;
1232
1233struct mwifiex_ie_types_htinfo {
1234 struct mwifiex_ie_types_header header;
1235 struct ieee80211_ht_info ht_info;
1236} __packed;
1237
1238struct mwifiex_ie_types_2040bssco {
1239 struct mwifiex_ie_types_header header;
1240 u8 bss_co_2040;
1241} __packed;
1242
1243struct mwifiex_ie_types_extcap {
1244 struct mwifiex_ie_types_header header;
1245 u8 ext_cap;
1246} __packed;
1247
1248struct host_cmd_ds_mac_reg_access {
1249 __le16 action;
1250 __le16 offset;
1251 __le32 value;
1252} __packed;
1253
1254struct host_cmd_ds_bbp_reg_access {
1255 __le16 action;
1256 __le16 offset;
1257 u8 value;
1258 u8 reserved[3];
1259} __packed;
1260
1261struct host_cmd_ds_rf_reg_access {
1262 __le16 action;
1263 __le16 offset;
1264 u8 value;
1265 u8 reserved[3];
1266} __packed;
1267
1268struct host_cmd_ds_pmic_reg_access {
1269 __le16 action;
1270 __le16 offset;
1271 u8 value;
1272 u8 reserved[3];
1273} __packed;
1274
1275struct host_cmd_ds_802_11_eeprom_access {
1276 __le16 action;
1277
1278 __le16 offset;
1279 __le16 byte_count;
1280 u8 value;
1281} __packed;
1282
1283struct host_cmd_ds_802_11_rf_channel {
1284 __le16 action;
1285 __le16 current_channel;
1286 __le16 rf_type;
1287 __le16 reserved;
1288 u8 reserved_1[32];
1289} __packed;
1290
1291struct host_cmd_ds_version_ext {
1292 u8 version_str_sel;
1293 char version_str[128];
1294} __packed;
1295
1296struct host_cmd_ds_802_11_ibss_status {
1297 __le16 action;
1298 __le16 enable;
1299 u8 bssid[ETH_ALEN];
1300 __le16 beacon_interval;
1301 __le16 atim_window;
1302 __le16 use_g_rate_protect;
1303} __packed;
1304
1305#define CONNECTION_TYPE_INFRA 0
1306#define CONNECTION_TYPE_ADHOC 1
1307
1308struct host_cmd_ds_set_bss_mode {
1309 u8 con_type;
1310} __packed;
1311
1312struct host_cmd_ds_command {
1313 __le16 command;
1314 __le16 size;
1315 __le16 seq_num;
1316 __le16 result;
1317 union {
1318 struct host_cmd_ds_get_hw_spec hw_spec;
1319 struct host_cmd_ds_mac_control mac_ctrl;
1320 struct host_cmd_ds_802_11_mac_address mac_addr;
1321 struct host_cmd_ds_mac_multicast_adr mc_addr;
1322 struct host_cmd_ds_802_11_get_log get_log;
1323 struct host_cmd_ds_802_11_rssi_info rssi_info;
1324 struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp;
1325 struct host_cmd_ds_802_11_snmp_mib smib;
1326 struct host_cmd_ds_802_11_rf_channel rf_channel;
1327 struct host_cmd_ds_tx_rate_query tx_rate;
1328 struct host_cmd_ds_tx_rate_cfg tx_rate_cfg;
1329 struct host_cmd_ds_txpwr_cfg txp_cfg;
1330 struct host_cmd_ds_802_11_ps_mode_enh psmode_enh;
1331 struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg;
1332 struct host_cmd_ds_802_11_scan scan;
1333 struct host_cmd_ds_802_11_scan_rsp scan_resp;
1334 struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
1335 struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
1336 struct host_cmd_ds_802_11_associate associate;
1337 struct host_cmd_ds_802_11_associate_rsp associate_rsp;
1338 struct host_cmd_ds_802_11_deauthenticate deauth;
1339 struct host_cmd_ds_802_11_ad_hoc_start adhoc_start;
1340 struct host_cmd_ds_802_11_ad_hoc_result adhoc_result;
1341 struct host_cmd_ds_802_11_ad_hoc_join adhoc_join;
1342 struct host_cmd_ds_802_11d_domain_info domain_info;
1343 struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp;
1344 struct host_cmd_ds_11n_addba_req add_ba_req;
1345 struct host_cmd_ds_11n_addba_rsp add_ba_rsp;
1346 struct host_cmd_ds_11n_delba del_ba;
1347 struct host_cmd_ds_txbuf_cfg tx_buf;
1348 struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl;
1349 struct host_cmd_ds_11n_cfg htcfg;
1350 struct host_cmd_ds_wmm_get_status get_wmm_status;
1351 struct host_cmd_ds_802_11_key_material key_material;
1352 struct host_cmd_ds_version_ext verext;
1353 struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
1354 struct host_cmd_ds_mac_reg_access mac_reg;
1355 struct host_cmd_ds_bbp_reg_access bbp_reg;
1356 struct host_cmd_ds_rf_reg_access rf_reg;
1357 struct host_cmd_ds_pmic_reg_access pmic_reg;
1358 struct host_cmd_ds_set_bss_mode bss_mode;
1359 struct host_cmd_ds_802_11_eeprom_access eeprom;
1360 } params;
1361} __packed;
1362
1363struct mwifiex_opt_sleep_confirm {
1364 __le16 command;
1365 __le16 size;
1366 __le16 seq_num;
1367 __le16 result;
1368 __le16 action;
1369 struct sleep_confirm_param sleep_cfm;
1370} __packed;
1371
1372struct mwifiex_opt_sleep_confirm_buffer {
1373 u8 hdr[4];
1374 struct mwifiex_opt_sleep_confirm ps_cfm_sleep;
1375} __packed;
1376#endif /* !_MWIFIEX_FW_H_ */
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
new file mode 100644
index 000000000000..07ebc97e19c0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -0,0 +1,665 @@
1/*
2 * Marvell Wireless LAN device driver: HW/FW Initialization
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * This function adds a BSS priority table to the table list.
30 *
31 * The function allocates a new BSS priority table node and adds it to
32 * the end of BSS priority table list, kept in driver memory.
33 */
34static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
35{
36 struct mwifiex_adapter *adapter = priv->adapter;
37 struct mwifiex_bss_prio_node *bss_prio;
38 int status = 0;
39 unsigned long flags;
40
41 bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
42 if (!bss_prio) {
43 dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
44 __func__);
45 return -1;
46 }
47
48 bss_prio->priv = priv;
49 INIT_LIST_HEAD(&bss_prio->list);
50 if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur)
51 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
52 bss_prio;
53
54 spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority]
55 .bss_prio_lock, flags);
56 list_add_tail(&bss_prio->list,
57 &adapter->bss_prio_tbl[priv->bss_priority]
58 .bss_prio_head);
59 spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority]
60 .bss_prio_lock, flags);
61
62 return status;
63}
64
65/*
66 * This function initializes the private structure and sets default
67 * values to the members.
68 *
69 * Additionally, it also initializes all the locks and sets up all the
70 * lists.
71 */
72static int mwifiex_init_priv(struct mwifiex_private *priv)
73{
74 u32 i;
75 int ret = 0;
76
77 priv->media_connected = false;
78 memset(priv->curr_addr, 0xff, ETH_ALEN);
79
80 priv->pkt_tx_ctrl = 0;
81 priv->bss_mode = MWIFIEX_BSS_MODE_INFRA;
82 priv->data_rate = 0; /* Initially indicate the rate as auto */
83 priv->is_data_rate_auto = true;
84 priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
85 priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
86
87 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
88 priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN;
89 priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE;
90 for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
91 memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key));
92 priv->wep_key_curr_index = 0;
93 priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
94 HostCmd_ACT_MAC_ETHERNETII_ENABLE;
95
96 priv->beacon_period = 100; /* beacon interval */ ;
97 priv->attempted_bss_desc = NULL;
98 memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
99 priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL;
100
101 memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid));
102 memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid));
103 memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
104 priv->assoc_rsp_size = 0;
105 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
106 priv->atim_window = 0;
107 priv->adhoc_state = ADHOC_IDLE;
108 priv->tx_power_level = 0;
109 priv->max_tx_power_level = 0;
110 priv->min_tx_power_level = 0;
111 priv->tx_rate = 0;
112 priv->rxpd_htinfo = 0;
113 priv->rxpd_rate = 0;
114 priv->rate_bitmap = 0;
115 priv->data_rssi_last = 0;
116 priv->data_rssi_avg = 0;
117 priv->data_nf_avg = 0;
118 priv->data_nf_last = 0;
119 priv->bcn_rssi_last = 0;
120 priv->bcn_rssi_avg = 0;
121 priv->bcn_nf_avg = 0;
122 priv->bcn_nf_last = 0;
123 memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie));
124 memset(&priv->aes_key, 0, sizeof(priv->aes_key));
125 priv->wpa_ie_len = 0;
126 priv->wpa_is_gtk_set = false;
127
128 memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf));
129 priv->assoc_tlv_buf_len = 0;
130 memset(&priv->wps, 0, sizeof(priv->wps));
131 memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
132 priv->gen_ie_buf_len = 0;
133 memset(priv->vs_ie, 0, sizeof(priv->vs_ie));
134
135 priv->wmm_required = true;
136 priv->wmm_enabled = false;
137 priv->wmm_qosinfo = 0;
138 priv->curr_bcn_buf = NULL;
139 priv->curr_bcn_size = 0;
140
141 priv->scan_block = false;
142
143 ret = mwifiex_add_bss_prio_tbl(priv);
144
145 return ret;
146}
147
148/*
149 * This function allocates buffers for members of the adapter
150 * structure.
151 *
152 * The memory allocated includes scan table, command buffers, and
153 * sleep confirm command buffer. In addition, the queues are
154 * also initialized.
155 */
156static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
157{
158 int ret = 0;
159 u32 buf_size;
160 struct mwifiex_bssdescriptor *temp_scan_table;
161
162 /* Allocate buffer to store the BSSID list */
163 buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP;
164 temp_scan_table = kzalloc(buf_size, GFP_KERNEL);
165 if (!temp_scan_table) {
166 dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
167 __func__);
168 return -1;
169 }
170
171 adapter->scan_table = temp_scan_table;
172
173 /* Allocate command buffer */
174 ret = mwifiex_alloc_cmd_buffer(adapter);
175 if (ret) {
176 dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
177 __func__);
178 return -1;
179 }
180
181 adapter->sleep_cfm =
182 dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer)
183 + INTF_HEADER_LEN);
184
185 if (!adapter->sleep_cfm) {
186 dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
187 " cmd buffer\n", __func__);
188 return -1;
189 }
190 skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
191
192 return 0;
193}
194
195/*
196 * This function initializes the adapter structure and sets default
197 * values to the members of adapter.
198 *
199 * This also initializes the WMM related parameters in the driver private
200 * structures.
201 */
202static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
203{
204 struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL;
205
206 skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep));
207 sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *)
208 (adapter->sleep_cfm->data);
209
210 adapter->cmd_sent = false;
211 adapter->data_sent = true;
212 adapter->cmd_resp_received = false;
213 adapter->event_received = false;
214 adapter->data_received = false;
215
216 adapter->surprise_removed = false;
217
218 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
219
220 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
221 adapter->ps_state = PS_STATE_AWAKE;
222 adapter->need_to_wakeup = false;
223
224 adapter->scan_mode = HostCmd_BSS_MODE_ANY;
225 adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
226 adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
227 adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
228
229 adapter->num_in_scan_table = 0;
230 memset(adapter->scan_table, 0,
231 (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP));
232 adapter->scan_probes = 1;
233
234 memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf));
235 adapter->bcn_buf_end = adapter->bcn_buf;
236
237 adapter->radio_on = RADIO_ON;
238 adapter->multiple_dtim = 1;
239
240 adapter->local_listen_interval = 0; /* default value in firmware
241 will be used */
242
243 adapter->is_deep_sleep = false;
244
245 adapter->delay_null_pkt = false;
246 adapter->delay_to_ps = 1000;
247 adapter->enhanced_ps_mode = PS_MODE_AUTO;
248
249 adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by
250 default */
251 adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by
252 default */
253 adapter->pm_wakeup_card_req = false;
254
255 adapter->pm_wakeup_fw_try = false;
256
257 adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
258 adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
259 adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
260
261 adapter->is_hs_configured = false;
262 adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
263 adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
264 adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
265 adapter->hs_activated = false;
266
267 memset(adapter->event_body, 0, sizeof(adapter->event_body));
268 adapter->hw_dot_11n_dev_cap = 0;
269 adapter->hw_dev_mcs_support = 0;
270 adapter->usr_dot_11n_dev_cap = 0;
271 adapter->usr_dev_mcs_support = 0;
272 adapter->chan_offset = 0;
273 adapter->adhoc_11n_enabled = false;
274
275 mwifiex_wmm_init(adapter);
276
277 if (adapter->sleep_cfm) {
278 memset(&sleep_cfm_buf->ps_cfm_sleep, 0,
279 adapter->sleep_cfm->len);
280 sleep_cfm_buf->ps_cfm_sleep.command =
281 cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
282 sleep_cfm_buf->ps_cfm_sleep.size =
283 cpu_to_le16(adapter->sleep_cfm->len);
284 sleep_cfm_buf->ps_cfm_sleep.result = 0;
285 sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM);
286 sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl =
287 cpu_to_le16(RESP_NEEDED);
288 }
289 memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
290 memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
291 adapter->tx_lock_flag = false;
292 adapter->null_pkt_interval = 0;
293 adapter->fw_bands = 0;
294 adapter->config_bands = 0;
295 adapter->adhoc_start_band = 0;
296 adapter->scan_channels = NULL;
297 adapter->fw_release_number = 0;
298 adapter->fw_cap_info = 0;
299 memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf));
300 adapter->event_cause = 0;
301 adapter->region_code = 0;
302 adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
303 adapter->adhoc_awake_period = 0;
304 memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
305 adapter->arp_filter_size = 0;
306
307 return;
308}
309
310/*
311 * This function frees the adapter structure.
312 *
313 * The freeing operation is done recursively, by canceling all
314 * pending commands, freeing the member buffers previously
315 * allocated (command buffers, scan table buffer, sleep confirm
316 * command buffer), stopping the timers and calling the cleanup
317 * routines for every interface, before the actual adapter
318 * structure is freed.
319 */
320static void
321mwifiex_free_adapter(struct mwifiex_adapter *adapter)
322{
323 if (!adapter) {
324 pr_err("%s: adapter is NULL\n", __func__);
325 return;
326 }
327
328 mwifiex_cancel_all_pending_cmd(adapter);
329
330 /* Free lock variables */
331 mwifiex_free_lock_list(adapter);
332
333 /* Free command buffer */
334 dev_dbg(adapter->dev, "info: free cmd buffer\n");
335 mwifiex_free_cmd_buffer(adapter);
336
337 del_timer(&adapter->cmd_timer);
338
339 dev_dbg(adapter->dev, "info: free scan table\n");
340 kfree(adapter->scan_table);
341 adapter->scan_table = NULL;
342
343 adapter->if_ops.cleanup_if(adapter);
344
345 dev_kfree_skb_any(adapter->sleep_cfm);
346
347 return;
348}
349
350/*
351 * This function intializes the lock variables and
352 * the list heads.
353 */
354int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
355{
356 struct mwifiex_private *priv = NULL;
357 s32 i = 0;
358 u32 j = 0;
359
360 spin_lock_init(&adapter->mwifiex_lock);
361 spin_lock_init(&adapter->int_lock);
362 spin_lock_init(&adapter->main_proc_lock);
363 spin_lock_init(&adapter->mwifiex_cmd_lock);
364 for (i = 0; i < adapter->priv_num; i++) {
365 if (adapter->priv[i]) {
366 priv = adapter->priv[i];
367 spin_lock_init(&priv->rx_pkt_lock);
368 spin_lock_init(&priv->wmm.ra_list_spinlock);
369 spin_lock_init(&priv->curr_bcn_buf_lock);
370 }
371 }
372
373 /* Initialize cmd_free_q */
374 INIT_LIST_HEAD(&adapter->cmd_free_q);
375 /* Initialize cmd_pending_q */
376 INIT_LIST_HEAD(&adapter->cmd_pending_q);
377 /* Initialize scan_pending_q */
378 INIT_LIST_HEAD(&adapter->scan_pending_q);
379
380 spin_lock_init(&adapter->cmd_free_q_lock);
381 spin_lock_init(&adapter->cmd_pending_q_lock);
382 spin_lock_init(&adapter->scan_pending_q_lock);
383
384 for (i = 0; i < adapter->priv_num; ++i) {
385 INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
386 adapter->bss_prio_tbl[i].bss_prio_cur = NULL;
387 spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock);
388 }
389
390 for (i = 0; i < adapter->priv_num; i++) {
391 if (!adapter->priv[i])
392 continue;
393 priv = adapter->priv[i];
394 for (j = 0; j < MAX_NUM_TID; ++j) {
395 INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
396 spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
397 }
398 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
399 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
400
401 spin_lock_init(&priv->tx_ba_stream_tbl_lock);
402 spin_lock_init(&priv->rx_reorder_tbl_lock);
403 }
404
405 return 0;
406}
407
408/*
409 * This function releases the lock variables and frees the locks and
410 * associated locks.
411 */
412void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
413{
414 struct mwifiex_private *priv = NULL;
415 s32 i = 0;
416 s32 j = 0;
417
418 /* Free lists */
419 list_del(&adapter->cmd_free_q);
420 list_del(&adapter->cmd_pending_q);
421 list_del(&adapter->scan_pending_q);
422
423 for (i = 0; i < adapter->priv_num; i++)
424 list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
425
426 for (i = 0; i < adapter->priv_num; i++) {
427 if (adapter->priv[i]) {
428 priv = adapter->priv[i];
429 for (j = 0; j < MAX_NUM_TID; ++j)
430 list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
431 list_del(&priv->tx_ba_stream_tbl_ptr);
432 list_del(&priv->rx_reorder_tbl_ptr);
433 }
434 }
435
436 return;
437}
438
439/*
440 * This function initializes the firmware.
441 *
442 * The following operations are performed sequentially -
443 * - Allocate adapter structure
444 * - Initialize the adapter structure
445 * - Initialize the private structure
446 * - Add BSS priority tables to the adapter structure
447 * - For each interface, send the init commands to firmware
448 * - Send the first command in command pending queue, if available
449 */
450int mwifiex_init_fw(struct mwifiex_adapter *adapter)
451{
452 int ret = 0;
453 struct mwifiex_private *priv = NULL;
454 u8 i = 0;
455 u8 first_sta = true;
456 int is_cmd_pend_q_empty;
457 unsigned long flags;
458
459 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
460
461 /* Allocate memory for member of adapter structure */
462 ret = mwifiex_allocate_adapter(adapter);
463 if (ret)
464 return -1;
465
466 /* Initialize adapter structure */
467 mwifiex_init_adapter(adapter);
468
469 for (i = 0; i < adapter->priv_num; i++) {
470 if (adapter->priv[i]) {
471 priv = adapter->priv[i];
472
473 /* Initialize private structure */
474 ret = mwifiex_init_priv(priv);
475 if (ret)
476 return -1;
477 }
478 }
479 for (i = 0; i < adapter->priv_num; i++) {
480 if (adapter->priv[i]) {
481 ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
482 if (ret == -1)
483 return -1;
484
485 first_sta = false;
486 }
487 }
488
489 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
490 is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
491 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
492 if (!is_cmd_pend_q_empty) {
493 /* Send the first command in queue and return */
494 if (mwifiex_main_process(adapter) != -1)
495 ret = -EINPROGRESS;
496 } else {
497 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
498 }
499
500 return ret;
501}
502
503/*
504 * This function deletes the BSS priority tables.
505 *
506 * The function traverses through all the allocated BSS priority nodes
507 * in every BSS priority table and frees them.
508 */
509static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
510{
511 int i;
512 struct mwifiex_adapter *adapter = priv->adapter;
513 struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL,
514 **cur = NULL;
515 struct list_head *head;
516 spinlock_t *lock;
517 unsigned long flags;
518
519 for (i = 0; i < adapter->priv_num; ++i) {
520 head = &adapter->bss_prio_tbl[i].bss_prio_head;
521 cur = &adapter->bss_prio_tbl[i].bss_prio_cur;
522 lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
523 dev_dbg(adapter->dev, "info: delete BSS priority table,"
524 " index = %d, i = %d, head = %p, cur = %p\n",
525 priv->bss_index, i, head, *cur);
526 if (*cur) {
527 spin_lock_irqsave(lock, flags);
528 if (list_empty(head)) {
529 spin_unlock_irqrestore(lock, flags);
530 continue;
531 }
532 bssprio_node = list_first_entry(head,
533 struct mwifiex_bss_prio_node, list);
534 spin_unlock_irqrestore(lock, flags);
535
536 list_for_each_entry_safe(bssprio_node, tmp_node, head,
537 list) {
538 if (bssprio_node->priv == priv) {
539 dev_dbg(adapter->dev, "info: Delete "
540 "node %p, next = %p\n",
541 bssprio_node, tmp_node);
542 spin_lock_irqsave(lock, flags);
543 list_del(&bssprio_node->list);
544 spin_unlock_irqrestore(lock, flags);
545 kfree(bssprio_node);
546 }
547 }
548 *cur = (struct mwifiex_bss_prio_node *)head;
549 }
550 }
551}
552
553/*
554 * This function is used to shutdown the driver.
555 *
556 * The following operations are performed sequentially -
557 * - Check if already shut down
558 * - Make sure the main process has stopped
559 * - Clean up the Tx and Rx queues
560 * - Delete BSS priority tables
561 * - Free the adapter
562 * - Notify completion
563 */
564int
565mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
566{
567 int ret = -EINPROGRESS;
568 struct mwifiex_private *priv = NULL;
569 s32 i = 0;
570 unsigned long flags;
571
572 /* mwifiex already shutdown */
573 if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)
574 return 0;
575
576 adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
577 /* wait for mwifiex_process to complete */
578 if (adapter->mwifiex_processing) {
579 dev_warn(adapter->dev, "main process is still running\n");
580 return ret;
581 }
582
583 /* shut down mwifiex */
584 dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
585
586 /* Clean up Tx/Rx queues and delete BSS priority table */
587 for (i = 0; i < adapter->priv_num; i++) {
588 if (adapter->priv[i]) {
589 priv = adapter->priv[i];
590
591 mwifiex_clean_txrx(priv);
592 mwifiex_delete_bss_prio_tbl(priv);
593 }
594 }
595
596 spin_lock_irqsave(&adapter->mwifiex_lock, flags);
597
598 /* Free adapter structure */
599 mwifiex_free_adapter(adapter);
600
601 spin_unlock_irqrestore(&adapter->mwifiex_lock, flags);
602
603 /* Notify completion */
604 ret = mwifiex_shutdown_fw_complete(adapter);
605
606 return ret;
607}
608
609/*
610 * This function downloads the firmware to the card.
611 *
612 * The actual download is preceded by two sanity checks -
613 * - Check if firmware is already running
614 * - Check if the interface is the winner to download the firmware
615 *
616 * ...and followed by another -
617 * - Check if the firmware is downloaded successfully
618 *
619 * After download is successfully completed, the host interrupts are enabled.
620 */
621int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
622 struct mwifiex_fw_image *pmfw)
623{
624 int ret = 0;
625 u32 poll_num = 1;
626 int winner;
627
628 /* Check if firmware is already running */
629 ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
630 if (!ret) {
631 dev_notice(adapter->dev,
632 "WLAN FW already running! Skip FW download\n");
633 goto done;
634 }
635 poll_num = MAX_FIRMWARE_POLL_TRIES;
636
637 /* Check if we are the winner for downloading FW */
638 if (!winner) {
639 dev_notice(adapter->dev,
640 "Other interface already running!"
641 " Skip FW download\n");
642 poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
643 goto poll_fw;
644 }
645 if (pmfw) {
646 /* Download firmware with helper */
647 ret = adapter->if_ops.prog_fw(adapter, pmfw);
648 if (ret) {
649 dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
650 return ret;
651 }
652 }
653
654poll_fw:
655 /* Check if the firmware is downloaded successfully or not */
656 ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
657 if (ret) {
658 dev_err(adapter->dev, "FW failed to be active in time\n");
659 return -1;
660 }
661done:
662 /* re-enable host interrupt for mwifiex after fw dnld is successful */
663 adapter->if_ops.enable_int(adapter);
664 return ret;
665}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
new file mode 100644
index 000000000000..d6babfb1495c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -0,0 +1,433 @@
1/*
2 * Marvell Wireless LAN device driver: ioctl data structures & APIs
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_IOCTL_H_
21#define _MWIFIEX_IOCTL_H_
22
23#include <net/mac80211.h>
24
25enum {
26 MWIFIEX_SCAN_MODE_UNCHANGED = 0,
27 MWIFIEX_SCAN_MODE_BSS,
28 MWIFIEX_SCAN_MODE_IBSS,
29 MWIFIEX_SCAN_MODE_ANY
30};
31
32enum {
33 MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
34 MWIFIEX_SCAN_TYPE_ACTIVE,
35 MWIFIEX_SCAN_TYPE_PASSIVE
36};
37
38struct mwifiex_get_scan_table_fixed {
39 u8 bssid[ETH_ALEN];
40 u8 channel;
41 u8 rssi;
42 long long network_tsf;
43};
44
45struct mwifiex_scan_time_params {
46 u32 specific_scan_time;
47 u32 active_scan_time;
48 u32 passive_scan_time;
49};
50
51struct mwifiex_user_scan {
52 u32 scan_cfg_len;
53 u8 scan_cfg_buf[1];
54};
55
56struct mwifiex_scan_req {
57 u32 scan_mode;
58 u32 scan_type;
59 struct mwifiex_802_11_ssid scan_ssid;
60 struct mwifiex_scan_time_params scan_time;
61 struct mwifiex_user_scan user_scan;
62};
63
64struct mwifiex_scan_resp {
65 u32 num_in_scan_table;
66 u8 *scan_table;
67};
68
69enum {
70 MWIFIEX_BSS_MODE_INFRA = 1,
71 MWIFIEX_BSS_MODE_IBSS,
72 MWIFIEX_BSS_MODE_AUTO
73};
74
75#define MWIFIEX_PROMISC_MODE 1
76#define MWIFIEX_MULTICAST_MODE 2
77#define MWIFIEX_ALL_MULTI_MODE 4
78#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32
79
80struct mwifiex_multicast_list {
81 u32 mode;
82 u32 num_multicast_addr;
83 u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
84};
85
86#define MWIFIEX_MAX_CHANNEL_NUM 128
87
88struct mwifiex_chan_freq {
89 u32 channel;
90 u32 freq;
91};
92
93struct mwifiex_chan_list {
94 u32 num_of_chan;
95 struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM];
96};
97
98struct mwifiex_ssid_bssid {
99 struct mwifiex_802_11_ssid ssid;
100 u8 bssid[ETH_ALEN];
101};
102
103enum {
104 BAND_B = 1,
105 BAND_G = 2,
106 BAND_A = 4,
107 BAND_GN = 8,
108 BAND_AN = 16,
109};
110
111#define NO_SEC_CHANNEL 0
112#define SEC_CHANNEL_ABOVE 1
113#define SEC_CHANNEL_BELOW 3
114
115struct mwifiex_ds_band_cfg {
116 u32 config_bands;
117 u32 adhoc_start_band;
118 u32 adhoc_channel;
119 u32 sec_chan_offset;
120};
121
122enum {
123 ADHOC_IDLE,
124 ADHOC_STARTED,
125 ADHOC_JOINED,
126 ADHOC_COALESCED
127};
128
129struct mwifiex_ds_get_stats {
130 u32 mcast_tx_frame;
131 u32 failed;
132 u32 retry;
133 u32 multi_retry;
134 u32 frame_dup;
135 u32 rts_success;
136 u32 rts_failure;
137 u32 ack_failure;
138 u32 rx_frag;
139 u32 mcast_rx_frame;
140 u32 fcs_error;
141 u32 tx_frame;
142 u32 wep_icv_error[4];
143};
144
145#define BCN_RSSI_LAST_MASK 0x00000001
146#define BCN_RSSI_AVG_MASK 0x00000002
147#define DATA_RSSI_LAST_MASK 0x00000004
148#define DATA_RSSI_AVG_MASK 0x00000008
149#define BCN_SNR_LAST_MASK 0x00000010
150#define BCN_SNR_AVG_MASK 0x00000020
151#define DATA_SNR_LAST_MASK 0x00000040
152#define DATA_SNR_AVG_MASK 0x00000080
153#define BCN_NF_LAST_MASK 0x00000100
154#define BCN_NF_AVG_MASK 0x00000200
155#define DATA_NF_LAST_MASK 0x00000400
156#define DATA_NF_AVG_MASK 0x00000800
157#define ALL_RSSI_INFO_MASK 0x00000fff
158
159struct mwifiex_ds_get_signal {
160 /*
161 * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
162 * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
163 * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
164 * Bit6: Last Data SNR, Bit7: Average Data SNR,
165 * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
166 * Bit10: Last Data NF, Bit11: Average Data NF
167 */
168 u16 selector;
169 s16 bcn_rssi_last;
170 s16 bcn_rssi_avg;
171 s16 data_rssi_last;
172 s16 data_rssi_avg;
173 s16 bcn_snr_last;
174 s16 bcn_snr_avg;
175 s16 data_snr_last;
176 s16 data_snr_avg;
177 s16 bcn_nf_last;
178 s16 bcn_nf_avg;
179 s16 data_nf_last;
180 s16 data_nf_avg;
181};
182
183struct mwifiex_fw_info {
184 u32 fw_ver;
185 u8 mac_addr[ETH_ALEN];
186};
187
188#define MWIFIEX_MAX_VER_STR_LEN 128
189
190struct mwifiex_ver_ext {
191 u32 version_str_sel;
192 char version_str[MWIFIEX_MAX_VER_STR_LEN];
193};
194
195struct mwifiex_bss_info {
196 u32 bss_mode;
197 struct mwifiex_802_11_ssid ssid;
198 u32 scan_table_idx;
199 u32 bss_chan;
200 u32 region_code;
201 u32 media_connected;
202 u32 radio_on;
203 u32 max_power_level;
204 u32 min_power_level;
205 u32 adhoc_state;
206 signed int bcn_nf_last;
207 u32 wep_status;
208 u32 is_hs_configured;
209 u32 is_deep_sleep;
210 u8 bssid[ETH_ALEN];
211};
212
213#define MAX_NUM_TID 8
214
215#define MAX_RX_WINSIZE 64
216
217struct mwifiex_ds_rx_reorder_tbl {
218 u16 tid;
219 u8 ta[ETH_ALEN];
220 u32 start_win;
221 u32 win_size;
222 u32 buffer[MAX_RX_WINSIZE];
223};
224
225struct mwifiex_ds_tx_ba_stream_tbl {
226 u16 tid;
227 u8 ra[ETH_ALEN];
228};
229
230#define DBG_CMD_NUM 5
231
232struct mwifiex_debug_info {
233 u32 int_counter;
234 u32 packets_out[MAX_NUM_TID];
235 u32 max_tx_buf_size;
236 u32 tx_buf_size;
237 u32 curr_tx_buf_size;
238 u32 tx_tbl_num;
239 struct mwifiex_ds_tx_ba_stream_tbl
240 tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED];
241 u32 rx_tbl_num;
242 struct mwifiex_ds_rx_reorder_tbl rx_tbl
243 [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED];
244 u16 ps_mode;
245 u32 ps_state;
246 u8 is_deep_sleep;
247 u8 pm_wakeup_card_req;
248 u32 pm_wakeup_fw_try;
249 u8 is_hs_configured;
250 u8 hs_activated;
251 u32 num_cmd_host_to_card_failure;
252 u32 num_cmd_sleep_cfm_host_to_card_failure;
253 u32 num_tx_host_to_card_failure;
254 u32 num_event_deauth;
255 u32 num_event_disassoc;
256 u32 num_event_link_lost;
257 u32 num_cmd_deauth;
258 u32 num_cmd_assoc_success;
259 u32 num_cmd_assoc_failure;
260 u32 num_tx_timeout;
261 u32 num_cmd_timeout;
262 u16 timeout_cmd_id;
263 u16 timeout_cmd_act;
264 u16 last_cmd_id[DBG_CMD_NUM];
265 u16 last_cmd_act[DBG_CMD_NUM];
266 u16 last_cmd_index;
267 u16 last_cmd_resp_id[DBG_CMD_NUM];
268 u16 last_cmd_resp_index;
269 u16 last_event[DBG_CMD_NUM];
270 u16 last_event_index;
271 u8 data_sent;
272 u8 cmd_sent;
273 u8 cmd_resp_received;
274 u8 event_received;
275};
276
277enum {
278 MWIFIEX_AUTH_MODE_OPEN = 0x00,
279 MWIFIEX_AUTH_MODE_SHARED = 0x01,
280 MWIFIEX_AUTH_MODE_NETWORKEAP = 0x80,
281 MWIFIEX_AUTH_MODE_AUTO = 0xFF,
282};
283
284enum {
285 MWIFIEX_ENCRYPTION_MODE_NONE = 0,
286 MWIFIEX_ENCRYPTION_MODE_WEP40 = 1,
287 MWIFIEX_ENCRYPTION_MODE_TKIP = 2,
288 MWIFIEX_ENCRYPTION_MODE_CCMP = 3,
289 MWIFIEX_ENCRYPTION_MODE_WEP104 = 4,
290};
291
292#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000
293#define MWIFIEX_MAX_KEY_LENGTH 32
294#define WAPI_RXPN_LEN 16
295
296struct mwifiex_ds_encrypt_key {
297 u32 key_disable;
298 u32 key_index;
299 u32 key_len;
300 u8 key_material[MWIFIEX_MAX_KEY_LENGTH];
301 u8 mac_addr[ETH_ALEN];
302 u32 is_wapi_key;
303 u8 wapi_rxpn[WAPI_RXPN_LEN];
304};
305
306struct mwifiex_rate_cfg {
307 u32 action;
308 u32 is_rate_auto;
309 u32 rate;
310};
311
312struct mwifiex_data_rate {
313 u32 tx_data_rate;
314 u32 rx_data_rate;
315};
316
317struct mwifiex_power_cfg {
318 u32 is_power_auto;
319 u32 power_level;
320};
321
322struct mwifiex_ds_hs_cfg {
323 u32 is_invoke_hostcmd;
324 /* Bit0: non-unicast data
325 * Bit1: unicast data
326 * Bit2: mac events
327 * Bit3: magic packet
328 */
329 u32 conditions;
330 u32 gpio;
331 u32 gap;
332};
333
334#define DEEP_SLEEP_ON 1
335#define DEEP_SLEEP_OFF 0
336
337#define DEEP_SLEEP_IDLE_TIME 100
338
339struct mwifiex_ds_auto_ds {
340 u16 auto_ds;
341 u16 idle_time;
342};
343
344#define PS_MODE_UNCHANGED 0
345#define PS_MODE_AUTO 1
346#define PS_MODE_POLL 2
347#define PS_MODE_NULL 3
348
349
350struct mwifiex_ds_pm_cfg {
351 union {
352 u32 ps_mode;
353 struct mwifiex_ds_hs_cfg hs_cfg;
354 struct mwifiex_ds_auto_ds auto_deep_sleep;
355 u32 sleep_period;
356 } param;
357};
358
359struct mwifiex_ioctl_wmm_queue_status_ac {
360 u8 wmm_acm;
361 u8 flow_required;
362 u8 flow_created;
363 u8 disabled;
364};
365
366struct mwifiex_ds_wmm_queue_status {
367 struct mwifiex_ioctl_wmm_queue_status_ac
368 ac_status[IEEE80211_MAX_QUEUES];
369};
370
371struct mwifiex_ds_11n_tx_cfg {
372 u16 tx_htcap;
373 u16 tx_htinfo;
374};
375
376struct mwifiex_ds_11n_amsdu_aggr_ctrl {
377 u16 enable;
378 u16 curr_buf_size;
379};
380
381#define MWIFIEX_NUM_OF_CMD_BUFFER 20
382#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048
383
384enum {
385 MWIFIEX_IE_TYPE_GEN_IE = 0,
386 MWIFIEX_IE_TYPE_ARP_FILTER,
387};
388
389enum {
390 MWIFIEX_REG_MAC = 1,
391 MWIFIEX_REG_BBP,
392 MWIFIEX_REG_RF,
393 MWIFIEX_REG_PMIC,
394 MWIFIEX_REG_CAU,
395};
396
397struct mwifiex_ds_reg_rw {
398 __le32 type;
399 __le32 offset;
400 __le32 value;
401};
402
403#define MAX_EEPROM_DATA 256
404
405struct mwifiex_ds_read_eeprom {
406 __le16 offset;
407 __le16 byte_count;
408 u8 value[MAX_EEPROM_DATA];
409};
410
411struct mwifiex_ds_misc_gen_ie {
412 u32 type;
413 u32 len;
414 u8 ie_data[IW_CUSTOM_MAX];
415};
416
417struct mwifiex_ds_misc_cmd {
418 u32 len;
419 u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER];
420};
421
422#define MWIFIEX_MAX_VSIE_LEN (256)
423#define MWIFIEX_MAX_VSIE_NUM (8)
424#define MWIFIEX_VSIE_MASK_SCAN 0x01
425#define MWIFIEX_VSIE_MASK_ASSOC 0x02
426#define MWIFIEX_VSIE_MASK_ADHOC 0x04
427
428enum {
429 MWIFIEX_FUNC_INIT = 1,
430 MWIFIEX_FUNC_SHUTDOWN,
431};
432
433#endif /* !_MWIFIEX_IOCTL_H_ */
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
new file mode 100644
index 000000000000..d06f4c2d1d30
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -0,0 +1,1464 @@
1/*
2 * Marvell Wireless LAN device driver: association and ad-hoc start/join
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
29
30/*
31 * Append a generic IE as a pass through TLV to a TLV buffer.
32 *
33 * This function is called from the network join command preparation routine.
34 *
35 * If the IE buffer has been setup by the application, this routine appends
36 * the buffer as a pass through TLV type to the request.
37 */
38static int
39mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
40{
41 int ret_len = 0;
42 struct mwifiex_ie_types_header ie_header;
43
44 /* Null Checks */
45 if (!buffer)
46 return 0;
47 if (!(*buffer))
48 return 0;
49
50 /*
51 * If there is a generic ie buffer setup, append it to the return
52 * parameter buffer pointer.
53 */
54 if (priv->gen_ie_buf_len) {
55 dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n",
56 __func__, priv->gen_ie_buf_len, *buffer);
57
58 /* Wrap the generic IE buffer with a pass through TLV type */
59 ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
60 ie_header.len = cpu_to_le16(priv->gen_ie_buf_len);
61 memcpy(*buffer, &ie_header, sizeof(ie_header));
62
63 /* Increment the return size and the return buffer pointer
64 param */
65 *buffer += sizeof(ie_header);
66 ret_len += sizeof(ie_header);
67
68 /* Copy the generic IE buffer to the output buffer, advance
69 pointer */
70 memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len);
71
72 /* Increment the return size and the return buffer pointer
73 param */
74 *buffer += priv->gen_ie_buf_len;
75 ret_len += priv->gen_ie_buf_len;
76
77 /* Reset the generic IE buffer */
78 priv->gen_ie_buf_len = 0;
79 }
80
81 /* return the length appended to the buffer */
82 return ret_len;
83}
84
85/*
86 * Append TSF tracking info from the scan table for the target AP.
87 *
88 * This function is called from the network join command preparation routine.
89 *
90 * The TSF table TSF sent to the firmware contains two TSF values:
91 * - The TSF of the target AP from its previous beacon/probe response
92 * - The TSF timestamp of our local MAC at the time we observed the
93 * beacon/probe response.
94 *
95 * The firmware uses the timestamp values to set an initial TSF value
96 * in the MAC for the new association after a reassociation attempt.
97 */
98static int
99mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
100 struct mwifiex_bssdescriptor *bss_desc)
101{
102 struct mwifiex_ie_types_tsf_timestamp tsf_tlv;
103 long long tsf_val;
104
105 /* Null Checks */
106 if (buffer == NULL)
107 return 0;
108 if (*buffer == NULL)
109 return 0;
110
111 memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp));
112
113 tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
114 tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val));
115
116 memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header));
117 *buffer += sizeof(tsf_tlv.header);
118
119 memcpy(*buffer, &tsf_val, sizeof(tsf_val));
120 *buffer += sizeof(tsf_val);
121
122 memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val));
123
124 dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - "
125 "%016llx\n", __func__, tsf_val, bss_desc->network_tsf);
126
127 memcpy(*buffer, &tsf_val, sizeof(tsf_val));
128 *buffer += sizeof(tsf_val);
129
130 return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
131}
132
133/*
134 * This function finds out the common rates between rate1 and rate2.
135 *
136 * It will fill common rates in rate1 as output if found.
137 *
138 * NOTE: Setting the MSB of the basic rates needs to be taken
139 * care of, either before or after calling this function.
140 */
141static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
142 u32 rate1_size, u8 *rate2, u32 rate2_size)
143{
144 int ret = 0;
145 u8 *ptr = rate1;
146 u8 *tmp = NULL;
147 u32 i, j;
148
149 tmp = kmalloc(rate1_size, GFP_KERNEL);
150 if (!tmp) {
151 dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
152 return -ENOMEM;
153 }
154
155 memcpy(tmp, rate1, rate1_size);
156 memset(rate1, 0, rate1_size);
157
158 for (i = 0; rate2[i] && i < rate2_size; i++) {
159 for (j = 0; tmp[j] && j < rate1_size; j++) {
160 /* Check common rate, excluding the bit for
161 basic rate */
162 if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
163 *rate1++ = tmp[j];
164 break;
165 }
166 }
167 }
168
169 dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n",
170 priv->data_rate);
171
172 if (!priv->is_data_rate_auto) {
173 while (*ptr) {
174 if ((*ptr & 0x7f) == priv->data_rate) {
175 ret = 0;
176 goto done;
177 }
178 ptr++;
179 }
180 dev_err(priv->adapter->dev, "previously set fixed data rate %#x"
181 " is not compatible with the network\n",
182 priv->data_rate);
183
184 ret = -1;
185 goto done;
186 }
187
188 ret = 0;
189done:
190 kfree(tmp);
191 return ret;
192}
193
194/*
195 * This function creates the intersection of the rates supported by a
196 * target BSS and our adapter settings for use in an assoc/join command.
197 */
198static int
199mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
200 struct mwifiex_bssdescriptor *bss_desc,
201 u8 *out_rates, u32 *out_rates_size)
202{
203 u8 card_rates[MWIFIEX_SUPPORTED_RATES];
204 u32 card_rates_size = 0;
205
206 /* Copy AP supported rates */
207 memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
208 /* Get the STA supported rates */
209 card_rates_size = mwifiex_get_active_data_rates(priv, card_rates);
210 /* Get the common rates between AP and STA supported rates */
211 if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
212 card_rates, card_rates_size)) {
213 *out_rates_size = 0;
214 dev_err(priv->adapter->dev, "%s: cannot get common rates\n",
215 __func__);
216 return -1;
217 }
218
219 *out_rates_size =
220 min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES);
221
222 return 0;
223}
224
225/*
226 * This function updates the scan entry TSF timestamps to reflect
227 * a new association.
228 */
229static void
230mwifiex_update_tsf_timestamps(struct mwifiex_private *priv,
231 struct mwifiex_bssdescriptor *new_bss_desc)
232{
233 struct mwifiex_adapter *adapter = priv->adapter;
234 u32 table_idx;
235 long long new_tsf_base;
236 signed long long tsf_delta;
237
238 memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base));
239
240 tsf_delta = new_tsf_base - new_bss_desc->network_tsf;
241
242 dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, "
243 "0x%016llx -> 0x%016llx\n",
244 new_bss_desc->network_tsf, new_tsf_base);
245
246 for (table_idx = 0; table_idx < adapter->num_in_scan_table;
247 table_idx++)
248 adapter->scan_table[table_idx].network_tsf += tsf_delta;
249}
250
251/*
252 * This function appends a WAPI IE.
253 *
254 * This function is called from the network join command preparation routine.
255 *
256 * If the IE buffer has been setup by the application, this routine appends
257 * the buffer as a WAPI TLV type to the request.
258 */
259static int
260mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
261{
262 int retLen = 0;
263 struct mwifiex_ie_types_header ie_header;
264
265 /* Null Checks */
266 if (buffer == NULL)
267 return 0;
268 if (*buffer == NULL)
269 return 0;
270
271 /*
272 * If there is a wapi ie buffer setup, append it to the return
273 * parameter buffer pointer.
274 */
275 if (priv->wapi_ie_len) {
276 dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n",
277 priv->wapi_ie_len, *buffer);
278
279 /* Wrap the generic IE buffer with a pass through TLV type */
280 ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
281 ie_header.len = cpu_to_le16(priv->wapi_ie_len);
282 memcpy(*buffer, &ie_header, sizeof(ie_header));
283
284 /* Increment the return size and the return buffer pointer
285 param */
286 *buffer += sizeof(ie_header);
287 retLen += sizeof(ie_header);
288
289 /* Copy the wapi IE buffer to the output buffer, advance
290 pointer */
291 memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len);
292
293 /* Increment the return size and the return buffer pointer
294 param */
295 *buffer += priv->wapi_ie_len;
296 retLen += priv->wapi_ie_len;
297
298 }
299 /* return the length appended to the buffer */
300 return retLen;
301}
302
303/*
304 * This function appends rsn ie tlv for wpa/wpa2 security modes.
305 * It is called from the network join command preparation routine.
306 */
307static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv,
308 u8 **buffer)
309{
310 struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv;
311 int rsn_ie_len;
312
313 if (!buffer || !(*buffer))
314 return 0;
315
316 rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer);
317 rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]);
318 rsn_ie_tlv->header.type = cpu_to_le16(
319 le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF);
320 rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]);
321 rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len)
322 & 0x00FF);
323 if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2))
324 memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2],
325 le16_to_cpu(rsn_ie_tlv->header.len));
326 else
327 return -1;
328
329 rsn_ie_len = sizeof(rsn_ie_tlv->header) +
330 le16_to_cpu(rsn_ie_tlv->header.len);
331 *buffer += rsn_ie_len;
332
333 return rsn_ie_len;
334}
335
336/*
337 * This function prepares command for association.
338 *
339 * This sets the following parameters -
340 * - Peer MAC address
341 * - Listen interval
342 * - Beacon interval
343 * - Capability information
344 *
345 * ...and the following TLVs, as required -
346 * - SSID TLV
347 * - PHY TLV
348 * - SS TLV
349 * - Rates TLV
350 * - Authentication TLV
351 * - Channel TLV
352 * - WPA/WPA2 IE
353 * - 11n TLV
354 * - Vendor specific TLV
355 * - WMM TLV
356 * - WAPI IE
357 * - Generic IE
358 * - TSF TLV
359 *
360 * Preparation also includes -
361 * - Setting command ID and proper size
362 * - Ensuring correct endian-ness
363 */
364int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
365 struct host_cmd_ds_command *cmd,
366 void *data_buf)
367{
368 struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate;
369 struct mwifiex_bssdescriptor *bss_desc;
370 struct mwifiex_ie_types_ssid_param_set *ssid_tlv;
371 struct mwifiex_ie_types_phy_param_set *phy_tlv;
372 struct mwifiex_ie_types_ss_param_set *ss_tlv;
373 struct mwifiex_ie_types_rates_param_set *rates_tlv;
374 struct mwifiex_ie_types_auth_type *auth_tlv;
375 struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
376 u8 rates[MWIFIEX_SUPPORTED_RATES];
377 u32 rates_size;
378 u16 tmp_cap;
379 u8 *pos;
380 int rsn_ie_len = 0;
381
382 bss_desc = (struct mwifiex_bssdescriptor *) data_buf;
383 pos = (u8 *) assoc;
384
385 mwifiex_cfg_tx_buf(priv, bss_desc);
386
387 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
388
389 /* Save so we know which BSS Desc to use in the response handler */
390 priv->attempted_bss_desc = bss_desc;
391
392 memcpy(assoc->peer_sta_addr,
393 bss_desc->mac_address, sizeof(assoc->peer_sta_addr));
394 pos += sizeof(assoc->peer_sta_addr);
395
396 /* Set the listen interval */
397 assoc->listen_interval = cpu_to_le16(priv->listen_interval);
398 /* Set the beacon period */
399 assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period);
400
401 pos += sizeof(assoc->cap_info_bitmap);
402 pos += sizeof(assoc->listen_interval);
403 pos += sizeof(assoc->beacon_period);
404 pos += sizeof(assoc->dtim_period);
405
406 ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos;
407 ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID);
408 ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len);
409 memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid,
410 le16_to_cpu(ssid_tlv->header.len));
411 pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len);
412
413 phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
414 phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
415 phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
416 memcpy(&phy_tlv->fh_ds.ds_param_set,
417 &bss_desc->phy_param_set.ds_param_set.current_chan,
418 sizeof(phy_tlv->fh_ds.ds_param_set));
419 pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
420
421 ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
422 ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
423 ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
424 pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
425
426 /* Get the common rates supported between the driver and the BSS Desc */
427 if (mwifiex_setup_rates_from_bssdesc
428 (priv, bss_desc, rates, &rates_size))
429 return -1;
430
431 /* Save the data rates into Current BSS state structure */
432 priv->curr_bss_params.num_of_rates = rates_size;
433 memcpy(&priv->curr_bss_params.data_rates, rates, rates_size);
434
435 /* Setup the Rates TLV in the association command */
436 rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos;
437 rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
438 rates_tlv->header.len = cpu_to_le16((u16) rates_size);
439 memcpy(rates_tlv->rates, rates, rates_size);
440 pos += sizeof(rates_tlv->header) + rates_size;
441 dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n",
442 rates_size);
443
444 /* Add the Authentication type to be used for Auth frames if needed */
445 if (priv->sec_info.authentication_mode != MWIFIEX_AUTH_MODE_AUTO) {
446 auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
447 auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
448 auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
449 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
450 auth_tlv->auth_type = cpu_to_le16((u16) priv->sec_info.
451 authentication_mode);
452 else
453 auth_tlv->auth_type =
454 cpu_to_le16(MWIFIEX_AUTH_MODE_OPEN);
455 pos += sizeof(auth_tlv->header) +
456 le16_to_cpu(auth_tlv->header.len);
457 }
458
459 if (IS_SUPPORT_MULTI_BANDS(priv->adapter)
460 && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
461 && (!bss_desc->disable_11n)
462 && (priv->adapter->config_bands & BAND_GN
463 || priv->adapter->config_bands & BAND_AN)
464 && (bss_desc->bcn_ht_cap)
465 )
466 ) {
467 /* Append a channel TLV for the channel the attempted AP was
468 found on */
469 chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
470 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
471 chan_tlv->header.len =
472 cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
473
474 memset(chan_tlv->chan_scan_param, 0x00,
475 sizeof(struct mwifiex_chan_scan_param_set));
476 chan_tlv->chan_scan_param[0].chan_number =
477 (bss_desc->phy_param_set.ds_param_set.current_chan);
478 dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n",
479 chan_tlv->chan_scan_param[0].chan_number);
480
481 chan_tlv->chan_scan_param[0].radio_type =
482 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
483
484 dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n",
485 chan_tlv->chan_scan_param[0].radio_type);
486 pos += sizeof(chan_tlv->header) +
487 sizeof(struct mwifiex_chan_scan_param_set);
488 }
489
490 if (!priv->wps.session_enable) {
491 if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
492 rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
493
494 if (rsn_ie_len == -1)
495 return -1;
496 }
497
498 if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
499 && (!bss_desc->disable_11n)
500 && (priv->adapter->config_bands & BAND_GN
501 || priv->adapter->config_bands & BAND_AN))
502 mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
503
504 /* Append vendor specific IE TLV */
505 mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
506
507 mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie,
508 bss_desc->bcn_ht_cap);
509 if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
510 mwifiex_cmd_append_wapi_ie(priv, &pos);
511
512
513 mwifiex_cmd_append_generic_ie(priv, &pos);
514
515 mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
516
517 cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
518
519 /* Set the Capability info at last */
520 tmp_cap = bss_desc->cap_info_bitmap;
521
522 if (priv->adapter->config_bands == BAND_B)
523 SHORT_SLOT_TIME_DISABLED(tmp_cap);
524
525 tmp_cap &= CAPINFO_MASK;
526 dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
527 tmp_cap, CAPINFO_MASK);
528 assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
529
530 return 0;
531}
532
533/*
534 * Association firmware command response handler
535 *
536 * The response buffer for the association command has the following
537 * memory layout.
538 *
539 * For cases where an association response was not received (indicated
540 * by the CapInfo and AId field):
541 *
542 * .------------------------------------------------------------.
543 * | Header(4 * sizeof(t_u16)): Standard command response hdr |
544 * .------------------------------------------------------------.
545 * | cap_info/Error Return(t_u16): |
546 * | 0xFFFF(-1): Internal error |
547 * | 0xFFFE(-2): Authentication unhandled message |
548 * | 0xFFFD(-3): Authentication refused |
549 * | 0xFFFC(-4): Timeout waiting for AP response |
550 * .------------------------------------------------------------.
551 * | status_code(t_u16): |
552 * | If cap_info is -1: |
553 * | An internal firmware failure prevented the |
554 * | command from being processed. The status_code |
555 * | will be set to 1. |
556 * | |
557 * | If cap_info is -2: |
558 * | An authentication frame was received but was |
559 * | not handled by the firmware. IEEE Status |
560 * | code for the failure is returned. |
561 * | |
562 * | If cap_info is -3: |
563 * | An authentication frame was received and the |
564 * | status_code is the IEEE Status reported in the |
565 * | response. |
566 * | |
567 * | If cap_info is -4: |
568 * | (1) Association response timeout |
569 * | (2) Authentication response timeout |
570 * .------------------------------------------------------------.
571 * | a_id(t_u16): 0xFFFF |
572 * .------------------------------------------------------------.
573 *
574 *
575 * For cases where an association response was received, the IEEE
576 * standard association response frame is returned:
577 *
578 * .------------------------------------------------------------.
579 * | Header(4 * sizeof(t_u16)): Standard command response hdr |
580 * .------------------------------------------------------------.
581 * | cap_info(t_u16): IEEE Capability |
582 * .------------------------------------------------------------.
583 * | status_code(t_u16): IEEE Status Code |
584 * .------------------------------------------------------------.
585 * | a_id(t_u16): IEEE Association ID |
586 * .------------------------------------------------------------.
587 * | IEEE IEs(variable): Any received IEs comprising the |
588 * | remaining portion of a received |
589 * | association response frame. |
590 * .------------------------------------------------------------.
591 *
592 * For simplistic handling, the status_code field can be used to determine
593 * an association success (0) or failure (non-zero).
594 */
595int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
596 struct host_cmd_ds_command *resp, void *wq_buf)
597{
598 int ret = 0;
599 struct mwifiex_wait_queue *wait_queue =
600 (struct mwifiex_wait_queue *) wq_buf;
601 struct ieee_types_assoc_rsp *assoc_rsp;
602 struct mwifiex_bssdescriptor *bss_desc;
603 u8 enable_data = true;
604
605 assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
606
607 priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
608 sizeof(priv->assoc_rsp_buf));
609
610 memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
611
612 if (le16_to_cpu(assoc_rsp->status_code)) {
613 priv->adapter->dbg.num_cmd_assoc_failure++;
614 dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, "
615 "status code = %d, error = 0x%x, a_id = 0x%x\n",
616 le16_to_cpu(assoc_rsp->status_code),
617 le16_to_cpu(assoc_rsp->cap_info_bitmap),
618 le16_to_cpu(assoc_rsp->a_id));
619
620 ret = -1;
621 goto done;
622 }
623
624 /* Send a Media Connected event, according to the Spec */
625 priv->media_connected = true;
626
627 priv->adapter->ps_state = PS_STATE_AWAKE;
628 priv->adapter->pps_uapsd_mode = false;
629 priv->adapter->tx_lock_flag = false;
630
631 /* Set the attempted BSSID Index to current */
632 bss_desc = priv->attempted_bss_desc;
633
634 dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n",
635 bss_desc->ssid.ssid);
636
637 /* Make a copy of current BSSID descriptor */
638 memcpy(&priv->curr_bss_params.bss_descriptor,
639 bss_desc, sizeof(struct mwifiex_bssdescriptor));
640
641 /* Update curr_bss_params */
642 priv->curr_bss_params.bss_descriptor.channel
643 = bss_desc->phy_param_set.ds_param_set.current_chan;
644
645 priv->curr_bss_params.band = (u8) bss_desc->bss_band;
646
647 /*
648 * Adjust the timestamps in the scan table to be relative to the newly
649 * associated AP's TSF
650 */
651 mwifiex_update_tsf_timestamps(priv, bss_desc);
652
653 if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
654 priv->curr_bss_params.wmm_enabled = true;
655 else
656 priv->curr_bss_params.wmm_enabled = false;
657
658 if ((priv->wmm_required || bss_desc->bcn_ht_cap)
659 && priv->curr_bss_params.wmm_enabled)
660 priv->wmm_enabled = true;
661 else
662 priv->wmm_enabled = false;
663
664 priv->curr_bss_params.wmm_uapsd_enabled = false;
665
666 if (priv->wmm_enabled)
667 priv->curr_bss_params.wmm_uapsd_enabled
668 = ((bss_desc->wmm_ie.qos_info_bitmap &
669 IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
670
671 dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
672 priv->curr_pkt_filter);
673 if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
674 priv->wpa_is_gtk_set = false;
675
676 if (priv->wmm_enabled) {
677 /* Don't re-enable carrier until we get the WMM_GET_STATUS
678 event */
679 enable_data = false;
680 } else {
681 /* Since WMM is not enabled, setup the queues with the
682 defaults */
683 mwifiex_wmm_setup_queue_priorities(priv, NULL);
684 mwifiex_wmm_setup_ac_downgrade(priv);
685 }
686
687 if (enable_data)
688 dev_dbg(priv->adapter->dev,
689 "info: post association, re-enabling data flow\n");
690
691 /* Reset SNR/NF/RSSI values */
692 priv->data_rssi_last = 0;
693 priv->data_nf_last = 0;
694 priv->data_rssi_avg = 0;
695 priv->data_nf_avg = 0;
696 priv->bcn_rssi_last = 0;
697 priv->bcn_nf_last = 0;
698 priv->bcn_rssi_avg = 0;
699 priv->bcn_nf_avg = 0;
700 priv->rxpd_rate = 0;
701 priv->rxpd_htinfo = 0;
702
703 mwifiex_save_curr_bcn(priv);
704
705 priv->adapter->dbg.num_cmd_assoc_success++;
706
707 dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n");
708
709 /* Add the ra_list here for infra mode as there will be only 1 ra
710 always */
711 mwifiex_ralist_add(priv,
712 priv->curr_bss_params.bss_descriptor.mac_address);
713
714 if (!netif_carrier_ok(priv->netdev))
715 netif_carrier_on(priv->netdev);
716 if (netif_queue_stopped(priv->netdev))
717 netif_wake_queue(priv->netdev);
718
719 if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
720 priv->scan_block = true;
721
722done:
723 /* Need to indicate IOCTL complete */
724 if (wait_queue) {
725 if (ret) {
726 if (assoc_rsp->status_code)
727 wait_queue->status =
728 le16_to_cpu(assoc_rsp->status_code);
729 else
730 wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL;
731 } else {
732 wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
733 }
734 }
735
736 return ret;
737}
738
739/*
740 * This function prepares command for ad-hoc start.
741 *
742 * Driver will fill up SSID, BSS mode, IBSS parameters, physical
743 * parameters, probe delay, and capability information. Firmware
744 * will fill up beacon period, basic rates and operational rates.
745 *
746 * In addition, the following TLVs are added -
747 * - Channel TLV
748 * - Vendor specific IE
749 * - WPA/WPA2 IE
750 * - HT Capabilities IE
751 * - HT Information IE
752 *
753 * Preparation also includes -
754 * - Setting command ID and proper size
755 * - Ensuring correct endian-ness
756 */
757int
758mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
759 struct host_cmd_ds_command *cmd, void *data_buf)
760{
761 int ret = 0, rsn_ie_len = 0;
762 struct mwifiex_adapter *adapter = priv->adapter;
763 struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start =
764 &cmd->params.adhoc_start;
765 struct mwifiex_bssdescriptor *bss_desc;
766 u32 cmd_append_size = 0;
767 u32 i;
768 u16 tmp_cap;
769 uint16_t ht_cap_info;
770 struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
771
772 struct mwifiex_ie_types_htcap *ht_cap;
773 struct mwifiex_ie_types_htinfo *ht_info;
774 u8 *pos = (u8 *) adhoc_start +
775 sizeof(struct host_cmd_ds_802_11_ad_hoc_start);
776
777 if (!adapter)
778 return -1;
779
780 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
781
782 bss_desc = &priv->curr_bss_params.bss_descriptor;
783 priv->attempted_bss_desc = bss_desc;
784
785 /*
786 * Fill in the parameters for 2 data structures:
787 * 1. struct host_cmd_ds_802_11_ad_hoc_start command
788 * 2. bss_desc
789 * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
790 * probe delay, and Cap info.
791 * Firmware will fill up beacon period, Basic rates
792 * and operational rates.
793 */
794
795 memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
796
797 memcpy(adhoc_start->ssid,
798 ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
799 ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
800
801 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n",
802 adhoc_start->ssid);
803
804 memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
805 memcpy(bss_desc->ssid.ssid,
806 ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
807 ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
808
809 bss_desc->ssid.ssid_len =
810 ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len;
811
812 /* Set the BSS mode */
813 adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
814 bss_desc->bss_mode = MWIFIEX_BSS_MODE_IBSS;
815 adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period);
816 bss_desc->beacon_period = priv->beacon_period;
817
818 /* Set Physical param set */
819/* Parameter IE Id */
820#define DS_PARA_IE_ID 3
821/* Parameter IE length */
822#define DS_PARA_IE_LEN 1
823
824 adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
825 adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
826
827 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
828 (priv, adapter->adhoc_start_band, (u16)
829 priv->adhoc_channel)) {
830 struct mwifiex_chan_freq_power *cfp;
831 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
832 adapter->adhoc_start_band, FIRST_VALID_CHANNEL);
833 if (cfp)
834 priv->adhoc_channel = (u8) cfp->channel;
835 }
836
837 if (!priv->adhoc_channel) {
838 dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
839 return -1;
840 }
841
842 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
843 priv->adhoc_channel);
844
845 priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
846 priv->curr_bss_params.band = adapter->adhoc_start_band;
847
848 bss_desc->channel = priv->adhoc_channel;
849 adhoc_start->phy_param_set.ds_param_set.current_chan =
850 priv->adhoc_channel;
851
852 memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set,
853 sizeof(union ieee_types_phy_param_set));
854
855 /* Set IBSS param set */
856/* IBSS parameter IE Id */
857#define IBSS_PARA_IE_ID 6
858/* IBSS parameter IE length */
859#define IBSS_PARA_IE_LEN 2
860
861 adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
862 adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
863 adhoc_start->ss_param_set.ibss_param_set.atim_window
864 = cpu_to_le16(priv->atim_window);
865 memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set,
866 sizeof(union ieee_types_ss_param_set));
867
868 /* Set Capability info */
869 bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS;
870 tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap);
871 tmp_cap &= ~WLAN_CAPABILITY_ESS;
872 tmp_cap |= WLAN_CAPABILITY_IBSS;
873
874 /* Set up privacy in bss_desc */
875 if (priv->sec_info.encryption_mode != MWIFIEX_ENCRYPTION_MODE_NONE) {
876 /* Ad-Hoc capability privacy on */
877 dev_dbg(adapter->dev,
878 "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
879 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
880 tmp_cap |= WLAN_CAPABILITY_PRIVACY;
881 } else {
882 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set,"
883 " setting privacy to ACCEPT ALL\n");
884 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
885 }
886
887 memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
888 mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
889 if ((adapter->adhoc_start_band & BAND_G) &&
890 (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
891 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
892 HostCmd_ACT_GEN_SET,
893 0, NULL, &priv->curr_pkt_filter);
894
895 if (ret) {
896 dev_err(adapter->dev,
897 "ADHOC_S_CMD: G Protection config failed\n");
898 return -1;
899 }
900 }
901 /* Find the last non zero */
902 for (i = 0; i < sizeof(adhoc_start->DataRate) &&
903 adhoc_start->DataRate[i];
904 i++)
905 ;
906
907 priv->curr_bss_params.num_of_rates = i;
908
909 /* Copy the ad-hoc creating rates into Current BSS rate structure */
910 memcpy(&priv->curr_bss_params.data_rates,
911 &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
912
913 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
914 adhoc_start->DataRate[0], adhoc_start->DataRate[1],
915 adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
916
917 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
918
919 if (IS_SUPPORT_MULTI_BANDS(adapter)) {
920 /* Append a channel TLV */
921 chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
922 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
923 chan_tlv->header.len =
924 cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
925
926 memset(chan_tlv->chan_scan_param, 0x00,
927 sizeof(struct mwifiex_chan_scan_param_set));
928 chan_tlv->chan_scan_param[0].chan_number =
929 (u8) priv->curr_bss_params.bss_descriptor.channel;
930
931 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n",
932 chan_tlv->chan_scan_param[0].chan_number);
933
934 chan_tlv->chan_scan_param[0].radio_type
935 = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
936 if (adapter->adhoc_start_band & BAND_GN
937 || adapter->adhoc_start_band & BAND_AN) {
938 if (adapter->chan_offset == SEC_CHANNEL_ABOVE)
939 chan_tlv->chan_scan_param[0].radio_type |=
940 SECOND_CHANNEL_ABOVE;
941 else if (adapter->chan_offset == SEC_CHANNEL_BELOW)
942 chan_tlv->chan_scan_param[0].radio_type |=
943 SECOND_CHANNEL_BELOW;
944 }
945 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n",
946 chan_tlv->chan_scan_param[0].radio_type);
947 pos += sizeof(chan_tlv->header) +
948 sizeof(struct mwifiex_chan_scan_param_set);
949 cmd_append_size +=
950 sizeof(chan_tlv->header) +
951 sizeof(struct mwifiex_chan_scan_param_set);
952 }
953
954 /* Append vendor specific IE TLV */
955 cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
956 MWIFIEX_VSIE_MASK_ADHOC, &pos);
957
958 if (priv->sec_info.wpa_enabled) {
959 rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
960 if (rsn_ie_len == -1)
961 return -1;
962 cmd_append_size += rsn_ie_len;
963 }
964
965 if (adapter->adhoc_11n_enabled) {
966 {
967 ht_cap = (struct mwifiex_ie_types_htcap *) pos;
968 memset(ht_cap, 0,
969 sizeof(struct mwifiex_ie_types_htcap));
970 ht_cap->header.type =
971 cpu_to_le16(WLAN_EID_HT_CAPABILITY);
972 ht_cap->header.len =
973 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
974 ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
975
976 SETHT_SHORTGI20(ht_cap_info);
977 if (adapter->chan_offset) {
978 SETHT_SHORTGI40(ht_cap_info);
979 SETHT_DSSSCCK40(ht_cap_info);
980 SETHT_SUPPCHANWIDTH(ht_cap_info);
981 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
982 }
983
984 ht_cap->ht_cap.ampdu_params_info
985 = MAX_RX_AMPDU_SIZE_64K;
986 ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
987 pos += sizeof(struct mwifiex_ie_types_htcap);
988 cmd_append_size +=
989 sizeof(struct mwifiex_ie_types_htcap);
990 }
991 {
992 ht_info = (struct mwifiex_ie_types_htinfo *) pos;
993 memset(ht_info, 0,
994 sizeof(struct mwifiex_ie_types_htinfo));
995 ht_info->header.type =
996 cpu_to_le16(WLAN_EID_HT_INFORMATION);
997 ht_info->header.len =
998 cpu_to_le16(sizeof(struct ieee80211_ht_info));
999 ht_info->ht_info.control_chan =
1000 (u8) priv->curr_bss_params.bss_descriptor.
1001 channel;
1002 if (adapter->chan_offset) {
1003 ht_info->ht_info.ht_param =
1004 adapter->chan_offset;
1005 SET_CHANWIDTH40(ht_info->ht_info.ht_param);
1006 }
1007 ht_info->ht_info.operation_mode =
1008 cpu_to_le16(NON_GREENFIELD_STAS);
1009 ht_info->ht_info.basic_set[0] = 0xff;
1010 pos += sizeof(struct mwifiex_ie_types_htinfo);
1011 cmd_append_size +=
1012 sizeof(struct mwifiex_ie_types_htinfo);
1013 }
1014 }
1015
1016 cmd->size = cpu_to_le16((u16)
1017 (sizeof(struct host_cmd_ds_802_11_ad_hoc_start)
1018 + S_DS_GEN + cmd_append_size));
1019
1020 if (adapter->adhoc_start_band == BAND_B)
1021 SHORT_SLOT_TIME_DISABLED(tmp_cap);
1022 else
1023 SHORT_SLOT_TIME_ENABLED(tmp_cap);
1024
1025 adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap);
1026
1027 return 0;
1028}
1029
1030/*
1031 * This function prepares command for ad-hoc join.
1032 *
1033 * Most of the parameters are set up by copying from the target BSS descriptor
1034 * from the scan response.
1035 *
1036 * In addition, the following TLVs are added -
1037 * - Channel TLV
1038 * - Vendor specific IE
1039 * - WPA/WPA2 IE
1040 * - 11n IE
1041 *
1042 * Preparation also includes -
1043 * - Setting command ID and proper size
1044 * - Ensuring correct endian-ness
1045 */
1046int
1047mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
1048 struct host_cmd_ds_command *cmd, void *data_buf)
1049{
1050 int ret = 0, rsn_ie_len = 0;
1051 struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
1052 &cmd->params.adhoc_join;
1053 struct mwifiex_bssdescriptor *bss_desc =
1054 (struct mwifiex_bssdescriptor *) data_buf;
1055 struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
1056 u32 cmd_append_size = 0;
1057 u16 tmp_cap;
1058 u32 i, rates_size = 0;
1059 u16 curr_pkt_filter;
1060 u8 *pos =
1061 (u8 *) adhoc_join +
1062 sizeof(struct host_cmd_ds_802_11_ad_hoc_join);
1063
1064/* Use G protection */
1065#define USE_G_PROTECTION 0x02
1066 if (bss_desc->erp_flags & USE_G_PROTECTION) {
1067 curr_pkt_filter =
1068 priv->
1069 curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
1070
1071 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1072 HostCmd_ACT_GEN_SET, 0, NULL,
1073 &curr_pkt_filter);
1074 if (ret) {
1075 dev_err(priv->adapter->dev,
1076 "ADHOC_J_CMD: G Protection config failed\n");
1077 return -1;
1078 }
1079 }
1080
1081 priv->attempted_bss_desc = bss_desc;
1082
1083 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
1084
1085 adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
1086
1087 adhoc_join->bss_descriptor.beacon_period
1088 = cpu_to_le16(bss_desc->beacon_period);
1089
1090 memcpy(&adhoc_join->bss_descriptor.bssid,
1091 &bss_desc->mac_address, ETH_ALEN);
1092
1093 memcpy(&adhoc_join->bss_descriptor.ssid,
1094 &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len);
1095
1096 memcpy(&adhoc_join->bss_descriptor.phy_param_set,
1097 &bss_desc->phy_param_set,
1098 sizeof(union ieee_types_phy_param_set));
1099
1100 memcpy(&adhoc_join->bss_descriptor.ss_param_set,
1101 &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set));
1102
1103 tmp_cap = bss_desc->cap_info_bitmap;
1104
1105 tmp_cap &= CAPINFO_MASK;
1106
1107 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X"
1108 " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK);
1109
1110 /* Information on BSSID descriptor passed to FW */
1111 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n",
1112 adhoc_join->bss_descriptor.bssid,
1113 adhoc_join->bss_descriptor.ssid);
1114
1115 for (i = 0; bss_desc->supported_rates[i] &&
1116 i < MWIFIEX_SUPPORTED_RATES;
1117 i++)
1118 ;
1119 rates_size = i;
1120
1121 /* Copy Data Rates from the Rates recorded in scan response */
1122 memset(adhoc_join->bss_descriptor.data_rates, 0,
1123 sizeof(adhoc_join->bss_descriptor.data_rates));
1124 memcpy(adhoc_join->bss_descriptor.data_rates,
1125 bss_desc->supported_rates, rates_size);
1126
1127 /* Copy the adhoc join rates into Current BSS state structure */
1128 priv->curr_bss_params.num_of_rates = rates_size;
1129 memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates,
1130 rates_size);
1131
1132 /* Copy the channel information */
1133 priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
1134 priv->curr_bss_params.band = (u8) bss_desc->bss_band;
1135
1136 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
1137 || priv->sec_info.wpa_enabled)
1138 tmp_cap |= WLAN_CAPABILITY_PRIVACY;
1139
1140 if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
1141 /* Append a channel TLV */
1142 chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
1143 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
1144 chan_tlv->header.len =
1145 cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
1146
1147 memset(chan_tlv->chan_scan_param, 0x00,
1148 sizeof(struct mwifiex_chan_scan_param_set));
1149 chan_tlv->chan_scan_param[0].chan_number =
1150 (bss_desc->phy_param_set.ds_param_set.current_chan);
1151 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n",
1152 chan_tlv->chan_scan_param[0].chan_number);
1153
1154 chan_tlv->chan_scan_param[0].radio_type =
1155 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
1156
1157 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n",
1158 chan_tlv->chan_scan_param[0].radio_type);
1159 pos += sizeof(chan_tlv->header) +
1160 sizeof(struct mwifiex_chan_scan_param_set);
1161 cmd_append_size += sizeof(chan_tlv->header) +
1162 sizeof(struct mwifiex_chan_scan_param_set);
1163 }
1164
1165 if (priv->sec_info.wpa_enabled)
1166 rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
1167 if (rsn_ie_len == -1)
1168 return -1;
1169 cmd_append_size += rsn_ie_len;
1170
1171 if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
1172 cmd_append_size += mwifiex_cmd_append_11n_tlv(priv,
1173 bss_desc, &pos);
1174
1175 /* Append vendor specific IE TLV */
1176 cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
1177 MWIFIEX_VSIE_MASK_ADHOC, &pos);
1178
1179 cmd->size = cpu_to_le16((u16)
1180 (sizeof(struct host_cmd_ds_802_11_ad_hoc_join)
1181 + S_DS_GEN + cmd_append_size));
1182
1183 adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
1184
1185 return ret;
1186}
1187
1188/*
1189 * This function handles the command response of ad-hoc start and
1190 * ad-hoc join.
1191 *
1192 * The function generates a device-connected event to notify
1193 * the applications, in case of successful ad-hoc start/join, and
1194 * saves the beacon buffer.
1195 */
1196int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
1197 struct host_cmd_ds_command *resp, void *wq_buf)
1198{
1199 int ret = 0;
1200 struct mwifiex_wait_queue *wait_queue =
1201 (struct mwifiex_wait_queue *) wq_buf;
1202 struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result;
1203 struct mwifiex_bssdescriptor *bss_desc;
1204 u16 command = le16_to_cpu(resp->command);
1205 u16 result = le16_to_cpu(resp->result);
1206
1207 adhoc_result = &resp->params.adhoc_result;
1208
1209 bss_desc = priv->attempted_bss_desc;
1210
1211 /* Join result code 0 --> SUCCESS */
1212 if (result) {
1213 dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
1214 if (priv->media_connected)
1215 mwifiex_reset_connect_state(priv);
1216
1217 memset(&priv->curr_bss_params.bss_descriptor,
1218 0x00, sizeof(struct mwifiex_bssdescriptor));
1219
1220 ret = -1;
1221 goto done;
1222 }
1223
1224 /* Send a Media Connected event, according to the Spec */
1225 priv->media_connected = true;
1226
1227 if (command == HostCmd_CMD_802_11_AD_HOC_START) {
1228 dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
1229 bss_desc->ssid.ssid);
1230
1231 /* Update the created network descriptor with the new BSSID */
1232 memcpy(bss_desc->mac_address,
1233 adhoc_result->bssid, ETH_ALEN);
1234
1235 priv->adhoc_state = ADHOC_STARTED;
1236 } else {
1237 /*
1238 * Now the join cmd should be successful.
1239 * If BSSID has changed use SSID to compare instead of BSSID
1240 */
1241 dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n",
1242 bss_desc->ssid.ssid);
1243
1244 /*
1245 * Make a copy of current BSSID descriptor, only needed for
1246 * join since the current descriptor is already being used
1247 * for adhoc start
1248 */
1249 memcpy(&priv->curr_bss_params.bss_descriptor,
1250 bss_desc, sizeof(struct mwifiex_bssdescriptor));
1251
1252 priv->adhoc_state = ADHOC_JOINED;
1253 }
1254
1255 dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n",
1256 priv->adhoc_channel);
1257 dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n",
1258 priv->curr_bss_params.bss_descriptor.mac_address);
1259
1260 if (!netif_carrier_ok(priv->netdev))
1261 netif_carrier_on(priv->netdev);
1262 if (netif_queue_stopped(priv->netdev))
1263 netif_wake_queue(priv->netdev);
1264
1265 mwifiex_save_curr_bcn(priv);
1266
1267done:
1268 /* Need to indicate IOCTL complete */
1269 if (wait_queue) {
1270 if (ret)
1271 wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL;
1272 else
1273 wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
1274
1275 }
1276
1277 return ret;
1278}
1279
1280/*
1281 * This function associates to a specific BSS discovered in a scan.
1282 *
1283 * It clears any past association response stored for application
1284 * retrieval and calls the command preparation routine to send the
1285 * command to firmware.
1286 */
1287int mwifiex_associate(struct mwifiex_private *priv,
1288 void *wait_queue, struct mwifiex_bssdescriptor *bss_desc)
1289{
1290 int ret = 0;
1291 u8 current_bssid[ETH_ALEN];
1292
1293 /* Return error if the adapter or table entry is not marked as infra */
1294 if ((priv->bss_mode != MWIFIEX_BSS_MODE_INFRA) ||
1295 (bss_desc->bss_mode != MWIFIEX_BSS_MODE_INFRA))
1296 return -1;
1297
1298 memcpy(&current_bssid,
1299 &priv->curr_bss_params.bss_descriptor.mac_address,
1300 sizeof(current_bssid));
1301
1302 /* Clear any past association response stored for application
1303 retrieval */
1304 priv->assoc_rsp_size = 0;
1305
1306 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
1307 HostCmd_ACT_GEN_SET, 0, wait_queue,
1308 bss_desc);
1309
1310 return ret;
1311}
1312
1313/*
1314 * This function starts an ad-hoc network.
1315 *
1316 * It calls the command preparation routine to send the command to firmware.
1317 */
1318int
1319mwifiex_adhoc_start(struct mwifiex_private *priv,
1320 void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid)
1321{
1322 int ret = 0;
1323
1324 dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
1325 priv->adhoc_channel);
1326 dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
1327 priv->curr_bss_params.bss_descriptor.channel);
1328 dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
1329 priv->curr_bss_params.band);
1330
1331 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
1332 HostCmd_ACT_GEN_SET, 0, wait_queue,
1333 adhoc_ssid);
1334
1335 return ret;
1336}
1337
1338/*
1339 * This function joins an ad-hoc network found in a previous scan.
1340 *
1341 * It calls the command preparation routine to send the command to firmware,
1342 * if already not connected to the requested SSID.
1343 */
1344int mwifiex_adhoc_join(struct mwifiex_private *priv,
1345 void *wait_queue, struct mwifiex_bssdescriptor *bss_desc)
1346{
1347 int ret = 0;
1348
1349 dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n",
1350 priv->curr_bss_params.bss_descriptor.ssid.ssid);
1351 dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n",
1352 priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
1353 dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n",
1354 bss_desc->ssid.ssid);
1355 dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n",
1356 bss_desc->ssid.ssid_len);
1357
1358 /* Check if the requested SSID is already joined */
1359 if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
1360 !mwifiex_ssid_cmp(&bss_desc->ssid,
1361 &priv->curr_bss_params.bss_descriptor.ssid) &&
1362 (priv->curr_bss_params.bss_descriptor.bss_mode ==
1363 MWIFIEX_BSS_MODE_IBSS)) {
1364 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID"
1365 " is the same as current; not attempting to re-join\n");
1366 return -1;
1367 }
1368
1369 dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
1370 priv->curr_bss_params.bss_descriptor.channel);
1371 dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
1372 priv->curr_bss_params.band);
1373
1374 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
1375 HostCmd_ACT_GEN_SET, 0, wait_queue,
1376 bss_desc);
1377
1378 return ret;
1379}
1380
1381/*
1382 * This function deauthenticates/disconnects from infra network by sending
1383 * deauthentication request.
1384 */
1385static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv,
1386 struct mwifiex_wait_queue *wait,
1387 u8 *mac)
1388{
1389 u8 mac_address[ETH_ALEN];
1390 int ret = 0;
1391 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
1392
1393 if (mac) {
1394 if (!memcmp(mac, zero_mac, sizeof(zero_mac)))
1395 memcpy((u8 *) &mac_address,
1396 (u8 *) &priv->curr_bss_params.bss_descriptor.
1397 mac_address, ETH_ALEN);
1398 else
1399 memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN);
1400 } else {
1401 memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params.
1402 bss_descriptor.mac_address, ETH_ALEN);
1403 }
1404
1405 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
1406 HostCmd_ACT_GEN_SET, 0, wait, &mac_address);
1407
1408 if (!ret && wait)
1409 ret = -EINPROGRESS;
1410
1411 return ret;
1412}
1413
1414/*
1415 * This function deauthenticates/disconnects from a BSS.
1416 *
1417 * In case of infra made, it sends deauthentication request, and
1418 * in case of ad-hoc mode, a stop network request is sent to the firmware.
1419 */
1420int mwifiex_deauthenticate(struct mwifiex_private *priv,
1421 struct mwifiex_wait_queue *wait, u8 *mac)
1422{
1423 int ret = 0;
1424
1425 if (priv->media_connected) {
1426 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) {
1427 ret = mwifiex_deauthenticate_infra(priv, wait, mac);
1428 } else if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
1429 ret = mwifiex_prepare_cmd(priv,
1430 HostCmd_CMD_802_11_AD_HOC_STOP,
1431 HostCmd_ACT_GEN_SET, 0, wait, NULL);
1432
1433 if (!ret && wait)
1434 ret = -EINPROGRESS;
1435 }
1436 }
1437
1438 return ret;
1439}
1440
1441/*
1442 * This function converts band to radio type used in channel TLV.
1443 */
1444u8
1445mwifiex_band_to_radio_type(u8 band)
1446{
1447 u8 ret_radio_type;
1448
1449 switch (band) {
1450 case BAND_A:
1451 case BAND_AN:
1452 case BAND_A | BAND_AN:
1453 ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A;
1454 break;
1455 case BAND_B:
1456 case BAND_G:
1457 case BAND_B | BAND_G:
1458 default:
1459 ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG;
1460 break;
1461 }
1462
1463 return ret_radio_type;
1464}
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
new file mode 100644
index 000000000000..ed89ca41a902
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -0,0 +1,1102 @@
1/*
2 * Marvell Wireless LAN device driver: major functions
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "main.h"
21#include "wmm.h"
22#include "cfg80211.h"
23#include "11n.h"
24
25#define VERSION "1.0"
26
27const char driver_version[] = "mwifiex " VERSION " (%s) ";
28
29struct mwifiex_adapter *g_adapter;
30EXPORT_SYMBOL_GPL(g_adapter);
31
32static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
33 {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0},
34};
35
36static int drv_mode = DRV_MODE_STA;
37
38static char fw_name[32] = DEFAULT_FW_NAME;
39
40/* Supported drv_mode table */
41static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
42 {
43 /* drv_mode */
44 .drv_mode = DRV_MODE_STA,
45 /* intf number */
46 .intf_num = ARRAY_SIZE(mwifiex_bss_sta),
47 /* bss_attr */
48 .bss_attr = mwifiex_bss_sta,
49 }
50 ,
51};
52
53/*
54 * This function registers the device and performs all the necessary
55 * initializations.
56 *
57 * The following initialization operations are performed -
58 * - Allocate adapter structure
59 * - Save interface specific operations table in adapter
60 * - Call interface specific initialization routine
61 * - Allocate private structures
62 * - Set default adapter structure parameters
63 * - Initialize locks
64 *
65 * In case of any errors during inittialization, this function also ensures
66 * proper cleanup before exiting.
67 */
68static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
69 struct mwifiex_device *mdevice, void **padapter)
70{
71 int ret = 0;
72 struct mwifiex_adapter *adapter = NULL;
73 u8 i = 0;
74
75 adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
76 /* Allocate memory for adapter structure */
77 if (!adapter)
78 return -1;
79
80 g_adapter = adapter;
81 adapter->card = card;
82
83 /* Save interface specific operations in adapter */
84 memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
85
86 /* card specific initialization has been deferred until now .. */
87 ret = adapter->if_ops.init_if(adapter);
88 if (ret)
89 goto error;
90
91 adapter->priv_num = 0;
92 for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
93 adapter->priv[i] = NULL;
94
95 if (!mdevice->bss_attr[i].active)
96 continue;
97
98 /* For valid bss_attr,
99 allocate memory for private structure */
100 adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
101 GFP_KERNEL);
102 if (!adapter->priv[i]) {
103 dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
104 __func__, i);
105 goto error;
106 }
107
108 adapter->priv_num++;
109 memset(adapter->priv[i], 0,
110 sizeof(struct mwifiex_private));
111 adapter->priv[i]->adapter = adapter;
112 /* Save bss_type, frame_type & bss_priority */
113 adapter->priv[i]->bss_type = (u8) mdevice->bss_attr[i].bss_type;
114 adapter->priv[i]->frame_type =
115 (u8) mdevice->bss_attr[i].frame_type;
116 adapter->priv[i]->bss_priority =
117 (u8) mdevice->bss_attr[i].bss_priority;
118 if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
119 adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
120 else if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_UAP)
121 adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
122
123 /* Save bss_index & bss_num */
124 adapter->priv[i]->bss_index = i;
125 adapter->priv[i]->bss_num = mdevice->bss_attr[i].bss_num;
126 }
127
128 /* Initialize lock variables */
129 if (mwifiex_init_lock_list(adapter))
130 goto error;
131
132 init_timer(&adapter->cmd_timer);
133 adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
134 adapter->cmd_timer.data = (unsigned long) adapter;
135
136 /* Return pointer of struct mwifiex_adapter */
137 *padapter = adapter;
138 return 0;
139
140error:
141 dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
142
143 /* Free lock variables */
144 mwifiex_free_lock_list(adapter);
145 for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++)
146 kfree(adapter->priv[i]);
147 kfree(adapter);
148
149 return -1;
150}
151
152/*
153 * This function unregisters the device and performs all the necessary
154 * cleanups.
155 *
156 * The following cleanup operations are performed -
157 * - Free the timers
158 * - Free beacon buffers
159 * - Free private structures
160 * - Free adapter structure
161 */
162static int mwifiex_unregister(struct mwifiex_adapter *adapter)
163{
164 s32 i = 0;
165
166 del_timer(&adapter->cmd_timer);
167
168 /* Free private structures */
169 for (i = 0; i < adapter->priv_num; i++) {
170 if (adapter->priv[i]) {
171 mwifiex_free_curr_bcn(adapter->priv[i]);
172 kfree(adapter->priv[i]);
173 }
174 }
175
176 kfree(adapter);
177 return 0;
178}
179
180/*
181 * The main process.
182 *
183 * This function is the main procedure of the driver and handles various driver
184 * operations. It runs in a loop and provides the core functionalities.
185 *
186 * The main responsibilities of this function are -
187 * - Ensure concurrency control
188 * - Handle pending interrupts and call interrupt handlers
189 * - Wake up the card if required
190 * - Handle command responses and call response handlers
191 * - Handle events and call event handlers
192 * - Execute pending commands
193 * - Transmit pending data packets
194 */
195int mwifiex_main_process(struct mwifiex_adapter *adapter)
196{
197 int ret = 0;
198 unsigned long flags;
199
200 spin_lock_irqsave(&adapter->main_proc_lock, flags);
201
202 /* Check if already processing */
203 if (adapter->mwifiex_processing) {
204 spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
205 goto exit_main_proc;
206 } else {
207 adapter->mwifiex_processing = true;
208 spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
209 }
210process_start:
211 do {
212 if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
213 (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
214 break;
215
216 /* Handle pending interrupt if any */
217 if (adapter->int_status) {
218 if (adapter->hs_activated)
219 mwifiex_process_hs_config(adapter);
220 adapter->if_ops.process_int_status(adapter);
221 }
222
223 /* Need to wake up the card ? */
224 if ((adapter->ps_state == PS_STATE_SLEEP) &&
225 (adapter->pm_wakeup_card_req &&
226 !adapter->pm_wakeup_fw_try) &&
227 (is_command_pending(adapter)
228 || !mwifiex_wmm_lists_empty(adapter))) {
229 adapter->pm_wakeup_fw_try = true;
230 adapter->if_ops.wakeup(adapter);
231 continue;
232 }
233 if (IS_CARD_RX_RCVD(adapter)) {
234 adapter->pm_wakeup_fw_try = false;
235 if (adapter->ps_state == PS_STATE_SLEEP)
236 adapter->ps_state = PS_STATE_AWAKE;
237 } else {
238 /* We have tried to wakeup the card already */
239 if (adapter->pm_wakeup_fw_try)
240 break;
241 if (adapter->ps_state != PS_STATE_AWAKE ||
242 adapter->tx_lock_flag)
243 break;
244
245 if (adapter->scan_processing || adapter->data_sent
246 || mwifiex_wmm_lists_empty(adapter)) {
247 if (adapter->cmd_sent || adapter->curr_cmd
248 || (!is_command_pending(adapter)))
249 break;
250 }
251 }
252
253 /* Check for Cmd Resp */
254 if (adapter->cmd_resp_received) {
255 adapter->cmd_resp_received = false;
256 mwifiex_process_cmdresp(adapter);
257
258 /* call mwifiex back when init_fw is done */
259 if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) {
260 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
261 mwifiex_init_fw_complete(adapter);
262 }
263 }
264
265 /* Check for event */
266 if (adapter->event_received) {
267 adapter->event_received = false;
268 mwifiex_process_event(adapter);
269 }
270
271 /* Check if we need to confirm Sleep Request
272 received previously */
273 if (adapter->ps_state == PS_STATE_PRE_SLEEP) {
274 if (!adapter->cmd_sent && !adapter->curr_cmd)
275 mwifiex_check_ps_cond(adapter);
276 }
277
278 /* * The ps_state may have been changed during processing of
279 * Sleep Request event.
280 */
281 if ((adapter->ps_state == PS_STATE_SLEEP)
282 || (adapter->ps_state == PS_STATE_PRE_SLEEP)
283 || (adapter->ps_state == PS_STATE_SLEEP_CFM)
284 || adapter->tx_lock_flag)
285 continue;
286
287 if (!adapter->cmd_sent && !adapter->curr_cmd) {
288 if (mwifiex_exec_next_cmd(adapter) == -1) {
289 ret = -1;
290 break;
291 }
292 }
293
294 if (!adapter->scan_processing && !adapter->data_sent &&
295 !mwifiex_wmm_lists_empty(adapter)) {
296 mwifiex_wmm_process_tx(adapter);
297 if (adapter->hs_activated) {
298 adapter->is_hs_configured = false;
299 mwifiex_hs_activated_event
300 (mwifiex_get_priv
301 (adapter, MWIFIEX_BSS_ROLE_ANY),
302 false);
303 }
304 }
305
306 if (adapter->delay_null_pkt && !adapter->cmd_sent &&
307 !adapter->curr_cmd && !is_command_pending(adapter)
308 && mwifiex_wmm_lists_empty(adapter)) {
309 if (!mwifiex_send_null_packet
310 (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
311 MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
312 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) {
313 adapter->delay_null_pkt = false;
314 adapter->ps_state = PS_STATE_SLEEP;
315 }
316 break;
317 }
318 } while (true);
319
320 if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter))
321 goto process_start;
322
323 spin_lock_irqsave(&adapter->main_proc_lock, flags);
324 adapter->mwifiex_processing = false;
325 spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
326
327exit_main_proc:
328 if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING)
329 mwifiex_shutdown_drv(adapter);
330 return ret;
331}
332
333/*
334 * This function initializes the software.
335 *
336 * The main work includes allocating and initializing the adapter structure
337 * and initializing the private structures.
338 */
339static int
340mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex)
341{
342 int i;
343 struct mwifiex_device device;
344 struct mwifiex_drv_mode *drv_mode_ptr;
345
346 /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
347 drv_mode_ptr = NULL;
348 for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
349 if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
350 drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
351 break;
352 }
353 }
354
355 if (!drv_mode_ptr) {
356 pr_err("invalid drv_mode=%d\n", drv_mode);
357 return -1;
358 }
359
360 memset(&device, 0, sizeof(struct mwifiex_device));
361
362 for (i = 0; i < drv_mode_ptr->intf_num; i++) {
363 device.bss_attr[i].bss_type =
364 drv_mode_ptr->bss_attr[i].bss_type;
365 device.bss_attr[i].frame_type =
366 drv_mode_ptr->bss_attr[i].frame_type;
367 device.bss_attr[i].active = drv_mode_ptr->bss_attr[i].active;
368 device.bss_attr[i].bss_priority =
369 drv_mode_ptr->bss_attr[i].bss_priority;
370 device.bss_attr[i].bss_num = drv_mode_ptr->bss_attr[i].bss_num;
371 }
372
373 if (mwifiex_register(card, if_ops, &device, pmwifiex))
374 return -1;
375
376 return 0;
377}
378
379/*
380 * This function frees the adapter structure.
381 *
382 * Additionally, this closes the netlink socket, frees the timers
383 * and private structures.
384 */
385static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
386{
387 if (!adapter) {
388 pr_err("%s: adapter is NULL\n", __func__);
389 return;
390 }
391
392 mwifiex_unregister(adapter);
393 pr_debug("info: %s: free adapter\n", __func__);
394}
395
396/*
397 * This function initializes the hardware and firmware.
398 *
399 * The main initialization steps followed are -
400 * - Download the correct firmware to card
401 * - Allocate and initialize the adapter structure
402 * - Initialize the private structures
403 * - Issue the init commands to firmware
404 */
405static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
406{
407 int ret = 0;
408 int err;
409 struct mwifiex_fw_image fw;
410
411 memset(&fw, 0, sizeof(struct mwifiex_fw_image));
412
413 switch (adapter->revision_id) {
414 case SD8787_W0:
415 case SD8787_W1:
416 strcpy(fw_name, SD8787_W1_FW_NAME);
417 break;
418 case SD8787_A0:
419 case SD8787_A1:
420 strcpy(fw_name, SD8787_AX_FW_NAME);
421 break;
422 default:
423 break;
424 }
425
426 err = request_firmware(&adapter->firmware, fw_name, adapter->dev);
427 if (err < 0) {
428 dev_err(adapter->dev, "request_firmware() returned"
429 " error code %#x\n", err);
430 ret = -1;
431 goto done;
432 }
433 fw.fw_buf = (u8 *) adapter->firmware->data;
434 fw.fw_len = adapter->firmware->size;
435
436 ret = mwifiex_dnld_fw(adapter, &fw);
437 if (ret == -1)
438 goto done;
439
440 dev_notice(adapter->dev, "WLAN FW is active\n");
441
442 adapter->init_wait_q_woken = false;
443 ret = mwifiex_init_fw(adapter);
444 if (ret == -1) {
445 goto done;
446 } else if (!ret) {
447 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
448 goto done;
449 }
450 /* Wait for mwifiex_init to complete */
451 wait_event_interruptible(adapter->init_wait_q,
452 adapter->init_wait_q_woken);
453 if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
454 ret = -1;
455 goto done;
456 }
457 ret = 0;
458
459done:
460 if (adapter->firmware)
461 release_firmware(adapter->firmware);
462 if (ret)
463 ret = -1;
464 return ret;
465}
466
467/*
468 * This function fills a driver buffer.
469 *
470 * The function associates a given SKB with the provided driver buffer
471 * and also updates some of the SKB parameters, including IP header,
472 * priority and timestamp.
473 */
474static void
475mwifiex_fill_buffer(struct sk_buff *skb)
476{
477 struct ethhdr *eth = NULL;
478 struct iphdr *iph;
479 struct timeval tv;
480 u8 tid = 0;
481
482 eth = (struct ethhdr *) skb->data;
483 switch (eth->h_proto) {
484 case __constant_htons(ETH_P_IP):
485 iph = ip_hdr(skb);
486 tid = IPTOS_PREC(iph->tos);
487 pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
488 eth->h_proto, tid, skb->priority);
489 break;
490 case __constant_htons(ETH_P_ARP):
491 pr_debug("data: ARP packet: %04x\n", eth->h_proto);
492 default:
493 break;
494 }
495/* Offset for TOS field in the IP header */
496#define IPTOS_OFFSET 5
497 tid = (tid >> IPTOS_OFFSET);
498 skb->priority = tid;
499 /* Record the current time the packet was queued; used to
500 determine the amount of time the packet was queued in
501 the driver before it was sent to the firmware.
502 The delay is then sent along with the packet to the
503 firmware for aggregate delay calculation for stats and
504 MSDU lifetime expiry.
505 */
506 do_gettimeofday(&tv);
507 skb->tstamp = timeval_to_ktime(tv);
508 return;
509}
510
511/*
512 * CFG802.11 network device handler for open.
513 *
514 * Starts the data queue.
515 */
516static int
517mwifiex_open(struct net_device *dev)
518{
519 netif_start_queue(dev);
520 return 0;
521}
522
523/*
524 * CFG802.11 network device handler for close.
525 */
526static int
527mwifiex_close(struct net_device *dev)
528{
529 return 0;
530}
531
532/*
533 * CFG802.11 network device handler for data transmission.
534 */
535static int
536mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
537{
538 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
539 struct sk_buff *new_skb = NULL;
540 struct mwifiex_txinfo *tx_info;
541
542 dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n",
543 jiffies, priv->bss_index);
544
545 if (priv->adapter->surprise_removed) {
546 kfree(skb);
547 priv->stats.tx_dropped++;
548 return 0;
549 }
550 if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
551 dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
552 kfree(skb);
553 priv->stats.tx_dropped++;
554 return 0;
555 }
556 if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
557 dev_dbg(priv->adapter->dev,
558 "data: Tx: insufficient skb headroom %d\n",
559 skb_headroom(skb));
560 /* Insufficient skb headroom - allocate a new skb */
561 new_skb =
562 skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
563 if (unlikely(!new_skb)) {
564 dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
565 kfree(skb);
566 priv->stats.tx_dropped++;
567 return 0;
568 }
569 kfree_skb(skb);
570 skb = new_skb;
571 dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n",
572 skb_headroom(skb));
573 }
574
575 tx_info = MWIFIEX_SKB_TXCB(skb);
576 tx_info->bss_index = priv->bss_index;
577 mwifiex_fill_buffer(skb);
578
579 mwifiex_wmm_add_buf_txqueue(priv->adapter, skb);
580 atomic_inc(&priv->adapter->tx_pending);
581
582 if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
583 netif_stop_queue(priv->netdev);
584 dev->trans_start = jiffies;
585 }
586
587 queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
588
589 return 0;
590}
591
592/*
593 * CFG802.11 network device handler for setting MAC address.
594 */
595static int
596mwifiex_set_mac_address(struct net_device *dev, void *addr)
597{
598 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
599 struct sockaddr *hw_addr = (struct sockaddr *) addr;
600
601 memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
602
603 if (mwifiex_request_set_mac_address(priv)) {
604 dev_err(priv->adapter->dev, "set MAC address failed\n");
605 return -EFAULT;
606 }
607 memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
608
609 return 0;
610}
611
612/*
613 * CFG802.11 network device handler for setting multicast list.
614 */
615static void mwifiex_set_multicast_list(struct net_device *dev)
616{
617 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
618 mwifiex_request_set_multicast_list(priv, dev);
619}
620
621/*
622 * CFG802.11 network device handler for transmission timeout.
623 */
624static void
625mwifiex_tx_timeout(struct net_device *dev)
626{
627 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
628
629 dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n",
630 jiffies, priv->bss_index);
631 dev->trans_start = jiffies;
632 priv->num_tx_timeout++;
633}
634
635/*
636 * CFG802.11 network device handler for statistics retrieval.
637 */
638static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
639{
640 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
641
642 return &priv->stats;
643}
644
645/* Network device handlers */
646static const struct net_device_ops mwifiex_netdev_ops = {
647 .ndo_open = mwifiex_open,
648 .ndo_stop = mwifiex_close,
649 .ndo_start_xmit = mwifiex_hard_start_xmit,
650 .ndo_set_mac_address = mwifiex_set_mac_address,
651 .ndo_tx_timeout = mwifiex_tx_timeout,
652 .ndo_get_stats = mwifiex_get_stats,
653 .ndo_set_multicast_list = mwifiex_set_multicast_list,
654};
655
656/*
657 * This function initializes the private structure parameters.
658 *
659 * The following wait queues are initialized -
660 * - IOCTL wait queue
661 * - Command wait queue
662 * - Statistics wait queue
663 *
664 * ...and the following default parameters are set -
665 * - Current key index : Set to 0
666 * - Rate index : Set to auto
667 * - Media connected : Set to disconnected
668 * - Adhoc link sensed : Set to false
669 * - Nick name : Set to null
670 * - Number of Tx timeout : Set to 0
671 * - Device address : Set to current address
672 *
673 * In addition, the CFG80211 work queue is also created.
674 */
675static void
676mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
677{
678 dev->netdev_ops = &mwifiex_netdev_ops;
679 /* Initialize private structure */
680 init_waitqueue_head(&priv->ioctl_wait_q);
681 init_waitqueue_head(&priv->cmd_wait_q);
682 init_waitqueue_head(&priv->w_stats_wait_q);
683 priv->current_key_index = 0;
684 priv->media_connected = false;
685 memset(&priv->nick_name, 0, sizeof(priv->nick_name));
686 priv->num_tx_timeout = 0;
687 priv->workqueue = create_singlethread_workqueue("cfg80211_wq");
688 INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results);
689 memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
690}
691
692/*
693 * This function adds a new logical interface.
694 *
695 * It allocates, initializes and registers the interface by performing
696 * the following opearations -
697 * - Allocate a new net device structure
698 * - Assign device name
699 * - Register the new device with CFG80211 subsystem
700 * - Initialize semaphore and private structure
701 * - Register the new device with kernel
702 * - Create the complete debug FS structure if configured
703 */
704static struct mwifiex_private *mwifiex_add_interface(
705 struct mwifiex_adapter *adapter,
706 u8 bss_index, u8 bss_type)
707{
708 struct net_device *dev = NULL;
709 struct mwifiex_private *priv = NULL;
710 void *mdev_priv = NULL;
711
712 dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
713 ether_setup, 1);
714 if (!dev) {
715 dev_err(adapter->dev, "no memory available for netdevice\n");
716 goto error;
717 }
718 if (dev_alloc_name(dev, dev->name)) {
719 dev_err(adapter->dev, "unable to alloc name for netdevice\n");
720 goto error;
721 }
722
723 if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
724 adapter->priv[bss_index]) != 0) {
725 dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
726 goto error;
727 }
728 /* Save the priv pointer in netdev */
729 priv = adapter->priv[bss_index];
730 mdev_priv = netdev_priv(dev);
731 *((unsigned long *) mdev_priv) = (unsigned long) priv;
732
733 priv->netdev = dev;
734
735 sema_init(&priv->async_sem, 1);
736 priv->scan_pending_on_block = false;
737
738 mwifiex_init_priv_params(priv, dev);
739
740 SET_NETDEV_DEV(dev, adapter->dev);
741
742 /* Register network device */
743 if (register_netdev(dev)) {
744 dev_err(adapter->dev, "cannot register virtual network device\n");
745 goto error;
746 }
747
748 dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
749#ifdef CONFIG_DEBUG_FS
750 mwifiex_dev_debugfs_init(priv);
751#endif
752 return priv;
753error:
754 if (dev)
755 free_netdev(dev);
756 return NULL;
757}
758
759/*
760 * This function removes a logical interface.
761 *
762 * It deregisters, resets and frees the interface by performing
763 * the following operations -
764 * - Disconnect the device if connected, send wireless event to
765 * notify applications.
766 * - Remove the debug FS structure if configured
767 * - Unregister the device from kernel
768 * - Free the net device structure
769 * - Cancel all works and destroy work queue
770 * - Unregister and free the wireless device from CFG80211 subsystem
771 */
772static void
773mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
774{
775 struct net_device *dev = NULL;
776 struct mwifiex_private *priv = adapter->priv[bss_index];
777
778 if (!priv)
779 return;
780 dev = priv->netdev;
781
782 if (priv->media_connected)
783 priv->media_connected = false;
784
785#ifdef CONFIG_DEBUG_FS
786 mwifiex_dev_debugfs_remove(priv);
787#endif
788 /* Last reference is our one */
789 dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
790 dev->name, netdev_refcnt_read(dev));
791
792 if (dev->reg_state == NETREG_REGISTERED)
793 unregister_netdev(dev);
794
795 /* Clear the priv in adapter */
796 priv->netdev = NULL;
797 if (dev)
798 free_netdev(dev);
799
800 cancel_work_sync(&priv->cfg_workqueue);
801 flush_workqueue(priv->workqueue);
802 destroy_workqueue(priv->workqueue);
803 wiphy_unregister(priv->wdev->wiphy);
804 wiphy_free(priv->wdev->wiphy);
805 kfree(priv->wdev);
806
807 return;
808}
809
810/*
811 * Sends IOCTL request to shutdown firmware.
812 *
813 * This function allocates the IOCTL request buffer, fills it
814 * with requisite parameters and calls the IOCTL handler.
815 */
816int mwifiex_shutdown_fw(struct mwifiex_private *priv, u8 wait_option)
817{
818 struct mwifiex_wait_queue *wait = NULL;
819 int status = 0;
820
821 /* Allocate an IOCTL request buffer */
822 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
823 if (!wait)
824 return -ENOMEM;
825
826 status = mwifiex_misc_ioctl_init_shutdown(priv->adapter, wait,
827 MWIFIEX_FUNC_SHUTDOWN);
828
829 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
830
831 kfree(wait);
832 return status;
833}
834EXPORT_SYMBOL_GPL(mwifiex_shutdown_fw);
835
836/*
837 * This function check if command is pending.
838 */
839int is_command_pending(struct mwifiex_adapter *adapter)
840{
841 unsigned long flags;
842 int is_cmd_pend_q_empty;
843
844 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
845 is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
846 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
847
848 return !is_cmd_pend_q_empty;
849}
850
851/*
852 * This function returns the correct private structure pointer based
853 * upon the BSS number.
854 */
855struct mwifiex_private *
856mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index)
857{
858 if (!adapter || (bss_index >= adapter->priv_num))
859 return NULL;
860 return adapter->priv[bss_index];
861}
862
863/*
864 * This is the main work queue function.
865 *
866 * It handles the main process, which in turn handles the complete
867 * driver operations.
868 */
869static void mwifiex_main_work_queue(struct work_struct *work)
870{
871 struct mwifiex_adapter *adapter =
872 container_of(work, struct mwifiex_adapter, main_work);
873
874 if (adapter->surprise_removed)
875 return;
876 mwifiex_main_process(adapter);
877}
878
879/*
880 * This function cancels all works in the queue and destroys
881 * the main workqueue.
882 */
883static void
884mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
885{
886 flush_workqueue(adapter->workqueue);
887 destroy_workqueue(adapter->workqueue);
888 adapter->workqueue = NULL;
889}
890
891/*
892 * This function adds the card.
893 *
894 * This function follows the following major steps to set up the device -
895 * - Initialize software. This includes probing the card, registering
896 * the interface operations table, and allocating/initializing the
897 * adapter structure
898 * - Set up the netlink socket
899 * - Create and start the main work queue
900 * - Register the device
901 * - Initialize firmware and hardware
902 * - Add logical interfaces
903 */
904int
905mwifiex_add_card(void *card, struct semaphore *sem,
906 struct mwifiex_if_ops *if_ops)
907{
908 int status = 0;
909 int i;
910 struct mwifiex_adapter *adapter = NULL;
911 struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0];
912
913 if (down_interruptible(sem))
914 goto exit_sem_err;
915
916 if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) {
917 pr_err("%s: software init failed\n", __func__);
918 goto err_init_sw;
919 }
920
921 adapter->drv_mode = drv_mode_info;
922
923 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
924 /* PnP and power profile */
925 adapter->surprise_removed = false;
926 init_waitqueue_head(&adapter->init_wait_q);
927 adapter->is_suspended = false;
928 adapter->hs_activated = false;
929 init_waitqueue_head(&adapter->hs_activate_wait_q);
930
931 /* Create workqueue */
932 adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
933 if (!adapter->workqueue)
934 goto err_kmalloc;
935
936 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
937
938 /* Register the device. Fill up the private data structure with relevant
939 information from the card and request for the required IRQ. */
940 if (adapter->if_ops.register_dev(adapter)) {
941 pr_err("%s: failed to register mwifiex device\n", __func__);
942 goto err_registerdev;
943 }
944
945 /* Init FW and HW */
946 if (mwifiex_init_hw_fw(adapter)) {
947 pr_err("%s: firmware init failed\n", __func__);
948 goto err_init_fw;
949 }
950 /* Add interfaces */
951 for (i = 0; i < drv_mode_info->intf_num; i++) {
952 if (!mwifiex_add_interface(adapter, i,
953 adapter->drv_mode->bss_attr[i].bss_type)) {
954 status = -1;
955 break;
956 }
957 }
958 if (status)
959 goto err_add_intf;
960
961 up(sem);
962
963 return 0;
964
965err_add_intf:
966 for (i = 0; i < adapter->priv_num; i++)
967 mwifiex_remove_interface(adapter, i);
968err_init_fw:
969 /* Unregister device */
970 pr_debug("info: %s: unregister device\n", __func__);
971 adapter->if_ops.unregister_dev(adapter);
972err_registerdev:
973 adapter->surprise_removed = true;
974 mwifiex_terminate_workqueue(adapter);
975err_kmalloc:
976 if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
977 (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
978 pr_debug("info: %s: shutdown mwifiex\n", __func__);
979 adapter->init_wait_q_woken = false;
980 status = mwifiex_shutdown_drv(adapter);
981 if (status == -EINPROGRESS)
982 wait_event_interruptible(adapter->init_wait_q,
983 adapter->init_wait_q_woken);
984 }
985
986 mwifiex_free_adapter(adapter);
987
988err_init_sw:
989 up(sem);
990
991exit_sem_err:
992 return -1;
993}
994EXPORT_SYMBOL_GPL(mwifiex_add_card);
995
996/*
997 * This function removes the card.
998 *
999 * This function follows the following major steps to remove the device -
1000 * - Stop data traffic
1001 * - Shutdown firmware
1002 * - Remove the logical interfaces
1003 * - Terminate the work queue
1004 * - Unregister the device
1005 * - Free the adapter structure
1006 */
1007int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
1008{
1009 struct mwifiex_private *priv = NULL;
1010 int status;
1011 int i;
1012
1013 if (down_interruptible(sem))
1014 goto exit_sem_err;
1015
1016 if (!adapter)
1017 goto exit_remove;
1018
1019 adapter->surprise_removed = true;
1020
1021 /* Stop data */
1022 for (i = 0; i < adapter->priv_num; i++) {
1023 priv = adapter->priv[i];
1024 if (priv) {
1025 if (!netif_queue_stopped(priv->netdev))
1026 netif_stop_queue(priv->netdev);
1027 if (netif_carrier_ok(priv->netdev))
1028 netif_carrier_off(priv->netdev);
1029 }
1030 }
1031
1032 dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
1033 adapter->init_wait_q_woken = false;
1034 status = mwifiex_shutdown_drv(adapter);
1035 if (status == -EINPROGRESS)
1036 wait_event_interruptible(adapter->init_wait_q,
1037 adapter->init_wait_q_woken);
1038 dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n");
1039 if (atomic_read(&adapter->rx_pending) ||
1040 atomic_read(&adapter->tx_pending) ||
1041 atomic_read(&adapter->ioctl_pending)) {
1042 dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
1043 "ioctl_pending=%d\n",
1044 atomic_read(&adapter->rx_pending),
1045 atomic_read(&adapter->tx_pending),
1046 atomic_read(&adapter->ioctl_pending));
1047 }
1048
1049 /* Remove interface */
1050 for (i = 0; i < adapter->priv_num; i++)
1051 mwifiex_remove_interface(adapter, i);
1052
1053 mwifiex_terminate_workqueue(adapter);
1054
1055 /* Unregister device */
1056 dev_dbg(adapter->dev, "info: unregister device\n");
1057 adapter->if_ops.unregister_dev(adapter);
1058 /* Free adapter structure */
1059 dev_dbg(adapter->dev, "info: free adapter\n");
1060 mwifiex_free_adapter(adapter);
1061
1062exit_remove:
1063 up(sem);
1064exit_sem_err:
1065 return 0;
1066}
1067EXPORT_SYMBOL_GPL(mwifiex_remove_card);
1068
1069/*
1070 * This function initializes the module.
1071 *
1072 * The debug FS is also initialized if configured.
1073 */
1074static int
1075mwifiex_init_module(void)
1076{
1077#ifdef CONFIG_DEBUG_FS
1078 mwifiex_debugfs_init();
1079#endif
1080 return 0;
1081}
1082
1083/*
1084 * This function cleans up the module.
1085 *
1086 * The debug FS is removed if available.
1087 */
1088static void
1089mwifiex_cleanup_module(void)
1090{
1091#ifdef CONFIG_DEBUG_FS
1092 mwifiex_debugfs_remove();
1093#endif
1094}
1095
1096module_init(mwifiex_init_module);
1097module_exit(mwifiex_cleanup_module);
1098
1099MODULE_AUTHOR("Marvell International Ltd.");
1100MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION);
1101MODULE_VERSION(VERSION);
1102MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
new file mode 100644
index 000000000000..2b0ad8e3d6e2
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -0,0 +1,1081 @@
1/*
2 * Marvell Wireless LAN device driver: major data structures and prototypes
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_MAIN_H_
21#define _MWIFIEX_MAIN_H_
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/sched.h>
26#include <linux/semaphore.h>
27#include <linux/ip.h>
28#include <linux/skbuff.h>
29#include <linux/if_arp.h>
30#include <linux/etherdevice.h>
31#include <net/sock.h>
32#include <net/lib80211.h>
33#include <linux/firmware.h>
34#include <linux/ctype.h>
35
36#include "decl.h"
37#include "ioctl.h"
38#include "util.h"
39#include "fw.h"
40
41extern const char driver_version[];
42extern struct mwifiex_adapter *g_adapter;
43
44enum {
45 MWIFIEX_NO_WAIT,
46 MWIFIEX_IOCTL_WAIT,
47 MWIFIEX_CMD_WAIT,
48 MWIFIEX_PROC_WAIT,
49 MWIFIEX_WSTATS_WAIT
50};
51
52#define DRV_MODE_STA 0x1
53#define DRV_MODE_UAP 0x2
54#define DRV_MODE_UAP_STA 0x3
55
56#define SD8787_W0 0x30
57#define SD8787_W1 0x31
58#define SD8787_A0 0x40
59#define SD8787_A1 0x41
60
61#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
62#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin"
63#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin"
64
65struct mwifiex_drv_mode {
66 u16 drv_mode;
67 u16 intf_num;
68 struct mwifiex_bss_attr *bss_attr;
69};
70
71
72#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
73
74#define MWIFIEX_TIMER_10S 10000
75#define MWIFIEX_TIMER_1S 1000
76
77#define NL_MAX_PAYLOAD 1024
78#define NL_MULTICAST_GROUP 1
79
80#define MAX_TX_PENDING 60
81
82#define HEADER_ALIGNMENT 8
83
84#define MWIFIEX_UPLD_SIZE (2312)
85
86#define MAX_EVENT_SIZE 1024
87
88#define ARP_FILTER_MAX_BUF_SIZE 68
89
90#define MWIFIEX_KEY_BUFFER_SIZE 16
91#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10
92#define MWIFIEX_MAX_REGION_CODE 7
93
94#define DEFAULT_BCN_AVG_FACTOR 8
95#define DEFAULT_DATA_AVG_FACTOR 8
96
97#define FIRST_VALID_CHANNEL 0xff
98#define DEFAULT_AD_HOC_CHANNEL 6
99#define DEFAULT_AD_HOC_CHANNEL_A 36
100
101#define DEFAULT_BCN_MISS_TIMEOUT 5
102
103#define MAX_SCAN_BEACON_BUFFER 8000
104
105#define SCAN_BEACON_ENTRY_PAD 6
106
107#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200
108#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200
109#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110
110
111#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
112
113#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
114
115#define RSN_GTK_OUI_OFFSET 2
116
117#define MWIFIEX_OUI_NOT_PRESENT 0
118#define MWIFIEX_OUI_PRESENT 1
119
120#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
121 adapter->event_received || \
122 adapter->data_received)
123
124#define MWIFIEX_TYPE_CMD 1
125#define MWIFIEX_TYPE_DATA 0
126#define MWIFIEX_TYPE_EVENT 3
127
128#define DBG_CMD_NUM 5
129
130#define MAX_BITMAP_RATES_SIZE 10
131
132#define MAX_CHANNEL_BAND_BG 14
133
134#define MAX_FREQUENCY_BAND_BG 2484
135
136struct mwifiex_dbg {
137 u32 num_cmd_host_to_card_failure;
138 u32 num_cmd_sleep_cfm_host_to_card_failure;
139 u32 num_tx_host_to_card_failure;
140 u32 num_event_deauth;
141 u32 num_event_disassoc;
142 u32 num_event_link_lost;
143 u32 num_cmd_deauth;
144 u32 num_cmd_assoc_success;
145 u32 num_cmd_assoc_failure;
146 u32 num_tx_timeout;
147 u32 num_cmd_timeout;
148 u16 timeout_cmd_id;
149 u16 timeout_cmd_act;
150 u16 last_cmd_id[DBG_CMD_NUM];
151 u16 last_cmd_act[DBG_CMD_NUM];
152 u16 last_cmd_index;
153 u16 last_cmd_resp_id[DBG_CMD_NUM];
154 u16 last_cmd_resp_index;
155 u16 last_event[DBG_CMD_NUM];
156 u16 last_event_index;
157};
158
159enum MWIFIEX_HARDWARE_STATUS {
160 MWIFIEX_HW_STATUS_READY,
161 MWIFIEX_HW_STATUS_INITIALIZING,
162 MWIFIEX_HW_STATUS_FW_READY,
163 MWIFIEX_HW_STATUS_INIT_DONE,
164 MWIFIEX_HW_STATUS_RESET,
165 MWIFIEX_HW_STATUS_CLOSING,
166 MWIFIEX_HW_STATUS_NOT_READY
167};
168
169enum MWIFIEX_802_11_POWER_MODE {
170 MWIFIEX_802_11_POWER_MODE_CAM,
171 MWIFIEX_802_11_POWER_MODE_PSP
172};
173
174struct mwifiex_tx_param {
175 u32 next_pkt_len;
176};
177
178enum MWIFIEX_PS_STATE {
179 PS_STATE_AWAKE,
180 PS_STATE_PRE_SLEEP,
181 PS_STATE_SLEEP_CFM,
182 PS_STATE_SLEEP
183};
184
185struct mwifiex_add_ba_param {
186 u32 tx_win_size;
187 u32 rx_win_size;
188 u32 timeout;
189};
190
191struct mwifiex_tx_aggr {
192 u8 ampdu_user;
193 u8 ampdu_ap;
194 u8 amsdu;
195};
196
197struct mwifiex_ra_list_tbl {
198 struct list_head list;
199 struct sk_buff_head skb_head;
200 u8 ra[ETH_ALEN];
201 u32 total_pkts_size;
202 u32 is_11n_enabled;
203};
204
205struct mwifiex_tid_tbl {
206 struct list_head ra_list;
207 /* spin lock for tid table */
208 spinlock_t tid_tbl_lock;
209 struct mwifiex_ra_list_tbl *ra_list_curr;
210};
211
212#define WMM_HIGHEST_PRIORITY 7
213#define HIGH_PRIO_TID 7
214#define LOW_PRIO_TID 0
215
216struct mwifiex_wmm_desc {
217 struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
218 u32 packets_out[MAX_NUM_TID];
219 /* spin lock to protect ra_list */
220 spinlock_t ra_list_spinlock;
221 struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES];
222 enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES];
223 u32 drv_pkt_delay_max;
224 u8 queue_priority[IEEE80211_MAX_QUEUES];
225 u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
226
227};
228
229struct mwifiex_802_11_security {
230 u8 wpa_enabled;
231 u8 wpa2_enabled;
232 u8 wapi_enabled;
233 u8 wapi_key_on;
234 enum MWIFIEX_802_11_WEP_STATUS wep_status;
235 u32 authentication_mode;
236 u32 encryption_mode;
237};
238
239struct ieee_types_header {
240 u8 element_id;
241 u8 len;
242} __packed;
243
244struct ieee_obss_scan_param {
245 u16 obss_scan_passive_dwell;
246 u16 obss_scan_active_dwell;
247 u16 bss_chan_width_trigger_scan_int;
248 u16 obss_scan_passive_total;
249 u16 obss_scan_active_total;
250 u16 bss_width_chan_trans_delay;
251 u16 obss_scan_active_threshold;
252} __packed;
253
254struct ieee_types_obss_scan_param {
255 struct ieee_types_header ieee_hdr;
256 struct ieee_obss_scan_param obss_scan;
257} __packed;
258
259#define MWIFIEX_SUPPORTED_RATES 14
260
261#define MWIFIEX_SUPPORTED_RATES_EXT 32
262
263#define IEEE_MAX_IE_SIZE 256
264
265struct ieee_types_vendor_specific {
266 struct ieee_types_vendor_header vend_hdr;
267 u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)];
268} __packed;
269
270struct ieee_types_generic {
271 struct ieee_types_header ieee_hdr;
272 u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)];
273} __packed;
274
275struct mwifiex_bssdescriptor {
276 u8 mac_address[ETH_ALEN];
277 struct mwifiex_802_11_ssid ssid;
278 u32 privacy;
279 s32 rssi;
280 u32 channel;
281 u32 freq;
282 u16 beacon_period;
283 u8 erp_flags;
284 u32 bss_mode;
285 u8 supported_rates[MWIFIEX_SUPPORTED_RATES];
286 u8 data_rates[MWIFIEX_SUPPORTED_RATES];
287 /* Network band.
288 * BAND_B(0x01): 'b' band
289 * BAND_G(0x02): 'g' band
290 * BAND_A(0X04): 'a' band
291 */
292 u16 bss_band;
293 long long network_tsf;
294 u8 time_stamp[8];
295 union ieee_types_phy_param_set phy_param_set;
296 union ieee_types_ss_param_set ss_param_set;
297 u16 cap_info_bitmap;
298 struct ieee_types_wmm_parameter wmm_ie;
299 u8 disable_11n;
300 struct ieee80211_ht_cap *bcn_ht_cap;
301 u16 ht_cap_offset;
302 struct ieee80211_ht_info *bcn_ht_info;
303 u16 ht_info_offset;
304 u8 *bcn_bss_co_2040;
305 u16 bss_co_2040_offset;
306 u8 *bcn_ext_cap;
307 u16 ext_cap_offset;
308 struct ieee_types_obss_scan_param *bcn_obss_scan;
309 u16 overlap_bss_offset;
310 struct ieee_types_vendor_specific *bcn_wpa_ie;
311 u16 wpa_offset;
312 struct ieee_types_generic *bcn_rsn_ie;
313 u16 rsn_offset;
314 struct ieee_types_generic *bcn_wapi_ie;
315 u16 wapi_offset;
316 u8 *beacon_buf;
317 u32 beacon_buf_size;
318 u32 beacon_buf_size_max;
319
320};
321
322struct mwifiex_current_bss_params {
323 struct mwifiex_bssdescriptor bss_descriptor;
324 u8 wmm_enabled;
325 u8 wmm_uapsd_enabled;
326 u8 band;
327 u32 num_of_rates;
328 u8 data_rates[MWIFIEX_SUPPORTED_RATES];
329};
330
331struct mwifiex_sleep_params {
332 u16 sp_error;
333 u16 sp_offset;
334 u16 sp_stable_time;
335 u8 sp_cal_control;
336 u8 sp_ext_sleep_clk;
337 u16 sp_reserved;
338};
339
340struct mwifiex_sleep_period {
341 u16 period;
342 u16 reserved;
343};
344
345struct mwifiex_wep_key {
346 u32 length;
347 u32 key_index;
348 u32 key_length;
349 u8 key_material[MWIFIEX_KEY_BUFFER_SIZE];
350};
351
352#define MAX_REGION_CHANNEL_NUM 2
353
354struct mwifiex_chan_freq_power {
355 u16 channel;
356 u32 freq;
357 u16 max_tx_power;
358 u8 unsupported;
359};
360
361enum state_11d_t {
362 DISABLE_11D = 0,
363 ENABLE_11D = 1,
364};
365
366#define MWIFIEX_MAX_TRIPLET_802_11D 83
367
368struct mwifiex_802_11d_domain_reg {
369 u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
370 u8 no_of_triplet;
371 struct ieee80211_country_ie_triplet
372 triplet[MWIFIEX_MAX_TRIPLET_802_11D];
373};
374
375struct mwifiex_vendor_spec_cfg_ie {
376 u16 mask;
377 u16 flag;
378 u8 ie[MWIFIEX_MAX_VSIE_LEN];
379};
380
381struct wps {
382 u8 session_enable;
383};
384
385struct mwifiex_adapter;
386struct mwifiex_private;
387
388struct mwifiex_private {
389 struct mwifiex_adapter *adapter;
390 u8 bss_index;
391 u8 bss_type;
392 u8 bss_role;
393 u8 bss_priority;
394 u8 bss_num;
395 u8 frame_type;
396 u8 curr_addr[ETH_ALEN];
397 u8 media_connected;
398 u32 num_tx_timeout;
399 struct net_device *netdev;
400 struct net_device_stats stats;
401 u16 curr_pkt_filter;
402 u32 bss_mode;
403 u32 pkt_tx_ctrl;
404 u16 tx_power_level;
405 u8 max_tx_power_level;
406 u8 min_tx_power_level;
407 u8 tx_rate;
408 u8 tx_htinfo;
409 u8 rxpd_htinfo;
410 u8 rxpd_rate;
411 u16 rate_bitmap;
412 u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
413 u32 data_rate;
414 u8 is_data_rate_auto;
415 u16 bcn_avg_factor;
416 u16 data_avg_factor;
417 s16 data_rssi_last;
418 s16 data_nf_last;
419 s16 data_rssi_avg;
420 s16 data_nf_avg;
421 s16 bcn_rssi_last;
422 s16 bcn_nf_last;
423 s16 bcn_rssi_avg;
424 s16 bcn_nf_avg;
425 struct mwifiex_bssdescriptor *attempted_bss_desc;
426 struct mwifiex_802_11_ssid prev_ssid;
427 u8 prev_bssid[ETH_ALEN];
428 struct mwifiex_current_bss_params curr_bss_params;
429 u16 beacon_period;
430 u16 listen_interval;
431 u16 atim_window;
432 u8 adhoc_channel;
433 u8 adhoc_is_link_sensed;
434 u8 adhoc_state;
435 struct mwifiex_802_11_security sec_info;
436 struct mwifiex_wep_key wep_key[NUM_WEP_KEYS];
437 u16 wep_key_curr_index;
438 u8 wpa_ie[256];
439 u8 wpa_ie_len;
440 u8 wpa_is_gtk_set;
441 struct host_cmd_ds_802_11_key_material aes_key;
442 u8 wapi_ie[256];
443 u8 wapi_ie_len;
444 u8 wmm_required;
445 u8 wmm_enabled;
446 u8 wmm_qosinfo;
447 struct mwifiex_wmm_desc wmm;
448 struct list_head tx_ba_stream_tbl_ptr;
449 /* spin lock for tx_ba_stream_tbl_ptr queue */
450 spinlock_t tx_ba_stream_tbl_lock;
451 struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID];
452 struct mwifiex_add_ba_param add_ba_param;
453 u16 rx_seq[MAX_NUM_TID];
454 struct list_head rx_reorder_tbl_ptr;
455 /* spin lock for rx_reorder_tbl_ptr queue */
456 spinlock_t rx_reorder_tbl_lock;
457 /* spin lock for Rx packets */
458 spinlock_t rx_pkt_lock;
459
460#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500
461 u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE];
462 u32 assoc_rsp_size;
463
464#define MWIFIEX_GENIE_BUF_SIZE 256
465 u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE];
466 u8 gen_ie_buf_len;
467
468 struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM];
469
470#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256
471 u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE];
472 u8 assoc_tlv_buf_len;
473
474 u8 *curr_bcn_buf;
475 u32 curr_bcn_size;
476 /* spin lock for beacon buffer */
477 spinlock_t curr_bcn_buf_lock;
478 u16 ioctl_wait_q_woken;
479 wait_queue_head_t ioctl_wait_q;
480 u16 cmd_wait_q_woken;
481 wait_queue_head_t cmd_wait_q;
482 struct wireless_dev *wdev;
483 struct mwifiex_chan_freq_power cfp;
484 char version_str[128];
485#ifdef CONFIG_DEBUG_FS
486 struct dentry *dfs_dev_dir;
487#endif
488 u8 nick_name[16];
489 struct iw_statistics w_stats;
490 u16 w_stats_wait_q_woken;
491 wait_queue_head_t w_stats_wait_q;
492 u16 current_key_index;
493 struct semaphore async_sem;
494 u8 scan_pending_on_block;
495 u8 report_scan_result;
496 struct cfg80211_scan_request *scan_request;
497 int scan_result_status;
498 bool assoc_request;
499 u16 assoc_result;
500 bool ibss_join_request;
501 u16 ibss_join_result;
502 bool disconnect;
503 u8 cfg_bssid[6];
504 struct workqueue_struct *workqueue;
505 struct work_struct cfg_workqueue;
506 u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
507 struct wps wps;
508 u8 scan_block;
509};
510
511enum mwifiex_ba_status {
512 BA_STREAM_NOT_SETUP = 0,
513 BA_STREAM_SETUP_INPROGRESS,
514 BA_STREAM_SETUP_COMPLETE
515};
516
517struct mwifiex_tx_ba_stream_tbl {
518 struct list_head list;
519 int tid;
520 u8 ra[ETH_ALEN];
521 enum mwifiex_ba_status ba_status;
522};
523
524struct mwifiex_rx_reorder_tbl;
525
526struct reorder_tmr_cnxt {
527 struct timer_list timer;
528 struct mwifiex_rx_reorder_tbl *ptr;
529 struct mwifiex_private *priv;
530};
531
532struct mwifiex_rx_reorder_tbl {
533 struct list_head list;
534 int tid;
535 u8 ta[ETH_ALEN];
536 int start_win;
537 int win_size;
538 void **rx_reorder_ptr;
539 struct reorder_tmr_cnxt timer_context;
540};
541
542struct mwifiex_bss_prio_node {
543 struct list_head list;
544 struct mwifiex_private *priv;
545};
546
547struct mwifiex_bss_prio_tbl {
548 struct list_head bss_prio_head;
549 /* spin lock for bss priority */
550 spinlock_t bss_prio_lock;
551 struct mwifiex_bss_prio_node *bss_prio_cur;
552};
553
554struct cmd_ctrl_node {
555 struct list_head list;
556 struct mwifiex_private *priv;
557 u32 cmd_oid;
558 u32 cmd_flag;
559 struct sk_buff *cmd_skb;
560 struct sk_buff *resp_skb;
561 void *data_buf;
562 void *wq_buf;
563 struct sk_buff *skb;
564};
565
566struct mwifiex_if_ops {
567 int (*init_if) (struct mwifiex_adapter *);
568 void (*cleanup_if) (struct mwifiex_adapter *);
569 int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
570 int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
571 int (*register_dev) (struct mwifiex_adapter *);
572 void (*unregister_dev) (struct mwifiex_adapter *);
573 int (*enable_int) (struct mwifiex_adapter *);
574 int (*process_int_status) (struct mwifiex_adapter *);
575 int (*host_to_card) (struct mwifiex_adapter *, u8,
576 u8 *payload, u32 pkt_len,
577 struct mwifiex_tx_param *);
578 int (*wakeup) (struct mwifiex_adapter *);
579 int (*wakeup_complete) (struct mwifiex_adapter *);
580
581 void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
582 void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
583};
584
585struct mwifiex_adapter {
586 struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
587 u8 priv_num;
588 struct mwifiex_drv_mode *drv_mode;
589 const struct firmware *firmware;
590 struct device *dev;
591 bool surprise_removed;
592 u32 fw_release_number;
593 u32 revision_id;
594 u16 init_wait_q_woken;
595 wait_queue_head_t init_wait_q;
596 void *card;
597 struct mwifiex_if_ops if_ops;
598 atomic_t rx_pending;
599 atomic_t tx_pending;
600 atomic_t ioctl_pending;
601 struct workqueue_struct *workqueue;
602 struct work_struct main_work;
603 struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
604 /* spin lock for init/shutdown */
605 spinlock_t mwifiex_lock;
606 /* spin lock for main process */
607 spinlock_t main_proc_lock;
608 u32 mwifiex_processing;
609 u16 max_tx_buf_size;
610 u16 tx_buf_size;
611 u16 curr_tx_buf_size;
612 u32 ioport;
613 enum MWIFIEX_HARDWARE_STATUS hw_status;
614 u16 radio_on;
615 u16 number_of_antenna;
616 u32 fw_cap_info;
617 /* spin lock for interrupt handling */
618 spinlock_t int_lock;
619 u8 int_status;
620 u32 event_cause;
621 struct sk_buff *event_skb;
622 u8 upld_buf[MWIFIEX_UPLD_SIZE];
623 u8 data_sent;
624 u8 cmd_sent;
625 u8 cmd_resp_received;
626 u8 event_received;
627 u8 data_received;
628 u16 seq_num;
629 struct cmd_ctrl_node *cmd_pool;
630 struct cmd_ctrl_node *curr_cmd;
631 /* spin lock for command */
632 spinlock_t mwifiex_cmd_lock;
633 u32 num_cmd_timeout;
634 u16 last_init_cmd;
635 struct timer_list cmd_timer;
636 struct list_head cmd_free_q;
637 /* spin lock for cmd_free_q */
638 spinlock_t cmd_free_q_lock;
639 struct list_head cmd_pending_q;
640 /* spin lock for cmd_pending_q */
641 spinlock_t cmd_pending_q_lock;
642 struct list_head scan_pending_q;
643 /* spin lock for scan_pending_q */
644 spinlock_t scan_pending_q_lock;
645 u32 scan_processing;
646 u16 region_code;
647 struct mwifiex_802_11d_domain_reg domain_reg;
648 struct mwifiex_bssdescriptor *scan_table;
649 u32 num_in_scan_table;
650 u16 scan_probes;
651 u32 scan_mode;
652 u16 specific_scan_time;
653 u16 active_scan_time;
654 u16 passive_scan_time;
655 u8 bcn_buf[MAX_SCAN_BEACON_BUFFER];
656 u8 *bcn_buf_end;
657 u8 fw_bands;
658 u8 adhoc_start_band;
659 u8 config_bands;
660 struct mwifiex_chan_scan_param_set *scan_channels;
661 u8 tx_lock_flag;
662 struct mwifiex_sleep_params sleep_params;
663 struct mwifiex_sleep_period sleep_period;
664 u16 ps_mode;
665 u32 ps_state;
666 u8 need_to_wakeup;
667 u16 multiple_dtim;
668 u16 local_listen_interval;
669 u16 null_pkt_interval;
670 struct sk_buff *sleep_cfm;
671 u16 bcn_miss_time_out;
672 u16 adhoc_awake_period;
673 u8 is_deep_sleep;
674 u8 delay_null_pkt;
675 u16 delay_to_ps;
676 u16 enhanced_ps_mode;
677 u8 pm_wakeup_card_req;
678 u16 gen_null_pkt;
679 u16 pps_uapsd_mode;
680 u32 pm_wakeup_fw_try;
681 u8 is_hs_configured;
682 struct mwifiex_hs_config_param hs_cfg;
683 u8 hs_activated;
684 u16 hs_activate_wait_q_woken;
685 wait_queue_head_t hs_activate_wait_q;
686 bool is_suspended;
687 u8 event_body[MAX_EVENT_SIZE];
688 u32 hw_dot_11n_dev_cap;
689 u8 hw_dev_mcs_support;
690 u32 usr_dot_11n_dev_cap;
691 u8 usr_dev_mcs_support;
692 u8 adhoc_11n_enabled;
693 u8 chan_offset;
694 struct mwifiex_dbg dbg;
695 u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
696 u32 arp_filter_size;
697};
698
699int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
700void mwifiex_free_lock_list(struct mwifiex_adapter *adapter);
701
702int mwifiex_init_fw(struct mwifiex_adapter *adapter);
703
704int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter);
705
706int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter);
707
708int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);
709
710int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
711
712int mwifiex_recv_complete(struct mwifiex_adapter *,
713 struct sk_buff *skb,
714 int status);
715
716int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
717
718int mwifiex_process_event(struct mwifiex_adapter *adapter);
719
720int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter,
721 struct mwifiex_wait_queue *ioctl_wq,
722 int status);
723
724int mwifiex_prepare_cmd(struct mwifiex_private *priv,
725 uint16_t cmd_no,
726 u16 cmd_action,
727 u32 cmd_oid,
728 void *wait_queue, void *data_buf);
729
730void mwifiex_cmd_timeout_func(unsigned long function_context);
731
732int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter,
733 struct mwifiex_wait_queue *wait_queue,
734 u32 func_init_shutdown);
735int mwifiex_get_debug_info(struct mwifiex_private *,
736 struct mwifiex_debug_info *);
737
738int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter);
739int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
740void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
741void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter,
742 struct mwifiex_wait_queue *ioctl_wq);
743
744void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
745 struct cmd_ctrl_node *cmd_node);
746
747void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
748 struct cmd_ctrl_node *cmd_node,
749 u32 addtail);
750
751int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter);
752int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter);
753int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
754 struct sk_buff *skb);
755int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
756 struct mwifiex_tx_param *tx_param);
757int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);
758int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
759 struct sk_buff *skb, int status);
760int mwifiex_recv_packet_complete(struct mwifiex_adapter *,
761 struct sk_buff *skb, int status);
762void mwifiex_clean_txrx(struct mwifiex_private *priv);
763u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);
764void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter);
765void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *,
766 u32);
767int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
768 struct host_cmd_ds_command *cmd,
769 u16 cmd_action, uint16_t ps_bitmap,
770 void *data_buf);
771int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
772 struct host_cmd_ds_command *resp,
773 void *data_buf);
774void mwifiex_process_hs_config(struct mwifiex_adapter *adapter);
775void mwifiex_hs_activated_event(struct mwifiex_private *priv,
776 u8 activated);
777int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
778 struct host_cmd_ds_command *resp);
779int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
780 struct sk_buff *skb);
781int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
782 u16 cmd_action, u32 cmd_oid,
783 void *data_buf, void *cmd_buf);
784int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
785 void *cmd_buf, void *ioctl);
786int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
787 struct sk_buff *skb);
788int mwifiex_process_sta_event(struct mwifiex_private *);
789void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
790int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
791int mwifiex_scan_networks(struct mwifiex_private *priv, void *wait_queue,
792 u16 action,
793 const struct mwifiex_user_scan_cfg
794 *user_scan_in, struct mwifiex_scan_resp *);
795int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv,
796 struct host_cmd_ds_command *cmd,
797 void *data_buf);
798void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
799 struct cmd_ctrl_node *cmd_node);
800int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
801 struct host_cmd_ds_command *resp,
802 void *wait_queue);
803s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
804 struct mwifiex_802_11_ssid *ssid, u8 *bssid,
805 u32 mode);
806s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
807 u32 mode);
808int mwifiex_find_best_network(struct mwifiex_private *priv,
809 struct mwifiex_ssid_bssid *req_ssid_bssid);
810s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
811 struct mwifiex_802_11_ssid *ssid2);
812int mwifiex_associate(struct mwifiex_private *priv, void *wait_queue,
813 struct mwifiex_bssdescriptor *bss_desc);
814int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
815 struct host_cmd_ds_command
816 *cmd, void *data_buf);
817int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
818 struct host_cmd_ds_command *resp,
819 void *wait_queue);
820void mwifiex_reset_connect_state(struct mwifiex_private *priv);
821void mwifiex_2040_coex_event(struct mwifiex_private *priv);
822u8 mwifiex_band_to_radio_type(u8 band);
823int mwifiex_deauthenticate(struct mwifiex_private *priv,
824 struct mwifiex_wait_queue *wait_queue,
825 u8 *mac);
826int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue,
827 struct mwifiex_802_11_ssid *adhoc_ssid);
828int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue,
829 struct mwifiex_bssdescriptor *bss_desc);
830int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
831 struct host_cmd_ds_command *cmd,
832 void *data_buf);
833int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
834 struct host_cmd_ds_command *cmd,
835 void *data_buf);
836int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
837 struct host_cmd_ds_command *resp,
838 void *wait_queue);
839int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv,
840 struct host_cmd_ds_command *cmd,
841 void *data_buf);
842struct mwifiex_chan_freq_power *
843 mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
844 struct mwifiex_private *priv,
845 u8 band, u16 channel);
846struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
847 struct mwifiex_private *priv,
848 u8 band, u32 freq);
849u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
850 u8 ht_info);
851u32 mwifiex_find_freq_from_band_chan(u8, u8);
852int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
853 u8 **buffer);
854u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
855 u8 ht_info);
856u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv,
857 u8 *rates);
858u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates);
859u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate);
860u8 mwifiex_is_rate_auto(struct mwifiex_private *priv);
861int mwifiex_get_rate_index(struct mwifiex_adapter *adapter,
862 u16 *rateBitmap, int size);
863extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE];
864void mwifiex_save_curr_bcn(struct mwifiex_private *priv);
865void mwifiex_free_curr_bcn(struct mwifiex_private *priv);
866int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
867 struct host_cmd_ds_command *cmd);
868int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
869 struct host_cmd_ds_command *resp);
870int is_command_pending(struct mwifiex_adapter *adapter);
871
872/*
873 * This function checks if the queuing is RA based or not.
874 */
875static inline u8
876mwifiex_queuing_ra_based(struct mwifiex_private *priv)
877{
878 /*
879 * Currently we assume if we are in Infra, then DA=RA. This might not be
880 * true in the future
881 */
882 if ((priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) &&
883 (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA))
884 return false;
885
886 return true;
887}
888
889/*
890 * This function copies rates.
891 */
892static inline u32
893mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len)
894{
895 int i;
896
897 for (i = 0; i < len && src[i]; i++, pos++) {
898 if (pos >= MWIFIEX_SUPPORTED_RATES)
899 break;
900 dest[pos] = src[i];
901 }
902
903 return pos;
904}
905
906/*
907 * This function returns the correct private structure pointer based
908 * upon the BSS type and BSS number.
909 */
910static inline struct mwifiex_private *
911mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter,
912 u32 bss_num, u32 bss_type)
913{
914 int i;
915
916 for (i = 0; i < adapter->priv_num; i++) {
917 if (adapter->priv[i]) {
918 if ((adapter->priv[i]->bss_num == bss_num)
919 && (adapter->priv[i]->bss_type == bss_type))
920 break;
921 }
922 }
923 return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
924}
925
926/*
927 * This function returns the first available private structure pointer
928 * based upon the BSS role.
929 */
930static inline struct mwifiex_private *
931mwifiex_get_priv(struct mwifiex_adapter *adapter,
932 enum mwifiex_bss_role bss_role)
933{
934 int i;
935
936 for (i = 0; i < adapter->priv_num; i++) {
937 if (adapter->priv[i]) {
938 if (bss_role == MWIFIEX_BSS_ROLE_ANY ||
939 GET_BSS_ROLE(adapter->priv[i]) == bss_role)
940 break;
941 }
942 }
943
944 return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
945}
946
947/*
948 * This function returns the driver private structure of a network device.
949 */
950static inline struct mwifiex_private *
951mwifiex_netdev_get_priv(struct net_device *dev)
952{
953 return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev));
954}
955
956struct mwifiex_wait_queue *mwifiex_alloc_fill_wait_queue(
957 struct mwifiex_private *,
958 u8 wait_option);
959struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
960 *adapter, u8 bss_index);
961int mwifiex_shutdown_fw(struct mwifiex_private *, u8);
962
963int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
964int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
965
966void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
967 int maxlen);
968int mwifiex_request_set_mac_address(struct mwifiex_private *priv);
969void mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
970 struct net_device *dev);
971int mwifiex_request_ioctl(struct mwifiex_private *priv,
972 struct mwifiex_wait_queue *req,
973 int, u8 wait_option);
974int mwifiex_disconnect(struct mwifiex_private *, u8, u8 *);
975int mwifiex_bss_start(struct mwifiex_private *priv,
976 u8 wait_option,
977 struct mwifiex_ssid_bssid *ssid_bssid);
978int mwifiex_set_hs_params(struct mwifiex_private *priv,
979 u16 action, u8 wait_option,
980 struct mwifiex_ds_hs_cfg *hscfg);
981int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option);
982int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
983void mwifiex_process_ioctl_resp(struct mwifiex_private *priv,
984 struct mwifiex_wait_queue *req);
985u32 mwifiex_get_mode(struct mwifiex_private *priv, u8 wait_option);
986int mwifiex_get_signal_info(struct mwifiex_private *priv,
987 u8 wait_option,
988 struct mwifiex_ds_get_signal *signal);
989int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
990 struct mwifiex_rate_cfg *rate);
991int mwifiex_get_channel_list(struct mwifiex_private *priv,
992 u8 wait_option,
993 struct mwifiex_chan_list *chanlist);
994int mwifiex_get_scan_table(struct mwifiex_private *priv,
995 u8 wait_option,
996 struct mwifiex_scan_resp *scanresp);
997int mwifiex_get_auth_mode(struct mwifiex_private *priv,
998 u8 wait_option, u32 *auth_mode);
999int mwifiex_get_encrypt_mode(struct mwifiex_private *priv,
1000 u8 wait_option,
1001 u32 *encrypt_mode);
1002int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option);
1003int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option,
1004 struct mwifiex_ssid_bssid *ssid_bssid);
1005int mwifiex_request_scan(struct mwifiex_private *priv,
1006 u8 wait_option,
1007 struct mwifiex_802_11_ssid *req_ssid);
1008int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
1009 struct mwifiex_user_scan_cfg *scan_req);
1010int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel);
1011int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
1012
1013int mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option);
1014
1015int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel);
1016
1017int mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode,
1018 int auth_mode, int wpa_enabled);
1019
1020int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
1021 int key_len, u8 key_index, int disable);
1022
1023int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
1024
1025int mwifiex_get_ver_ext(struct mwifiex_private *priv);
1026
1027int mwifiex_get_stats_info(struct mwifiex_private *priv,
1028 struct mwifiex_ds_get_stats *log);
1029
1030int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
1031 u32 reg_offset, u32 reg_value);
1032
1033int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
1034 u32 reg_offset, u32 *value);
1035
1036int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
1037 u8 *value);
1038
1039int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data);
1040
1041int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data);
1042
1043int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index);
1044
1045int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index);
1046
1047int mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on);
1048
1049int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter,
1050 char *version, int max_len);
1051
1052int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm);
1053
1054int mwifiex_main_process(struct mwifiex_adapter *);
1055
1056int mwifiex_bss_ioctl_mode(struct mwifiex_private *,
1057 struct mwifiex_wait_queue *,
1058 u16 action, int *mode);
1059int mwifiex_bss_ioctl_channel(struct mwifiex_private *,
1060 u16 action,
1061 struct mwifiex_chan_freq_power *cfp);
1062int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *,
1063 struct mwifiex_wait_queue *,
1064 struct mwifiex_ssid_bssid *);
1065int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *,
1066 u16 action,
1067 struct mwifiex_ds_band_cfg *);
1068int mwifiex_snmp_mib_ioctl(struct mwifiex_private *,
1069 struct mwifiex_wait_queue *,
1070 u32 cmd_oid, u16 action, u32 *value);
1071int mwifiex_get_bss_info(struct mwifiex_private *,
1072 struct mwifiex_bss_info *);
1073
1074#ifdef CONFIG_DEBUG_FS
1075void mwifiex_debugfs_init(void);
1076void mwifiex_debugfs_remove(void);
1077
1078void mwifiex_dev_debugfs_init(struct mwifiex_private *priv);
1079void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv);
1080#endif
1081#endif /* !_MWIFIEX_MAIN_H_ */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
new file mode 100644
index 000000000000..1152beb930ab
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -0,0 +1,3098 @@
1/*
2 * Marvell Wireless LAN device driver: scan ioctl and command handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "11n.h"
26#include "cfg80211.h"
27
28/* The maximum number of channels the firmware can scan per command */
29#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
30
31#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4
32
33/* Memory needed to store a max sized Channel List TLV for a firmware scan */
34#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \
35 + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \
36 *sizeof(struct mwifiex_chan_scan_param_set)))
37
38/* Memory needed to store supported rate */
39#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \
40 + HOSTCMD_SUPPORTED_RATES)
41
42/* Memory needed to store a max number/size WildCard SSID TLV for a firmware
43 scan */
44#define WILDCARD_SSID_TLV_MAX_SIZE \
45 (MWIFIEX_MAX_SSID_LIST_LENGTH * \
46 (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \
47 + IEEE80211_MAX_SSID_LEN))
48
49/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */
50#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \
51 + sizeof(struct mwifiex_ie_types_num_probes) \
52 + sizeof(struct mwifiex_ie_types_htcap) \
53 + CHAN_TLV_MAX_SIZE \
54 + RATE_TLV_MAX_SIZE \
55 + WILDCARD_SSID_TLV_MAX_SIZE)
56
57
58union mwifiex_scan_cmd_config_tlv {
59 /* Scan configuration (variable length) */
60 struct mwifiex_scan_cmd_config config;
61 /* Max allocated block */
62 u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
63};
64
65enum cipher_suite {
66 CIPHER_SUITE_TKIP,
67 CIPHER_SUITE_CCMP,
68 CIPHER_SUITE_MAX
69};
70static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = {
71 { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */
72 { 0x00, 0x50, 0xf2, 0x04 }, /* AES */
73};
74static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = {
75 { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */
76 { 0x00, 0x0f, 0xac, 0x04 }, /* AES */
77};
78
79/*
80 * This function parses a given IE for a given OUI.
81 *
82 * This is used to parse a WPA/RSN IE to find if it has
83 * a given oui in PTK.
84 */
85static u8
86mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
87{
88 u8 count;
89
90 count = iebody->ptk_cnt[0];
91
92 /* There could be multiple OUIs for PTK hence
93 1) Take the length.
94 2) Check all the OUIs for AES.
95 3) If one of them is AES then pass success. */
96 while (count) {
97 if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body)))
98 return MWIFIEX_OUI_PRESENT;
99
100 --count;
101 if (count)
102 iebody = (struct ie_body *) ((u8 *) iebody +
103 sizeof(iebody->ptk_body));
104 }
105
106 pr_debug("info: %s: OUI is not found in PTK\n", __func__);
107 return MWIFIEX_OUI_NOT_PRESENT;
108}
109
110/*
111 * This function checks if a given OUI is present in a RSN IE.
112 *
113 * The function first checks if a RSN IE is present or not in the
114 * BSS descriptor. It tries to locate the OUI only if such an IE is
115 * present.
116 */
117static u8
118mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
119{
120 u8 *oui = NULL;
121 struct ie_body *iebody = NULL;
122 u8 ret = MWIFIEX_OUI_NOT_PRESENT;
123
124 if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).
125 ieee_hdr.element_id == WLAN_EID_RSN))) {
126 iebody = (struct ie_body *)
127 (((u8 *) bss_desc->bcn_rsn_ie->data) +
128 RSN_GTK_OUI_OFFSET);
129 oui = &mwifiex_rsn_oui[cipher][0];
130 ret = mwifiex_search_oui_in_ie(iebody, oui);
131 if (ret)
132 return ret;
133 }
134 return ret;
135}
136
137/*
138 * This function checks if a given OUI is present in a WPA IE.
139 *
140 * The function first checks if a WPA IE is present or not in the
141 * BSS descriptor. It tries to locate the OUI only if such an IE is
142 * present.
143 */
144static u8
145mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
146{
147 u8 *oui = NULL;
148 struct ie_body *iebody = NULL;
149 u8 ret = MWIFIEX_OUI_NOT_PRESENT;
150
151 if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).
152 vend_hdr.element_id == WLAN_EID_WPA))) {
153 iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
154 oui = &mwifiex_wpa_oui[cipher][0];
155 ret = mwifiex_search_oui_in_ie(iebody, oui);
156 if (ret)
157 return ret;
158 }
159 return ret;
160}
161
162/*
163 * This function compares two SSIDs and checks if they match.
164 */
165s32
166mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
167 struct mwifiex_802_11_ssid *ssid2)
168{
169 if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
170 return -1;
171 return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
172}
173
174/*
175 * Sends IOCTL request to get the best BSS.
176 *
177 * This function allocates the IOCTL request buffer, fills it
178 * with requisite parameters and calls the IOCTL handler.
179 */
180int mwifiex_find_best_bss(struct mwifiex_private *priv,
181 u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid)
182{
183 struct mwifiex_wait_queue *wait = NULL;
184 struct mwifiex_ssid_bssid tmp_ssid_bssid;
185 int ret = 0;
186 u8 *mac = NULL;
187
188 if (!ssid_bssid)
189 return -1;
190
191 /* Allocate wait request buffer */
192 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
193 if (!wait)
194 return -ENOMEM;
195
196 memcpy(&tmp_ssid_bssid, ssid_bssid,
197 sizeof(struct mwifiex_ssid_bssid));
198 ret = mwifiex_bss_ioctl_find_bss(priv, wait, &tmp_ssid_bssid);
199
200 if (!ret) {
201 memcpy(ssid_bssid, &tmp_ssid_bssid,
202 sizeof(struct mwifiex_ssid_bssid));
203 mac = (u8 *) &ssid_bssid->bssid;
204 dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
205 " %pM\n", ssid_bssid->ssid.ssid, mac);
206 }
207
208 kfree(wait);
209 return ret;
210}
211
212/*
213 * Sends IOCTL request to start a scan with user configurations.
214 *
215 * This function allocates the IOCTL request buffer, fills it
216 * with requisite parameters and calls the IOCTL handler.
217 *
218 * Upon completion, it also generates a wireless event to notify
219 * applications.
220 */
221int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
222 struct mwifiex_user_scan_cfg *scan_req)
223{
224 struct mwifiex_wait_queue *wait = NULL;
225 int status = 0;
226 u8 wait_option = MWIFIEX_IOCTL_WAIT;
227
228 /* Allocate an IOCTL request buffer */
229 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
230 if (!wait)
231 return -ENOMEM;
232
233 status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET,
234 scan_req, NULL);
235
236 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
237
238 if (wait && (status != -EINPROGRESS))
239 kfree(wait);
240 return status;
241}
242
243/*
244 * This function checks if wapi is enabled in driver and scanned network is
245 * compatible with it.
246 */
247static bool
248mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv,
249 struct mwifiex_bssdescriptor *bss_desc)
250{
251 if (priv->sec_info.wapi_enabled &&
252 (bss_desc->bcn_wapi_ie &&
253 ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id ==
254 WLAN_EID_BSS_AC_ACCESS_DELAY))) {
255 return true;
256 }
257 return false;
258}
259
260/*
261 * This function checks if driver is configured with no security mode and
262 * scanned network is compatible with it.
263 */
264static bool
265mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
266 struct mwifiex_bssdescriptor *bss_desc)
267{
268 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
269 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
270 && ((!bss_desc->bcn_wpa_ie) ||
271 ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
272 WLAN_EID_WPA))
273 && ((!bss_desc->bcn_rsn_ie) ||
274 ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
275 WLAN_EID_RSN))
276 && priv->sec_info.encryption_mode ==
277 MWIFIEX_ENCRYPTION_MODE_NONE && !bss_desc->privacy) {
278 return true;
279 }
280 return false;
281}
282
283/*
284 * This function checks if static WEP is enabled in driver and scanned network
285 * is compatible with it.
286 */
287static bool
288mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
289 struct mwifiex_bssdescriptor *bss_desc)
290{
291 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
292 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
293 && bss_desc->privacy) {
294 return true;
295 }
296 return false;
297}
298
299/*
300 * This function checks if wpa is enabled in driver and scanned network is
301 * compatible with it.
302 */
303static bool
304mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
305 struct mwifiex_bssdescriptor *bss_desc,
306 int index)
307{
308 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
309 && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
310 && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
311 element_id == WLAN_EID_WPA))
312 /*
313 * Privacy bit may NOT be set in some APs like
314 * LinkSys WRT54G && bss_desc->privacy
315 */
316 ) {
317 dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
318 " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
319 "EncMode=%#x privacy=%#x\n", __func__, index,
320 (bss_desc->bcn_wpa_ie) ?
321 (*(bss_desc->bcn_wpa_ie)).
322 vend_hdr.element_id : 0,
323 (bss_desc->bcn_rsn_ie) ?
324 (*(bss_desc->bcn_rsn_ie)).
325 ieee_hdr.element_id : 0,
326 (priv->sec_info.wep_status ==
327 MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
328 (priv->sec_info.wpa_enabled) ? "e" : "d",
329 (priv->sec_info.wpa2_enabled) ? "e" : "d",
330 priv->sec_info.encryption_mode,
331 bss_desc->privacy);
332 return true;
333 }
334 return false;
335}
336
337/*
338 * This function checks if wpa2 is enabled in driver and scanned network is
339 * compatible with it.
340 */
341static bool
342mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
343 struct mwifiex_bssdescriptor *bss_desc,
344 int index)
345{
346 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
347 && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
348 && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
349 element_id == WLAN_EID_RSN))
350 /*
351 * Privacy bit may NOT be set in some APs like
352 * LinkSys WRT54G && bss_desc->privacy
353 */
354 ) {
355 dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
356 " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
357 "EncMode=%#x privacy=%#x\n", __func__, index,
358 (bss_desc->bcn_wpa_ie) ?
359 (*(bss_desc->bcn_wpa_ie)).
360 vend_hdr.element_id : 0,
361 (bss_desc->bcn_rsn_ie) ?
362 (*(bss_desc->bcn_rsn_ie)).
363 ieee_hdr.element_id : 0,
364 (priv->sec_info.wep_status ==
365 MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
366 (priv->sec_info.wpa_enabled) ? "e" : "d",
367 (priv->sec_info.wpa2_enabled) ? "e" : "d",
368 priv->sec_info.encryption_mode,
369 bss_desc->privacy);
370 return true;
371 }
372 return false;
373}
374
375/*
376 * This function checks if adhoc AES is enabled in driver and scanned network is
377 * compatible with it.
378 */
379static bool
380mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
381 struct mwifiex_bssdescriptor *bss_desc)
382{
383 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
384 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
385 && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
386 element_id != WLAN_EID_WPA))
387 && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
388 element_id != WLAN_EID_RSN))
389 && priv->sec_info.encryption_mode ==
390 MWIFIEX_ENCRYPTION_MODE_NONE && bss_desc->privacy) {
391 return true;
392 }
393 return false;
394}
395
396/*
397 * This function checks if dynamic WEP is enabled in driver and scanned network
398 * is compatible with it.
399 */
400static bool
401mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
402 struct mwifiex_bssdescriptor *bss_desc,
403 int index)
404{
405 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
406 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
407 && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
408 element_id != WLAN_EID_WPA))
409 && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
410 element_id != WLAN_EID_RSN))
411 && priv->sec_info.encryption_mode !=
412 MWIFIEX_ENCRYPTION_MODE_NONE && bss_desc->privacy) {
413 dev_dbg(priv->adapter->dev, "info: %s: dynamic "
414 "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x "
415 "EncMode=%#x privacy=%#x\n",
416 __func__, index,
417 (bss_desc->bcn_wpa_ie) ?
418 (*(bss_desc->bcn_wpa_ie)).
419 vend_hdr.element_id : 0,
420 (bss_desc->bcn_rsn_ie) ?
421 (*(bss_desc->bcn_rsn_ie)).
422 ieee_hdr.element_id : 0,
423 priv->sec_info.encryption_mode,
424 bss_desc->privacy);
425 return true;
426 }
427 return false;
428}
429
430/*
431 * This function checks if a scanned network is compatible with the driver
432 * settings.
433 *
434 * WEP WPA WPA2 ad-hoc encrypt Network
435 * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
436 * 0 0 0 0 NONE 0 0 0 yes No security
437 * 0 1 0 0 x 1x 1 x yes WPA (disable
438 * HT if no AES)
439 * 0 0 1 0 x 1x x 1 yes WPA2 (disable
440 * HT if no AES)
441 * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
442 * 1 0 0 0 NONE 1 0 0 yes Static WEP
443 * (disable HT)
444 * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
445 *
446 * Compatibility is not matched while roaming, except for mode.
447 */
448static s32
449mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
450{
451 struct mwifiex_adapter *adapter = priv->adapter;
452 struct mwifiex_bssdescriptor *bss_desc;
453
454 bss_desc = &adapter->scan_table[index];
455 bss_desc->disable_11n = false;
456
457 /* Don't check for compatibility if roaming */
458 if (priv->media_connected && (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA)
459 && (bss_desc->bss_mode == MWIFIEX_BSS_MODE_INFRA))
460 return index;
461
462 if (priv->wps.session_enable) {
463 dev_dbg(adapter->dev,
464 "info: return success directly in WPS period\n");
465 return index;
466 }
467
468 if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
469 dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
470 return index;
471 }
472
473 if (bss_desc->bss_mode == mode) {
474 if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
475 /* No security */
476 return index;
477 } else if (mwifiex_is_network_compatible_for_static_wep(priv,
478 bss_desc)) {
479 /* Static WEP enabled */
480 dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
481 bss_desc->disable_11n = true;
482 return index;
483 } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc,
484 index)) {
485 /* WPA enabled */
486 if (((priv->adapter->config_bands & BAND_GN
487 || priv->adapter->config_bands & BAND_AN)
488 && bss_desc->bcn_ht_cap)
489 && !mwifiex_is_wpa_oui_present(bss_desc,
490 CIPHER_SUITE_CCMP)) {
491
492 if (mwifiex_is_wpa_oui_present(bss_desc,
493 CIPHER_SUITE_TKIP)) {
494 dev_dbg(adapter->dev,
495 "info: Disable 11n if AES "
496 "is not supported by AP\n");
497 bss_desc->disable_11n = true;
498 } else {
499 return -1;
500 }
501 }
502 return index;
503 } else if (mwifiex_is_network_compatible_for_wpa2(priv,
504 bss_desc, index)) {
505 /* WPA2 enabled */
506 if (((priv->adapter->config_bands & BAND_GN
507 || priv->adapter->config_bands & BAND_AN)
508 && bss_desc->bcn_ht_cap)
509 && !mwifiex_is_rsn_oui_present(bss_desc,
510 CIPHER_SUITE_CCMP)) {
511
512 if (mwifiex_is_rsn_oui_present(bss_desc,
513 CIPHER_SUITE_TKIP)) {
514 dev_dbg(adapter->dev,
515 "info: Disable 11n if AES "
516 "is not supported by AP\n");
517 bss_desc->disable_11n = true;
518 } else {
519 return -1;
520 }
521 }
522 return index;
523 } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
524 bss_desc)) {
525 /* Ad-hoc AES enabled */
526 return index;
527 } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
528 bss_desc, index)) {
529 /* Dynamic WEP enabled */
530 return index;
531 }
532
533 /* Security doesn't match */
534 dev_dbg(adapter->dev, "info: %s: failed: index=%d "
535 "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
536 "=%#x privacy=%#x\n",
537 __func__, index,
538 (bss_desc->bcn_wpa_ie) ?
539 (*(bss_desc->bcn_wpa_ie)).vend_hdr.
540 element_id : 0,
541 (bss_desc->bcn_rsn_ie) ?
542 (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
543 element_id : 0,
544 (priv->sec_info.wep_status ==
545 MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
546 (priv->sec_info.wpa_enabled) ? "e" : "d",
547 (priv->sec_info.wpa2_enabled) ? "e" : "d",
548 priv->sec_info.encryption_mode, bss_desc->privacy);
549 return -1;
550 }
551
552 /* Mode doesn't match */
553 return -1;
554}
555
556/*
557 * This function finds the best SSID in the scan list.
558 *
559 * It searches the scan table for the best SSID that also matches the current
560 * adapter network preference (mode, security etc.).
561 */
562static s32
563mwifiex_find_best_network_in_list(struct mwifiex_private *priv)
564{
565 struct mwifiex_adapter *adapter = priv->adapter;
566 u32 mode = priv->bss_mode;
567 s32 best_net = -1;
568 s32 best_rssi = 0;
569 u32 i;
570
571 dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n",
572 adapter->num_in_scan_table);
573
574 for (i = 0; i < adapter->num_in_scan_table; i++) {
575 switch (mode) {
576 case MWIFIEX_BSS_MODE_INFRA:
577 case MWIFIEX_BSS_MODE_IBSS:
578 if (mwifiex_is_network_compatible(priv, i, mode) >= 0) {
579 if (SCAN_RSSI(adapter->scan_table[i].rssi) >
580 best_rssi) {
581 best_rssi = SCAN_RSSI(adapter->
582 scan_table[i].rssi);
583 best_net = i;
584 }
585 }
586 break;
587 case MWIFIEX_BSS_MODE_AUTO:
588 default:
589 if (SCAN_RSSI(adapter->scan_table[i].rssi) >
590 best_rssi) {
591 best_rssi = SCAN_RSSI(adapter->scan_table[i].
592 rssi);
593 best_net = i;
594 }
595 break;
596 }
597 }
598
599 return best_net;
600}
601
602/*
603 * This function creates a channel list for the driver to scan, based
604 * on region/band information.
605 *
606 * This routine is used for any scan that is not provided with a
607 * specific channel list to scan.
608 */
609static void
610mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
611 const struct mwifiex_user_scan_cfg
612 *user_scan_in,
613 struct mwifiex_chan_scan_param_set
614 *scan_chan_list,
615 u8 filtered_scan)
616{
617 enum ieee80211_band band;
618 struct ieee80211_supported_band *sband;
619 struct ieee80211_channel *ch;
620 struct mwifiex_adapter *adapter = priv->adapter;
621 int chan_idx = 0, i;
622 u8 scan_type;
623
624 for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
625
626 if (!priv->wdev->wiphy->bands[band])
627 continue;
628
629 sband = priv->wdev->wiphy->bands[band];
630
631 for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
632 ch = &sband->channels[i];
633 if (ch->flags & IEEE80211_CHAN_DISABLED)
634 continue;
635 scan_chan_list[chan_idx].radio_type = band;
636 scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN;
637 if (user_scan_in &&
638 user_scan_in->chan_list[0].scan_time)
639 scan_chan_list[chan_idx].max_scan_time =
640 cpu_to_le16((u16) user_scan_in->
641 chan_list[0].scan_time);
642 else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
643 scan_chan_list[chan_idx].max_scan_time =
644 cpu_to_le16(adapter->passive_scan_time);
645 else
646 scan_chan_list[chan_idx].max_scan_time =
647 cpu_to_le16(adapter->active_scan_time);
648 if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
649 scan_chan_list[chan_idx].chan_scan_mode_bitmap
650 |= MWIFIEX_PASSIVE_SCAN;
651 else
652 scan_chan_list[chan_idx].chan_scan_mode_bitmap
653 &= ~MWIFIEX_PASSIVE_SCAN;
654 scan_chan_list[chan_idx].chan_number =
655 (u32) ch->hw_value;
656 if (filtered_scan) {
657 scan_chan_list[chan_idx].max_scan_time =
658 cpu_to_le16(adapter->specific_scan_time);
659 scan_chan_list[chan_idx].chan_scan_mode_bitmap
660 |= MWIFIEX_DISABLE_CHAN_FILT;
661 }
662 }
663
664 }
665}
666
667/*
668 * This function constructs and sends multiple scan config commands to
669 * the firmware.
670 *
671 * Previous routines in the code flow have created a scan command configuration
672 * with any requested TLVs. This function splits the channel TLV into maximum
673 * channels supported per scan lists and sends the portion of the channel TLV,
674 * along with the other TLVs, to the firmware.
675 */
676static int
677mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf,
678 u32 max_chan_per_scan, u8 filtered_scan,
679 struct mwifiex_scan_cmd_config *scan_cfg_out,
680 struct mwifiex_ie_types_chan_list_param_set
681 *chan_tlv_out,
682 struct mwifiex_chan_scan_param_set *scan_chan_list)
683{
684 int ret = 0;
685 struct mwifiex_chan_scan_param_set *tmp_chan_list;
686 struct mwifiex_chan_scan_param_set *start_chan;
687
688 u32 tlv_idx;
689 u32 total_scan_time;
690 u32 done_early;
691
692 if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
693 dev_dbg(priv->adapter->dev,
694 "info: Scan: Null detect: %p, %p, %p\n",
695 scan_cfg_out, chan_tlv_out, scan_chan_list);
696 return -1;
697 }
698
699 chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
700
701 /* Set the temp channel struct pointer to the start of the desired
702 list */
703 tmp_chan_list = scan_chan_list;
704
705 /* Loop through the desired channel list, sending a new firmware scan
706 commands for each max_chan_per_scan channels (or for 1,6,11
707 individually if configured accordingly) */
708 while (tmp_chan_list->chan_number) {
709
710 tlv_idx = 0;
711 total_scan_time = 0;
712 chan_tlv_out->header.len = 0;
713 start_chan = tmp_chan_list;
714 done_early = false;
715
716 /*
717 * Construct the Channel TLV for the scan command. Continue to
718 * insert channel TLVs until:
719 * - the tlv_idx hits the maximum configured per scan command
720 * - the next channel to insert is 0 (end of desired channel
721 * list)
722 * - done_early is set (controlling individual scanning of
723 * 1,6,11)
724 */
725 while (tlv_idx < max_chan_per_scan
726 && tmp_chan_list->chan_number && !done_early) {
727
728 dev_dbg(priv->adapter->dev,
729 "info: Scan: Chan(%3d), Radio(%d),"
730 " Mode(%d, %d), Dur(%d)\n",
731 tmp_chan_list->chan_number,
732 tmp_chan_list->radio_type,
733 tmp_chan_list->chan_scan_mode_bitmap
734 & MWIFIEX_PASSIVE_SCAN,
735 (tmp_chan_list->chan_scan_mode_bitmap
736 & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
737 le16_to_cpu(tmp_chan_list->max_scan_time));
738
739 /* Copy the current channel TLV to the command being
740 prepared */
741 memcpy(chan_tlv_out->chan_scan_param + tlv_idx,
742 tmp_chan_list,
743 sizeof(chan_tlv_out->chan_scan_param));
744
745 /* Increment the TLV header length by the size
746 appended */
747 chan_tlv_out->header.len =
748 cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) +
749 (sizeof(chan_tlv_out->chan_scan_param)));
750
751 /*
752 * The tlv buffer length is set to the number of bytes
753 * of the between the channel tlv pointer and the start
754 * of the tlv buffer. This compensates for any TLVs
755 * that were appended before the channel list.
756 */
757 scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out -
758 scan_cfg_out->tlv_buf);
759
760 /* Add the size of the channel tlv header and the data
761 length */
762 scan_cfg_out->tlv_buf_len +=
763 (sizeof(chan_tlv_out->header)
764 + le16_to_cpu(chan_tlv_out->header.len));
765
766 /* Increment the index to the channel tlv we are
767 constructing */
768 tlv_idx++;
769
770 /* Count the total scan time per command */
771 total_scan_time +=
772 le16_to_cpu(tmp_chan_list->max_scan_time);
773
774 done_early = false;
775
776 /* Stop the loop if the *current* channel is in the
777 1,6,11 set and we are not filtering on a BSSID
778 or SSID. */
779 if (!filtered_scan && (tmp_chan_list->chan_number == 1
780 || tmp_chan_list->chan_number == 6
781 || tmp_chan_list->chan_number == 11))
782 done_early = true;
783
784 /* Increment the tmp pointer to the next channel to
785 be scanned */
786 tmp_chan_list++;
787
788 /* Stop the loop if the *next* channel is in the 1,6,11
789 set. This will cause it to be the only channel
790 scanned on the next interation */
791 if (!filtered_scan && (tmp_chan_list->chan_number == 1
792 || tmp_chan_list->chan_number == 6
793 || tmp_chan_list->chan_number == 11))
794 done_early = true;
795 }
796
797 /* The total scan time should be less than scan command timeout
798 value */
799 if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
800 dev_err(priv->adapter->dev, "total scan time %dms"
801 " is over limit (%dms), scan skipped\n",
802 total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
803 ret = -1;
804 break;
805 }
806
807 priv->adapter->scan_channels = start_chan;
808
809 /* Send the scan command to the firmware with the specified
810 cfg */
811 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN,
812 HostCmd_ACT_GEN_SET,
813 0, wait_buf, scan_cfg_out);
814 if (ret)
815 break;
816 }
817
818 if (ret)
819 return -1;
820
821 return 0;
822}
823
824/*
825 * This function constructs a scan command configuration structure to use
826 * in scan commands.
827 *
828 * Application layer or other functions can invoke network scanning
829 * with a scan configuration supplied in a user scan configuration structure.
830 * This structure is used as the basis of one or many scan command configuration
831 * commands that are sent to the command processing module and eventually to the
832 * firmware.
833 *
834 * This function creates a scan command configuration structure based on the
835 * following user supplied parameters (if present):
836 * - SSID filter
837 * - BSSID filter
838 * - Number of Probes to be sent
839 * - Channel list
840 *
841 * If the SSID or BSSID filter is not present, the filter is disabled/cleared.
842 * If the number of probes is not set, adapter default setting is used.
843 */
844static void
845mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
846 const struct mwifiex_user_scan_cfg *user_scan_in,
847 struct mwifiex_scan_cmd_config *scan_cfg_out,
848 struct mwifiex_ie_types_chan_list_param_set
849 **chan_list_out,
850 struct mwifiex_chan_scan_param_set
851 *scan_chan_list,
852 u8 *max_chan_per_scan, u8 *filtered_scan,
853 u8 *scan_current_only)
854{
855 struct mwifiex_adapter *adapter = priv->adapter;
856 struct mwifiex_ie_types_num_probes *num_probes_tlv;
857 struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
858 struct mwifiex_ie_types_rates_param_set *rates_tlv;
859 const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
860 u8 *tlv_pos;
861 u32 num_probes;
862 u32 ssid_len;
863 u32 chan_idx;
864 u32 scan_type;
865 u16 scan_dur;
866 u8 channel;
867 u8 radio_type;
868 u32 ssid_idx;
869 u8 ssid_filter;
870 u8 rates[MWIFIEX_SUPPORTED_RATES];
871 u32 rates_size;
872 struct mwifiex_ie_types_htcap *ht_cap;
873
874 /* The tlv_buf_len is calculated for each scan command. The TLVs added
875 in this routine will be preserved since the routine that sends the
876 command will append channelTLVs at *chan_list_out. The difference
877 between the *chan_list_out and the tlv_buf start will be used to
878 calculate the size of anything we add in this routine. */
879 scan_cfg_out->tlv_buf_len = 0;
880
881 /* Running tlv pointer. Assigned to chan_list_out at end of function
882 so later routines know where channels can be added to the command
883 buf */
884 tlv_pos = scan_cfg_out->tlv_buf;
885
886 /* Initialize the scan as un-filtered; the flag is later set to TRUE
887 below if a SSID or BSSID filter is sent in the command */
888 *filtered_scan = false;
889
890 /* Initialize the scan as not being only on the current channel. If
891 the channel list is customized, only contains one channel, and is
892 the active channel, this is set true and data flow is not halted. */
893 *scan_current_only = false;
894
895 if (user_scan_in) {
896
897 /* Default the ssid_filter flag to TRUE, set false under
898 certain wildcard conditions and qualified by the existence
899 of an SSID list before marking the scan as filtered */
900 ssid_filter = true;
901
902 /* Set the BSS type scan filter, use Adapter setting if
903 unset */
904 scan_cfg_out->bss_mode =
905 (user_scan_in->bss_mode ? (u8) user_scan_in->
906 bss_mode : (u8) adapter->scan_mode);
907
908 /* Set the number of probes to send, use Adapter setting
909 if unset */
910 num_probes =
911 (user_scan_in->num_probes ? user_scan_in->
912 num_probes : adapter->scan_probes);
913
914 /*
915 * Set the BSSID filter to the incoming configuration,
916 * if non-zero. If not set, it will remain disabled
917 * (all zeros).
918 */
919 memcpy(scan_cfg_out->specific_bssid,
920 user_scan_in->specific_bssid,
921 sizeof(scan_cfg_out->specific_bssid));
922
923 for (ssid_idx = 0;
924 ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list))
925 && (*user_scan_in->ssid_list[ssid_idx].ssid
926 || user_scan_in->ssid_list[ssid_idx].max_len));
927 ssid_idx++) {
928
929 ssid_len = strlen(user_scan_in->ssid_list[ssid_idx].
930 ssid) + 1;
931
932 wildcard_ssid_tlv =
933 (struct mwifiex_ie_types_wildcard_ssid_params *)
934 tlv_pos;
935 wildcard_ssid_tlv->header.type =
936 cpu_to_le16(TLV_TYPE_WILDCARDSSID);
937 wildcard_ssid_tlv->header.len = cpu_to_le16(
938 (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
939 max_ssid_length)));
940 wildcard_ssid_tlv->max_ssid_length =
941 user_scan_in->ssid_list[ssid_idx].max_len;
942
943 memcpy(wildcard_ssid_tlv->ssid,
944 user_scan_in->ssid_list[ssid_idx].ssid,
945 ssid_len);
946
947 tlv_pos += (sizeof(wildcard_ssid_tlv->header)
948 + le16_to_cpu(wildcard_ssid_tlv->header.len));
949
950 dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n",
951 ssid_idx, wildcard_ssid_tlv->ssid,
952 wildcard_ssid_tlv->max_ssid_length);
953
954 /* Empty wildcard ssid with a maxlen will match many or
955 potentially all SSIDs (maxlen == 32), therefore do
956 not treat the scan as
957 filtered. */
958 if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
959 ssid_filter = false;
960
961 }
962
963 /*
964 * The default number of channels sent in the command is low to
965 * ensure the response buffer from the firmware does not
966 * truncate scan results. That is not an issue with an SSID
967 * or BSSID filter applied to the scan results in the firmware.
968 */
969 if ((ssid_idx && ssid_filter)
970 || memcmp(scan_cfg_out->specific_bssid, &zero_mac,
971 sizeof(zero_mac)))
972 *filtered_scan = true;
973 } else {
974 scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
975 num_probes = adapter->scan_probes;
976 }
977
978 /*
979 * If a specific BSSID or SSID is used, the number of channels in the
980 * scan command will be increased to the absolute maximum.
981 */
982 if (*filtered_scan)
983 *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
984 else
985 *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
986
987 /* If the input config or adapter has the number of Probes set,
988 add tlv */
989 if (num_probes) {
990
991 dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
992 num_probes);
993
994 num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
995 num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
996 num_probes_tlv->header.len =
997 cpu_to_le16(sizeof(num_probes_tlv->num_probes));
998 num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes);
999
1000 tlv_pos += sizeof(num_probes_tlv->header) +
1001 le16_to_cpu(num_probes_tlv->header.len);
1002
1003 }
1004
1005 /* Append rates tlv */
1006 memset(rates, 0, sizeof(rates));
1007
1008 rates_size = mwifiex_get_supported_rates(priv, rates);
1009
1010 rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos;
1011 rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
1012 rates_tlv->header.len = cpu_to_le16((u16) rates_size);
1013 memcpy(rates_tlv->rates, rates, rates_size);
1014 tlv_pos += sizeof(rates_tlv->header) + rates_size;
1015
1016 dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size);
1017
1018 if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
1019 && (priv->adapter->config_bands & BAND_GN
1020 || priv->adapter->config_bands & BAND_AN)) {
1021 ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos;
1022 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
1023 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1024 ht_cap->header.len =
1025 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1026 mwifiex_fill_cap_info(priv, ht_cap);
1027 tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
1028 }
1029
1030 /* Append vendor specific IE TLV */
1031 mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos);
1032
1033 /*
1034 * Set the output for the channel TLV to the address in the tlv buffer
1035 * past any TLVs that were added in this function (SSID, num_probes).
1036 * Channel TLVs will be added past this for each scan command,
1037 * preserving the TLVs that were previously added.
1038 */
1039 *chan_list_out =
1040 (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos;
1041
1042 if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
1043
1044 dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
1045
1046 for (chan_idx = 0;
1047 chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX
1048 && user_scan_in->chan_list[chan_idx].chan_number;
1049 chan_idx++) {
1050
1051 channel = user_scan_in->chan_list[chan_idx].chan_number;
1052 (scan_chan_list + chan_idx)->chan_number = channel;
1053
1054 radio_type =
1055 user_scan_in->chan_list[chan_idx].radio_type;
1056 (scan_chan_list + chan_idx)->radio_type = radio_type;
1057
1058 scan_type = user_scan_in->chan_list[chan_idx].scan_type;
1059
1060 if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1061 (scan_chan_list +
1062 chan_idx)->chan_scan_mode_bitmap
1063 |= MWIFIEX_PASSIVE_SCAN;
1064 else
1065 (scan_chan_list +
1066 chan_idx)->chan_scan_mode_bitmap
1067 &= ~MWIFIEX_PASSIVE_SCAN;
1068
1069 if (user_scan_in->chan_list[chan_idx].scan_time) {
1070 scan_dur = (u16) user_scan_in->
1071 chan_list[chan_idx].scan_time;
1072 } else {
1073 if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1074 scan_dur = adapter->passive_scan_time;
1075 else if (*filtered_scan)
1076 scan_dur = adapter->specific_scan_time;
1077 else
1078 scan_dur = adapter->active_scan_time;
1079 }
1080
1081 (scan_chan_list + chan_idx)->min_scan_time =
1082 cpu_to_le16(scan_dur);
1083 (scan_chan_list + chan_idx)->max_scan_time =
1084 cpu_to_le16(scan_dur);
1085 }
1086
1087 /* Check if we are only scanning the current channel */
1088 if ((chan_idx == 1)
1089 && (user_scan_in->chan_list[0].chan_number
1090 == priv->curr_bss_params.bss_descriptor.channel)) {
1091 *scan_current_only = true;
1092 dev_dbg(adapter->dev,
1093 "info: Scan: Scanning current channel only\n");
1094 }
1095
1096 } else {
1097 dev_dbg(adapter->dev,
1098 "info: Scan: Creating full region channel list\n");
1099 mwifiex_scan_create_channel_list(priv, user_scan_in,
1100 scan_chan_list,
1101 *filtered_scan);
1102 }
1103}
1104
1105/*
1106 * This function inspects the scan response buffer for pointers to
1107 * expected TLVs.
1108 *
1109 * TLVs can be included at the end of the scan response BSS information.
1110 *
1111 * Data in the buffer is parsed pointers to TLVs that can potentially
1112 * be passed back in the response.
1113 */
1114static void
1115mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
1116 struct mwifiex_ie_types_data *tlv,
1117 u32 tlv_buf_size, u32 req_tlv_type,
1118 struct mwifiex_ie_types_data **tlv_data)
1119{
1120 struct mwifiex_ie_types_data *current_tlv;
1121 u32 tlv_buf_left;
1122 u32 tlv_type;
1123 u32 tlv_len;
1124
1125 current_tlv = tlv;
1126 tlv_buf_left = tlv_buf_size;
1127 *tlv_data = NULL;
1128
1129 dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
1130 tlv_buf_size);
1131
1132 while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
1133
1134 tlv_type = le16_to_cpu(current_tlv->header.type);
1135 tlv_len = le16_to_cpu(current_tlv->header.len);
1136
1137 if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
1138 dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
1139 break;
1140 }
1141
1142 if (req_tlv_type == tlv_type) {
1143 switch (tlv_type) {
1144 case TLV_TYPE_TSFTIMESTAMP:
1145 dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
1146 "timestamp TLV, len = %d\n", tlv_len);
1147 *tlv_data = (struct mwifiex_ie_types_data *)
1148 current_tlv;
1149 break;
1150 case TLV_TYPE_CHANNELBANDLIST:
1151 dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
1152 " band list TLV, len = %d\n", tlv_len);
1153 *tlv_data = (struct mwifiex_ie_types_data *)
1154 current_tlv;
1155 break;
1156 default:
1157 dev_err(adapter->dev,
1158 "SCAN_RESP: unhandled TLV = %d\n",
1159 tlv_type);
1160 /* Give up, this seems corrupted */
1161 return;
1162 }
1163 }
1164
1165 if (*tlv_data)
1166 break;
1167
1168
1169 tlv_buf_left -= (sizeof(tlv->header) + tlv_len);
1170 current_tlv =
1171 (struct mwifiex_ie_types_data *) (current_tlv->data +
1172 tlv_len);
1173
1174 } /* while */
1175}
1176
1177/*
1178 * This function interprets a BSS scan response returned from the firmware.
1179 *
1180 * The various fixed fields and IEs are parsed and passed back for a BSS
1181 * probe response or beacon from scan command. Information is recorded as
1182 * needed in the scan table for that entry.
1183 *
1184 * The following IE types are recognized and parsed -
1185 * - SSID
1186 * - Supported rates
1187 * - FH parameters set
1188 * - DS parameters set
1189 * - CF parameters set
1190 * - IBSS parameters set
1191 * - ERP information
1192 * - Extended supported rates
1193 * - Vendor specific (221)
1194 * - RSN IE
1195 * - WAPI IE
1196 * - HT capability
1197 * - HT operation
1198 * - BSS Coexistence 20/40
1199 * - Extended capability
1200 * - Overlapping BSS scan parameters
1201 */
1202static int
1203mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
1204 struct mwifiex_bssdescriptor *bss_entry,
1205 u8 **beacon_info, u32 *bytes_left)
1206{
1207 int ret = 0;
1208 u8 element_id;
1209 struct ieee_types_fh_param_set *fh_param_set;
1210 struct ieee_types_ds_param_set *ds_param_set;
1211 struct ieee_types_cf_param_set *cf_param_set;
1212 struct ieee_types_ibss_param_set *ibss_param_set;
1213 struct mwifiex_802_11_fixed_ies fixed_ie;
1214 u8 *current_ptr;
1215 u8 *rate;
1216 u8 element_len;
1217 u16 total_ie_len;
1218 u8 bytes_to_copy;
1219 u8 rate_size;
1220 u16 beacon_size;
1221 u8 found_data_rate_ie;
1222 u32 bytes_left_for_current_beacon;
1223 struct ieee_types_vendor_specific *vendor_ie;
1224 const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
1225 const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
1226
1227 found_data_rate_ie = false;
1228 rate_size = 0;
1229 beacon_size = 0;
1230
1231 if (*bytes_left >= sizeof(beacon_size)) {
1232 /* Extract & convert beacon size from the command buffer */
1233 memcpy(&beacon_size, *beacon_info, sizeof(beacon_size));
1234 *bytes_left -= sizeof(beacon_size);
1235 *beacon_info += sizeof(beacon_size);
1236 }
1237
1238 if (!beacon_size || beacon_size > *bytes_left) {
1239 *beacon_info += *bytes_left;
1240 *bytes_left = 0;
1241 return -1;
1242 }
1243
1244 /* Initialize the current working beacon pointer for this BSS
1245 iteration */
1246 current_ptr = *beacon_info;
1247
1248 /* Advance the return beacon pointer past the current beacon */
1249 *beacon_info += beacon_size;
1250 *bytes_left -= beacon_size;
1251
1252 bytes_left_for_current_beacon = beacon_size;
1253
1254 memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN);
1255 dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n",
1256 bss_entry->mac_address);
1257
1258 current_ptr += ETH_ALEN;
1259 bytes_left_for_current_beacon -= ETH_ALEN;
1260
1261 if (bytes_left_for_current_beacon < 12) {
1262 dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
1263 return -1;
1264 }
1265
1266 /*
1267 * Next 4 fields are RSSI, time stamp, beacon interval,
1268 * and capability information
1269 */
1270
1271 /* RSSI is 1 byte long */
1272 bss_entry->rssi = (s32) (*current_ptr);
1273 dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr);
1274 current_ptr += 1;
1275 bytes_left_for_current_beacon -= 1;
1276
1277 /*
1278 * The RSSI is not part of the beacon/probe response. After we have
1279 * advanced current_ptr past the RSSI field, save the remaining
1280 * data for use at the application layer
1281 */
1282 bss_entry->beacon_buf = current_ptr;
1283 bss_entry->beacon_buf_size = bytes_left_for_current_beacon;
1284
1285 /* Time stamp is 8 bytes long */
1286 memcpy(fixed_ie.time_stamp, current_ptr, 8);
1287 memcpy(bss_entry->time_stamp, current_ptr, 8);
1288 current_ptr += 8;
1289 bytes_left_for_current_beacon -= 8;
1290
1291 /* Beacon interval is 2 bytes long */
1292 memcpy(&fixed_ie.beacon_interval, current_ptr, 2);
1293 bss_entry->beacon_period = le16_to_cpu(fixed_ie.beacon_interval);
1294 current_ptr += 2;
1295 bytes_left_for_current_beacon -= 2;
1296
1297 /* Capability information is 2 bytes long */
1298 memcpy(&fixed_ie.capabilities, current_ptr, 2);
1299 dev_dbg(adapter->dev, "info: InterpretIE: fixed_ie.capabilities=0x%X\n",
1300 fixed_ie.capabilities);
1301 bss_entry->cap_info_bitmap = le16_to_cpu(fixed_ie.capabilities);
1302 current_ptr += 2;
1303 bytes_left_for_current_beacon -= 2;
1304
1305 /* Rest of the current buffer are IE's */
1306 dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
1307 bytes_left_for_current_beacon);
1308
1309 if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
1310 dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n");
1311 bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
1312 } else {
1313 bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
1314 }
1315
1316 if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
1317 bss_entry->bss_mode = MWIFIEX_BSS_MODE_IBSS;
1318 else
1319 bss_entry->bss_mode = MWIFIEX_BSS_MODE_INFRA;
1320
1321
1322 /* Process variable IE */
1323 while (bytes_left_for_current_beacon >= 2) {
1324 element_id = *current_ptr;
1325 element_len = *(current_ptr + 1);
1326 total_ie_len = element_len + sizeof(struct ieee_types_header);
1327
1328 if (bytes_left_for_current_beacon < total_ie_len) {
1329 dev_err(adapter->dev, "err: InterpretIE: in processing"
1330 " IE, bytes left < IE length\n");
1331 bytes_left_for_current_beacon = 0;
1332 ret = -1;
1333 continue;
1334 }
1335 switch (element_id) {
1336 case WLAN_EID_SSID:
1337 bss_entry->ssid.ssid_len = element_len;
1338 memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
1339 element_len);
1340 dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n",
1341 bss_entry->ssid.ssid);
1342 break;
1343
1344 case WLAN_EID_SUPP_RATES:
1345 memcpy(bss_entry->data_rates, current_ptr + 2,
1346 element_len);
1347 memcpy(bss_entry->supported_rates, current_ptr + 2,
1348 element_len);
1349 rate_size = element_len;
1350 found_data_rate_ie = true;
1351 break;
1352
1353 case WLAN_EID_FH_PARAMS:
1354 fh_param_set =
1355 (struct ieee_types_fh_param_set *) current_ptr;
1356 memcpy(&bss_entry->phy_param_set.fh_param_set,
1357 fh_param_set,
1358 sizeof(struct ieee_types_fh_param_set));
1359 break;
1360
1361 case WLAN_EID_DS_PARAMS:
1362 ds_param_set =
1363 (struct ieee_types_ds_param_set *) current_ptr;
1364
1365 bss_entry->channel = ds_param_set->current_chan;
1366
1367 memcpy(&bss_entry->phy_param_set.ds_param_set,
1368 ds_param_set,
1369 sizeof(struct ieee_types_ds_param_set));
1370 break;
1371
1372 case WLAN_EID_CF_PARAMS:
1373 cf_param_set =
1374 (struct ieee_types_cf_param_set *) current_ptr;
1375 memcpy(&bss_entry->ss_param_set.cf_param_set,
1376 cf_param_set,
1377 sizeof(struct ieee_types_cf_param_set));
1378 break;
1379
1380 case WLAN_EID_IBSS_PARAMS:
1381 ibss_param_set =
1382 (struct ieee_types_ibss_param_set *)
1383 current_ptr;
1384 memcpy(&bss_entry->ss_param_set.ibss_param_set,
1385 ibss_param_set,
1386 sizeof(struct ieee_types_ibss_param_set));
1387 break;
1388
1389 case WLAN_EID_ERP_INFO:
1390 bss_entry->erp_flags = *(current_ptr + 2);
1391 break;
1392
1393 case WLAN_EID_EXT_SUPP_RATES:
1394 /*
1395 * Only process extended supported rate
1396 * if data rate is already found.
1397 * Data rate IE should come before
1398 * extended supported rate IE
1399 */
1400 if (found_data_rate_ie) {
1401 if ((element_len + rate_size) >
1402 MWIFIEX_SUPPORTED_RATES)
1403 bytes_to_copy =
1404 (MWIFIEX_SUPPORTED_RATES -
1405 rate_size);
1406 else
1407 bytes_to_copy = element_len;
1408
1409 rate = (u8 *) bss_entry->data_rates;
1410 rate += rate_size;
1411 memcpy(rate, current_ptr + 2, bytes_to_copy);
1412
1413 rate = (u8 *) bss_entry->supported_rates;
1414 rate += rate_size;
1415 memcpy(rate, current_ptr + 2, bytes_to_copy);
1416 }
1417 break;
1418
1419 case WLAN_EID_VENDOR_SPECIFIC:
1420 vendor_ie = (struct ieee_types_vendor_specific *)
1421 current_ptr;
1422
1423 if (!memcmp
1424 (vendor_ie->vend_hdr.oui, wpa_oui,
1425 sizeof(wpa_oui))) {
1426 bss_entry->bcn_wpa_ie =
1427 (struct ieee_types_vendor_specific *)
1428 current_ptr;
1429 bss_entry->wpa_offset = (u16) (current_ptr -
1430 bss_entry->beacon_buf);
1431 } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
1432 sizeof(wmm_oui))) {
1433 if (total_ie_len ==
1434 sizeof(struct ieee_types_wmm_parameter)
1435 || total_ie_len ==
1436 sizeof(struct ieee_types_wmm_info))
1437 /*
1438 * Only accept and copy the WMM IE if
1439 * it matches the size expected for the
1440 * WMM Info IE or the WMM Parameter IE.
1441 */
1442 memcpy((u8 *) &bss_entry->wmm_ie,
1443 current_ptr, total_ie_len);
1444 }
1445 break;
1446 case WLAN_EID_RSN:
1447 bss_entry->bcn_rsn_ie =
1448 (struct ieee_types_generic *) current_ptr;
1449 bss_entry->rsn_offset = (u16) (current_ptr -
1450 bss_entry->beacon_buf);
1451 break;
1452 case WLAN_EID_BSS_AC_ACCESS_DELAY:
1453 bss_entry->bcn_wapi_ie =
1454 (struct ieee_types_generic *) current_ptr;
1455 bss_entry->wapi_offset = (u16) (current_ptr -
1456 bss_entry->beacon_buf);
1457 break;
1458 case WLAN_EID_HT_CAPABILITY:
1459 bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
1460 (current_ptr +
1461 sizeof(struct ieee_types_header));
1462 bss_entry->ht_cap_offset = (u16) (current_ptr +
1463 sizeof(struct ieee_types_header) -
1464 bss_entry->beacon_buf);
1465 break;
1466 case WLAN_EID_HT_INFORMATION:
1467 bss_entry->bcn_ht_info = (struct ieee80211_ht_info *)
1468 (current_ptr +
1469 sizeof(struct ieee_types_header));
1470 bss_entry->ht_info_offset = (u16) (current_ptr +
1471 sizeof(struct ieee_types_header) -
1472 bss_entry->beacon_buf);
1473 break;
1474 case WLAN_EID_BSS_COEX_2040:
1475 bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr +
1476 sizeof(struct ieee_types_header));
1477 bss_entry->bss_co_2040_offset = (u16) (current_ptr +
1478 sizeof(struct ieee_types_header) -
1479 bss_entry->beacon_buf);
1480 break;
1481 case WLAN_EID_EXT_CAPABILITY:
1482 bss_entry->bcn_ext_cap = (u8 *) (current_ptr +
1483 sizeof(struct ieee_types_header));
1484 bss_entry->ext_cap_offset = (u16) (current_ptr +
1485 sizeof(struct ieee_types_header) -
1486 bss_entry->beacon_buf);
1487 break;
1488 case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
1489 bss_entry->bcn_obss_scan =
1490 (struct ieee_types_obss_scan_param *)
1491 current_ptr;
1492 bss_entry->overlap_bss_offset = (u16) (current_ptr -
1493 bss_entry->beacon_buf);
1494 break;
1495 default:
1496 break;
1497 }
1498
1499 current_ptr += element_len + 2;
1500
1501 /* Need to account for IE ID and IE Len */
1502 bytes_left_for_current_beacon -= (element_len + 2);
1503
1504 } /* while (bytes_left_for_current_beacon > 2) */
1505 return ret;
1506}
1507
1508/*
1509 * This function adjusts the pointers used in beacon buffers to reflect
1510 * shifts.
1511 *
1512 * The memory allocated for beacon buffers is of fixed sizes where all the
1513 * saved beacons must be stored. New beacons are added in the free portion
1514 * of this memory, space permitting; while duplicate beacon buffers are
1515 * placed at the same start location. However, since duplicate beacon
1516 * buffers may not match the size of the old one, all the following buffers
1517 * in the memory must be shifted to either make space, or to fill up freed
1518 * up space.
1519 *
1520 * This function is used to update the beacon buffer pointers that are past
1521 * an existing beacon buffer that is updated with a new one of different
1522 * size. The pointers are shifted by a fixed amount, either forward or
1523 * backward.
1524 *
1525 * the following pointers in every affected beacon buffers are changed, if
1526 * present -
1527 * - WPA IE pointer
1528 * - RSN IE pointer
1529 * - WAPI IE pointer
1530 * - HT capability IE pointer
1531 * - HT information IE pointer
1532 * - BSS coexistence 20/40 IE pointer
1533 * - Extended capability IE pointer
1534 * - Overlapping BSS scan parameter IE pointer
1535 */
1536static void
1537mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance,
1538 u8 *bcn_store, u32 rem_bcn_size,
1539 u32 num_of_ent)
1540{
1541 struct mwifiex_adapter *adapter = priv->adapter;
1542 u32 adj_idx;
1543 for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
1544 if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) {
1545
1546 if (advance)
1547 adapter->scan_table[adj_idx].beacon_buf +=
1548 rem_bcn_size;
1549 else
1550 adapter->scan_table[adj_idx].beacon_buf -=
1551 rem_bcn_size;
1552
1553 if (adapter->scan_table[adj_idx].bcn_wpa_ie)
1554 adapter->scan_table[adj_idx].bcn_wpa_ie =
1555 (struct ieee_types_vendor_specific *)
1556 (adapter->scan_table[adj_idx].beacon_buf +
1557 adapter->scan_table[adj_idx].wpa_offset);
1558 if (adapter->scan_table[adj_idx].bcn_rsn_ie)
1559 adapter->scan_table[adj_idx].bcn_rsn_ie =
1560 (struct ieee_types_generic *)
1561 (adapter->scan_table[adj_idx].beacon_buf +
1562 adapter->scan_table[adj_idx].rsn_offset);
1563 if (adapter->scan_table[adj_idx].bcn_wapi_ie)
1564 adapter->scan_table[adj_idx].bcn_wapi_ie =
1565 (struct ieee_types_generic *)
1566 (adapter->scan_table[adj_idx].beacon_buf +
1567 adapter->scan_table[adj_idx].wapi_offset);
1568 if (adapter->scan_table[adj_idx].bcn_ht_cap)
1569 adapter->scan_table[adj_idx].bcn_ht_cap =
1570 (struct ieee80211_ht_cap *)
1571 (adapter->scan_table[adj_idx].beacon_buf +
1572 adapter->scan_table[adj_idx].ht_cap_offset);
1573
1574 if (adapter->scan_table[adj_idx].bcn_ht_info)
1575 adapter->scan_table[adj_idx].bcn_ht_info =
1576 (struct ieee80211_ht_info *)
1577 (adapter->scan_table[adj_idx].beacon_buf +
1578 adapter->scan_table[adj_idx].ht_info_offset);
1579 if (adapter->scan_table[adj_idx].bcn_bss_co_2040)
1580 adapter->scan_table[adj_idx].bcn_bss_co_2040 =
1581 (u8 *)
1582 (adapter->scan_table[adj_idx].beacon_buf +
1583 adapter->scan_table[adj_idx].bss_co_2040_offset);
1584 if (adapter->scan_table[adj_idx].bcn_ext_cap)
1585 adapter->scan_table[adj_idx].bcn_ext_cap =
1586 (u8 *)
1587 (adapter->scan_table[adj_idx].beacon_buf +
1588 adapter->scan_table[adj_idx].ext_cap_offset);
1589 if (adapter->scan_table[adj_idx].bcn_obss_scan)
1590 adapter->scan_table[adj_idx].bcn_obss_scan =
1591 (struct ieee_types_obss_scan_param *)
1592 (adapter->scan_table[adj_idx].beacon_buf +
1593 adapter->scan_table[adj_idx].overlap_bss_offset);
1594 }
1595 }
1596}
1597
1598/*
1599 * This function updates the pointers used in beacon buffer for given bss
1600 * descriptor to reflect shifts
1601 *
1602 * Following pointers are updated
1603 * - WPA IE pointer
1604 * - RSN IE pointer
1605 * - WAPI IE pointer
1606 * - HT capability IE pointer
1607 * - HT information IE pointer
1608 * - BSS coexistence 20/40 IE pointer
1609 * - Extended capability IE pointer
1610 * - Overlapping BSS scan parameter IE pointer
1611 */
1612static void
1613mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon)
1614{
1615 if (beacon->bcn_wpa_ie)
1616 beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *)
1617 (beacon->beacon_buf + beacon->wpa_offset);
1618 if (beacon->bcn_rsn_ie)
1619 beacon->bcn_rsn_ie = (struct ieee_types_generic *)
1620 (beacon->beacon_buf + beacon->rsn_offset);
1621 if (beacon->bcn_wapi_ie)
1622 beacon->bcn_wapi_ie = (struct ieee_types_generic *)
1623 (beacon->beacon_buf + beacon->wapi_offset);
1624 if (beacon->bcn_ht_cap)
1625 beacon->bcn_ht_cap = (struct ieee80211_ht_cap *)
1626 (beacon->beacon_buf + beacon->ht_cap_offset);
1627 if (beacon->bcn_ht_info)
1628 beacon->bcn_ht_info = (struct ieee80211_ht_info *)
1629 (beacon->beacon_buf + beacon->ht_info_offset);
1630 if (beacon->bcn_bss_co_2040)
1631 beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf +
1632 beacon->bss_co_2040_offset);
1633 if (beacon->bcn_ext_cap)
1634 beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf +
1635 beacon->ext_cap_offset);
1636 if (beacon->bcn_obss_scan)
1637 beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *)
1638 (beacon->beacon_buf + beacon->overlap_bss_offset);
1639}
1640
1641/*
1642 * This function stores a beacon or probe response for a BSS returned
1643 * in the scan.
1644 *
1645 * This stores a new scan response or an update for a previous scan response.
1646 * New entries need to verify that they do not exceed the total amount of
1647 * memory allocated for the table.
1648 *
1649 * Replacement entries need to take into consideration the amount of space
1650 * currently allocated for the beacon/probe response and adjust the entry
1651 * as needed.
1652 *
1653 * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
1654 * for an entry in case it is a beacon since a probe response for the
1655 * network will by larger per the standard. This helps to reduce the
1656 * amount of memory copying to fit a new probe response into an entry
1657 * already occupied by a network's previously stored beacon.
1658 */
1659static void
1660mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv,
1661 u32 beacon_idx, u32 num_of_ent,
1662 struct mwifiex_bssdescriptor *new_beacon)
1663{
1664 struct mwifiex_adapter *adapter = priv->adapter;
1665 u8 *bcn_store;
1666 u32 new_bcn_size;
1667 u32 old_bcn_size;
1668 u32 bcn_space;
1669
1670 if (adapter->scan_table[beacon_idx].beacon_buf) {
1671
1672 new_bcn_size = new_beacon->beacon_buf_size;
1673 old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size;
1674 bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max;
1675 bcn_store = adapter->scan_table[beacon_idx].beacon_buf;
1676
1677 /* Set the max to be the same as current entry unless changed
1678 below */
1679 new_beacon->beacon_buf_size_max = bcn_space;
1680 if (new_bcn_size == old_bcn_size) {
1681 /*
1682 * Beacon is the same size as the previous entry.
1683 * Replace the previous contents with the scan result
1684 */
1685 memcpy(bcn_store, new_beacon->beacon_buf,
1686 new_beacon->beacon_buf_size);
1687
1688 } else if (new_bcn_size <= bcn_space) {
1689 /*
1690 * New beacon size will fit in the amount of space
1691 * we have previously allocated for it
1692 */
1693
1694 /* Copy the new beacon buffer entry over the old one */
1695 memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
1696
1697 /*
1698 * If the old beacon size was less than the maximum
1699 * we had alloted for the entry, and the new entry
1700 * is even smaller, reset the max size to the old
1701 * beacon entry and compress the storage space
1702 * (leaving a new pad space of (old_bcn_size -
1703 * new_bcn_size).
1704 */
1705 if (old_bcn_size < bcn_space
1706 && new_bcn_size <= old_bcn_size) {
1707 /*
1708 * Old Beacon size is smaller than the alloted
1709 * storage size. Shrink the alloted storage
1710 * space.
1711 */
1712 dev_dbg(adapter->dev, "info: AppControl:"
1713 " smaller duplicate beacon "
1714 "(%d), old = %d, new = %d, space = %d,"
1715 "left = %d\n",
1716 beacon_idx, old_bcn_size, new_bcn_size,
1717 bcn_space,
1718 (int)(sizeof(adapter->bcn_buf) -
1719 (adapter->bcn_buf_end -
1720 adapter->bcn_buf)));
1721
1722 /*
1723 * memmove (since the memory overlaps) the
1724 * data after the beacon we just stored to the
1725 * end of the current beacon. This cleans up
1726 * any unused space the old larger beacon was
1727 * using in the buffer
1728 */
1729 memmove(bcn_store + old_bcn_size,
1730 bcn_store + bcn_space,
1731 adapter->bcn_buf_end - (bcn_store +
1732 bcn_space));
1733
1734 /*
1735 * Decrement the end pointer by the difference
1736 * between the old larger size and the new
1737 * smaller size since we are using less space
1738 * due to the new beacon being smaller
1739 */
1740 adapter->bcn_buf_end -=
1741 (bcn_space - old_bcn_size);
1742
1743 /* Set the maximum storage size to the old
1744 beacon size */
1745 new_beacon->beacon_buf_size_max = old_bcn_size;
1746
1747 /* Adjust beacon buffer pointers that are past
1748 the current */
1749 mwifiex_adjust_beacon_buffer_ptrs(priv, 0,
1750 bcn_store, (bcn_space - old_bcn_size),
1751 num_of_ent);
1752 }
1753 } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space)
1754 < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) {
1755 /*
1756 * Beacon is larger than space previously allocated
1757 * (bcn_space) and there is enough space left in the
1758 * beaconBuffer to store the additional data
1759 */
1760 dev_dbg(adapter->dev, "info: AppControl:"
1761 " larger duplicate beacon (%d), "
1762 "old = %d, new = %d, space = %d, left = %d\n",
1763 beacon_idx, old_bcn_size, new_bcn_size,
1764 bcn_space,
1765 (int)(sizeof(adapter->bcn_buf) -
1766 (adapter->bcn_buf_end -
1767 adapter->bcn_buf)));
1768
1769 /*
1770 * memmove (since the memory overlaps) the data
1771 * after the beacon we just stored to the end of
1772 * the current beacon. This moves the data for
1773 * the beacons after this further in memory to
1774 * make space for the new larger beacon we are
1775 * about to copy in.
1776 */
1777 memmove(bcn_store + new_bcn_size,
1778 bcn_store + bcn_space,
1779 adapter->bcn_buf_end - (bcn_store + bcn_space));
1780
1781 /* Copy the new beacon buffer entry over the old one */
1782 memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
1783
1784 /* Move the beacon end pointer by the amount of new
1785 beacon data we are adding */
1786 adapter->bcn_buf_end += (new_bcn_size - bcn_space);
1787
1788 /*
1789 * This entry is bigger than the alloted max space
1790 * previously reserved. Increase the max space to
1791 * be equal to the new beacon size
1792 */
1793 new_beacon->beacon_buf_size_max = new_bcn_size;
1794
1795 /* Adjust beacon buffer pointers that are past the
1796 current */
1797 mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store,
1798 (new_bcn_size - bcn_space),
1799 num_of_ent);
1800 } else {
1801 /*
1802 * Beacon is larger than the previously allocated space,
1803 * but there is not enough free space to store the
1804 * additional data.
1805 */
1806 dev_err(adapter->dev, "AppControl: larger duplicate "
1807 " beacon (%d), old = %d new = %d, space = %d,"
1808 " left = %d\n", beacon_idx, old_bcn_size,
1809 new_bcn_size, bcn_space,
1810 (int)(sizeof(adapter->bcn_buf) -
1811 (adapter->bcn_buf_end - adapter->bcn_buf)));
1812
1813 /* Storage failure, keep old beacon intact */
1814 new_beacon->beacon_buf_size = old_bcn_size;
1815 if (new_beacon->bcn_wpa_ie)
1816 new_beacon->wpa_offset =
1817 adapter->scan_table[beacon_idx].
1818 wpa_offset;
1819 if (new_beacon->bcn_rsn_ie)
1820 new_beacon->rsn_offset =
1821 adapter->scan_table[beacon_idx].
1822 rsn_offset;
1823 if (new_beacon->bcn_wapi_ie)
1824 new_beacon->wapi_offset =
1825 adapter->scan_table[beacon_idx].
1826 wapi_offset;
1827 if (new_beacon->bcn_ht_cap)
1828 new_beacon->ht_cap_offset =
1829 adapter->scan_table[beacon_idx].
1830 ht_cap_offset;
1831 if (new_beacon->bcn_ht_info)
1832 new_beacon->ht_info_offset =
1833 adapter->scan_table[beacon_idx].
1834 ht_info_offset;
1835 if (new_beacon->bcn_bss_co_2040)
1836 new_beacon->bss_co_2040_offset =
1837 adapter->scan_table[beacon_idx].
1838 bss_co_2040_offset;
1839 if (new_beacon->bcn_ext_cap)
1840 new_beacon->ext_cap_offset =
1841 adapter->scan_table[beacon_idx].
1842 ext_cap_offset;
1843 if (new_beacon->bcn_obss_scan)
1844 new_beacon->overlap_bss_offset =
1845 adapter->scan_table[beacon_idx].
1846 overlap_bss_offset;
1847 }
1848 /* Point the new entry to its permanent storage space */
1849 new_beacon->beacon_buf = bcn_store;
1850 mwifiex_update_beacon_buffer_ptrs(new_beacon);
1851 } else {
1852 /*
1853 * No existing beacon data exists for this entry, check to see
1854 * if we can fit it in the remaining space
1855 */
1856 if (adapter->bcn_buf_end + new_beacon->beacon_buf_size +
1857 SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf +
1858 sizeof(adapter->bcn_buf))) {
1859
1860 /*
1861 * Copy the beacon buffer data from the local entry to
1862 * the adapter dev struct buffer space used to store
1863 * the raw beacon data for each entry in the scan table
1864 */
1865 memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf,
1866 new_beacon->beacon_buf_size);
1867
1868 /* Update the beacon ptr to point to the table save
1869 area */
1870 new_beacon->beacon_buf = adapter->bcn_buf_end;
1871 new_beacon->beacon_buf_size_max =
1872 (new_beacon->beacon_buf_size +
1873 SCAN_BEACON_ENTRY_PAD);
1874
1875 mwifiex_update_beacon_buffer_ptrs(new_beacon);
1876
1877 /* Increment the end pointer by the size reserved */
1878 adapter->bcn_buf_end += new_beacon->beacon_buf_size_max;
1879
1880 dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]"
1881 " sz=%03d, used = %04d, left = %04d\n",
1882 beacon_idx,
1883 new_beacon->beacon_buf_size,
1884 (int)(adapter->bcn_buf_end - adapter->bcn_buf),
1885 (int)(sizeof(adapter->bcn_buf) -
1886 (adapter->bcn_buf_end -
1887 adapter->bcn_buf)));
1888 } else {
1889 /* No space for new beacon */
1890 dev_dbg(adapter->dev, "info: AppControl: no space for"
1891 " beacon (%d): %pM sz=%03d, left=%03d\n",
1892 beacon_idx, new_beacon->mac_address,
1893 new_beacon->beacon_buf_size,
1894 (int)(sizeof(adapter->bcn_buf) -
1895 (adapter->bcn_buf_end -
1896 adapter->bcn_buf)));
1897
1898 /* Storage failure; clear storage records for this
1899 bcn */
1900 new_beacon->beacon_buf = NULL;
1901 new_beacon->beacon_buf_size = 0;
1902 new_beacon->beacon_buf_size_max = 0;
1903 new_beacon->bcn_wpa_ie = NULL;
1904 new_beacon->wpa_offset = 0;
1905 new_beacon->bcn_rsn_ie = NULL;
1906 new_beacon->rsn_offset = 0;
1907 new_beacon->bcn_wapi_ie = NULL;
1908 new_beacon->wapi_offset = 0;
1909 new_beacon->bcn_ht_cap = NULL;
1910 new_beacon->ht_cap_offset = 0;
1911 new_beacon->bcn_ht_info = NULL;
1912 new_beacon->ht_info_offset = 0;
1913 new_beacon->bcn_bss_co_2040 = NULL;
1914 new_beacon->bss_co_2040_offset = 0;
1915 new_beacon->bcn_ext_cap = NULL;
1916 new_beacon->ext_cap_offset = 0;
1917 new_beacon->bcn_obss_scan = NULL;
1918 new_beacon->overlap_bss_offset = 0;
1919 }
1920 }
1921}
1922
1923/*
1924 * This function restores a beacon buffer of the current BSS descriptor.
1925 */
1926static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv)
1927{
1928 struct mwifiex_adapter *adapter = priv->adapter;
1929 struct mwifiex_bssdescriptor *curr_bss =
1930 &priv->curr_bss_params.bss_descriptor;
1931 unsigned long flags;
1932
1933 if (priv->curr_bcn_buf &&
1934 ((adapter->bcn_buf_end + priv->curr_bcn_size) <
1935 (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) {
1936 spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
1937
1938 /* restore the current beacon buffer */
1939 memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf,
1940 priv->curr_bcn_size);
1941 curr_bss->beacon_buf = adapter->bcn_buf_end;
1942 curr_bss->beacon_buf_size = priv->curr_bcn_size;
1943 adapter->bcn_buf_end += priv->curr_bcn_size;
1944
1945 /* adjust the pointers in the current BSS descriptor */
1946 if (curr_bss->bcn_wpa_ie)
1947 curr_bss->bcn_wpa_ie =
1948 (struct ieee_types_vendor_specific *)
1949 (curr_bss->beacon_buf +
1950 curr_bss->wpa_offset);
1951
1952 if (curr_bss->bcn_rsn_ie)
1953 curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
1954 (curr_bss->beacon_buf +
1955 curr_bss->rsn_offset);
1956
1957 if (curr_bss->bcn_ht_cap)
1958 curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
1959 (curr_bss->beacon_buf +
1960 curr_bss->ht_cap_offset);
1961
1962 if (curr_bss->bcn_ht_info)
1963 curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
1964 (curr_bss->beacon_buf +
1965 curr_bss->ht_info_offset);
1966
1967 if (curr_bss->bcn_bss_co_2040)
1968 curr_bss->bcn_bss_co_2040 =
1969 (u8 *) (curr_bss->beacon_buf +
1970 curr_bss->bss_co_2040_offset);
1971
1972 if (curr_bss->bcn_ext_cap)
1973 curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
1974 curr_bss->ext_cap_offset);
1975
1976 if (curr_bss->bcn_obss_scan)
1977 curr_bss->bcn_obss_scan =
1978 (struct ieee_types_obss_scan_param *)
1979 (curr_bss->beacon_buf +
1980 curr_bss->overlap_bss_offset);
1981
1982 spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
1983
1984 dev_dbg(adapter->dev, "info: current beacon restored %d\n",
1985 priv->curr_bcn_size);
1986 } else {
1987 dev_warn(adapter->dev,
1988 "curr_bcn_buf not saved or bcn_buf has no space\n");
1989 }
1990}
1991
1992/*
1993 * This function post processes the scan table after a new scan command has
1994 * completed.
1995 *
1996 * It inspects each entry of the scan table and tries to find an entry that
1997 * matches with our current associated/joined network from the scan. If
1998 * one is found, the stored copy of the BSS descriptor of our current network
1999 * is updated.
2000 *
2001 * It also debug dumps the current scan table contents after processing is over.
2002 */
2003static void
2004mwifiex_process_scan_results(struct mwifiex_private *priv)
2005{
2006 struct mwifiex_adapter *adapter = priv->adapter;
2007 s32 j;
2008 u32 i;
2009 unsigned long flags;
2010
2011 if (priv->media_connected) {
2012
2013 j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params.
2014 bss_descriptor.ssid,
2015 priv->curr_bss_params.
2016 bss_descriptor.mac_address,
2017 priv->bss_mode);
2018
2019 if (j >= 0) {
2020 spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
2021 priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
2022 priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
2023 priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
2024 priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
2025 priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
2026 priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
2027 priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
2028 priv->curr_bss_params.bss_descriptor.ht_cap_offset =
2029 0;
2030 priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
2031 priv->curr_bss_params.bss_descriptor.ht_info_offset =
2032 0;
2033 priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
2034 NULL;
2035 priv->curr_bss_params.bss_descriptor.
2036 bss_co_2040_offset = 0;
2037 priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
2038 priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
2039 priv->curr_bss_params.bss_descriptor.
2040 bcn_obss_scan = NULL;
2041 priv->curr_bss_params.bss_descriptor.
2042 overlap_bss_offset = 0;
2043 priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
2044 priv->curr_bss_params.bss_descriptor.beacon_buf_size =
2045 0;
2046 priv->curr_bss_params.bss_descriptor.
2047 beacon_buf_size_max = 0;
2048
2049 dev_dbg(adapter->dev, "info: Found current ssid/bssid"
2050 " in list @ index #%d\n", j);
2051 /* Make a copy of current BSSID descriptor */
2052 memcpy(&priv->curr_bss_params.bss_descriptor,
2053 &adapter->scan_table[j],
2054 sizeof(priv->curr_bss_params.bss_descriptor));
2055
2056 mwifiex_save_curr_bcn(priv);
2057 spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
2058
2059 } else {
2060 mwifiex_restore_curr_bcn(priv);
2061 }
2062 }
2063
2064 for (i = 0; i < adapter->num_in_scan_table; i++)
2065 dev_dbg(adapter->dev, "info: scan:(%02d) %pM "
2066 "RSSI[%03d], SSID[%s]\n",
2067 i, adapter->scan_table[i].mac_address,
2068 (s32) adapter->scan_table[i].rssi,
2069 adapter->scan_table[i].ssid.ssid);
2070}
2071
2072/*
2073 * This function converts radio type scan parameter to a band configuration
2074 * to be used in join command.
2075 */
2076static u8
2077mwifiex_radio_type_to_band(u8 radio_type)
2078{
2079 u8 ret_band;
2080
2081 switch (radio_type) {
2082 case HostCmd_SCAN_RADIO_TYPE_A:
2083 ret_band = BAND_A;
2084 break;
2085 case HostCmd_SCAN_RADIO_TYPE_BG:
2086 default:
2087 ret_band = BAND_G;
2088 break;
2089 }
2090
2091 return ret_band;
2092}
2093
2094/*
2095 * This function deletes a specific indexed entry from the scan table.
2096 *
2097 * This also compacts the remaining entries and adjusts any buffering
2098 * of beacon/probe response data if needed.
2099 */
2100static void
2101mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx)
2102{
2103 struct mwifiex_adapter *adapter = priv->adapter;
2104 u32 del_idx;
2105 u32 beacon_buf_adj;
2106 u8 *beacon_buf;
2107
2108 /*
2109 * Shift the saved beacon buffer data for the scan table back over the
2110 * entry being removed. Update the end of buffer pointer. Save the
2111 * deleted buffer allocation size for pointer adjustments for entries
2112 * compacted after the deleted index.
2113 */
2114 beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max;
2115
2116 dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer "
2117 "removal = %d bytes\n", table_idx, beacon_buf_adj);
2118
2119 /* Check if the table entry had storage allocated for its beacon */
2120 if (beacon_buf_adj) {
2121 beacon_buf = adapter->scan_table[table_idx].beacon_buf;
2122
2123 /*
2124 * Remove the entry's buffer space, decrement the table end
2125 * pointer by the amount we are removing
2126 */
2127 adapter->bcn_buf_end -= beacon_buf_adj;
2128
2129 dev_dbg(adapter->dev, "info: scan: delete entry %d,"
2130 " compact data: %p <- %p (sz = %d)\n",
2131 table_idx, beacon_buf,
2132 beacon_buf + beacon_buf_adj,
2133 (int)(adapter->bcn_buf_end - beacon_buf));
2134
2135 /*
2136 * Compact data storage. Copy all data after the deleted
2137 * entry's end address (beacon_buf + beacon_buf_adj) back
2138 * to the original start address (beacon_buf).
2139 *
2140 * Scan table entries affected by the move will have their
2141 * entry pointer adjusted below.
2142 *
2143 * Use memmove since the dest/src memory regions overlap.
2144 */
2145 memmove(beacon_buf, beacon_buf + beacon_buf_adj,
2146 adapter->bcn_buf_end - beacon_buf);
2147 }
2148
2149 dev_dbg(adapter->dev,
2150 "info: Scan: Delete Entry %d, num_in_scan_table = %d\n",
2151 table_idx, adapter->num_in_scan_table);
2152
2153 /* Shift all of the entries after the table_idx back by one, compacting
2154 the table and removing the requested entry */
2155 for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table;
2156 del_idx++) {
2157 /* Copy the next entry over this one */
2158 memcpy(adapter->scan_table + del_idx,
2159 adapter->scan_table + del_idx + 1,
2160 sizeof(struct mwifiex_bssdescriptor));
2161
2162 /*
2163 * Adjust this entry's pointer to its beacon buffer based on
2164 * the removed/compacted entry from the deleted index. Don't
2165 * decrement if the buffer pointer is NULL (no data stored for
2166 * this entry).
2167 */
2168 if (adapter->scan_table[del_idx].beacon_buf) {
2169 adapter->scan_table[del_idx].beacon_buf -=
2170 beacon_buf_adj;
2171 if (adapter->scan_table[del_idx].bcn_wpa_ie)
2172 adapter->scan_table[del_idx].bcn_wpa_ie =
2173 (struct ieee_types_vendor_specific *)
2174 (adapter->scan_table[del_idx].
2175 beacon_buf +
2176 adapter->scan_table[del_idx].
2177 wpa_offset);
2178 if (adapter->scan_table[del_idx].bcn_rsn_ie)
2179 adapter->scan_table[del_idx].bcn_rsn_ie =
2180 (struct ieee_types_generic *)
2181 (adapter->scan_table[del_idx].
2182 beacon_buf +
2183 adapter->scan_table[del_idx].
2184 rsn_offset);
2185 if (adapter->scan_table[del_idx].bcn_wapi_ie)
2186 adapter->scan_table[del_idx].bcn_wapi_ie =
2187 (struct ieee_types_generic *)
2188 (adapter->scan_table[del_idx].beacon_buf
2189 + adapter->scan_table[del_idx].
2190 wapi_offset);
2191 if (adapter->scan_table[del_idx].bcn_ht_cap)
2192 adapter->scan_table[del_idx].bcn_ht_cap =
2193 (struct ieee80211_ht_cap *)
2194 (adapter->scan_table[del_idx].beacon_buf
2195 + adapter->scan_table[del_idx].
2196 ht_cap_offset);
2197
2198 if (adapter->scan_table[del_idx].bcn_ht_info)
2199 adapter->scan_table[del_idx].bcn_ht_info =
2200 (struct ieee80211_ht_info *)
2201 (adapter->scan_table[del_idx].beacon_buf
2202 + adapter->scan_table[del_idx].
2203 ht_info_offset);
2204 if (adapter->scan_table[del_idx].bcn_bss_co_2040)
2205 adapter->scan_table[del_idx].bcn_bss_co_2040 =
2206 (u8 *)
2207 (adapter->scan_table[del_idx].beacon_buf
2208 + adapter->scan_table[del_idx].
2209 bss_co_2040_offset);
2210 if (adapter->scan_table[del_idx].bcn_ext_cap)
2211 adapter->scan_table[del_idx].bcn_ext_cap =
2212 (u8 *)
2213 (adapter->scan_table[del_idx].beacon_buf
2214 + adapter->scan_table[del_idx].
2215 ext_cap_offset);
2216 if (adapter->scan_table[del_idx].bcn_obss_scan)
2217 adapter->scan_table[del_idx].
2218 bcn_obss_scan =
2219 (struct ieee_types_obss_scan_param *)
2220 (adapter->scan_table[del_idx].beacon_buf
2221 + adapter->scan_table[del_idx].
2222 overlap_bss_offset);
2223 }
2224 }
2225
2226 /* The last entry is invalid now that it has been deleted or moved
2227 back */
2228 memset(adapter->scan_table + adapter->num_in_scan_table - 1,
2229 0x00, sizeof(struct mwifiex_bssdescriptor));
2230
2231 adapter->num_in_scan_table--;
2232}
2233
2234/*
2235 * This function deletes all occurrences of a given SSID from the scan table.
2236 *
2237 * This iterates through the scan table and deletes all entries that match
2238 * the given SSID. It also compacts the remaining scan table entries.
2239 */
2240static int
2241mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
2242 struct mwifiex_802_11_ssid *del_ssid)
2243{
2244 int ret = -1;
2245 s32 table_idx;
2246
2247 dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
2248 del_ssid->ssid);
2249
2250 /* If the requested SSID is found in the table, delete it. Then keep
2251 searching the table for multiple entires for the SSID until no
2252 more are found */
2253 while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL,
2254 MWIFIEX_BSS_MODE_AUTO)) >=
2255 0) {
2256 dev_dbg(priv->adapter->dev,
2257 "info: Scan: Delete SSID Entry: Found Idx = %d\n",
2258 table_idx);
2259 ret = 0;
2260 mwifiex_scan_delete_table_entry(priv, table_idx);
2261 }
2262
2263 return ret;
2264}
2265
2266/*
2267 * This is an internal function used to start a scan based on an input
2268 * configuration.
2269 *
2270 * This uses the input user scan configuration information when provided in
2271 * order to send the appropriate scan commands to firmware to populate or
2272 * update the internal driver scan table.
2273 */
2274int mwifiex_scan_networks(struct mwifiex_private *priv,
2275 void *wait_buf, u16 action,
2276 const struct mwifiex_user_scan_cfg *user_scan_in,
2277 struct mwifiex_scan_resp *scan_resp)
2278{
2279 int ret = 0;
2280 struct mwifiex_adapter *adapter = priv->adapter;
2281 struct cmd_ctrl_node *cmd_node = NULL;
2282 union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL;
2283 struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
2284 u32 buf_size;
2285 struct mwifiex_chan_scan_param_set *scan_chan_list;
2286 u8 keep_previous_scan;
2287 u8 filtered_scan;
2288 u8 scan_current_chan_only;
2289 u8 max_chan_per_scan;
2290 unsigned long flags;
2291
2292 if (action == HostCmd_ACT_GEN_GET) {
2293 if (scan_resp) {
2294 scan_resp->scan_table = (u8 *) adapter->scan_table;
2295 scan_resp->num_in_scan_table =
2296 adapter->num_in_scan_table;
2297 } else {
2298 ret = -1;
2299 }
2300 return ret;
2301 }
2302
2303 if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) {
2304 dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
2305 return ret;
2306 }
2307
2308 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2309 adapter->scan_processing = true;
2310 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2311
2312 if (priv->scan_block && action == HostCmd_ACT_GEN_SET) {
2313 dev_dbg(adapter->dev,
2314 "cmd: Scan is blocked during association...\n");
2315 return ret;
2316 }
2317
2318 scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
2319 GFP_KERNEL);
2320 if (!scan_cfg_out) {
2321 dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
2322 return -1;
2323 }
2324
2325 buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
2326 MWIFIEX_USER_SCAN_CHAN_MAX;
2327 scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
2328 if (!scan_chan_list) {
2329 dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
2330 kfree(scan_cfg_out);
2331 return -1;
2332 }
2333
2334 keep_previous_scan = false;
2335
2336 mwifiex_scan_setup_scan_config(priv, user_scan_in,
2337 &scan_cfg_out->config, &chan_list_out,
2338 scan_chan_list, &max_chan_per_scan,
2339 &filtered_scan, &scan_current_chan_only);
2340
2341 if (user_scan_in)
2342 keep_previous_scan = user_scan_in->keep_previous_scan;
2343
2344
2345 if (!keep_previous_scan) {
2346 memset(adapter->scan_table, 0x00,
2347 sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
2348 adapter->num_in_scan_table = 0;
2349 adapter->bcn_buf_end = adapter->bcn_buf;
2350 }
2351
2352 ret = mwifiex_scan_channel_list(priv, wait_buf, max_chan_per_scan,
2353 filtered_scan, &scan_cfg_out->config,
2354 chan_list_out, scan_chan_list);
2355
2356 /* Get scan command from scan_pending_q and put to cmd_pending_q */
2357 if (!ret) {
2358 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2359 if (!list_empty(&adapter->scan_pending_q)) {
2360 cmd_node = list_first_entry(&adapter->scan_pending_q,
2361 struct cmd_ctrl_node, list);
2362 list_del(&cmd_node->list);
2363 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
2364 flags);
2365 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
2366 true);
2367 } else {
2368 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
2369 flags);
2370 }
2371 ret = -EINPROGRESS;
2372 } else {
2373 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2374 adapter->scan_processing = true;
2375 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2376 }
2377
2378 kfree(scan_cfg_out);
2379 kfree(scan_chan_list);
2380 return ret;
2381}
2382
2383/*
2384 * This function prepares a scan command to be sent to the firmware.
2385 *
2386 * This uses the scan command configuration sent to the command processing
2387 * module in command preparation stage to configure a scan command structure
2388 * to send to firmware.
2389 *
2390 * The fixed fields specifying the BSS type and BSSID filters as well as a
2391 * variable number/length of TLVs are sent in the command to firmware.
2392 *
2393 * Preparation also includes -
2394 * - Setting command ID, and proper size
2395 * - Ensuring correct endian-ness
2396 */
2397int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv,
2398 struct host_cmd_ds_command *cmd, void *data_buf)
2399{
2400 struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
2401 struct mwifiex_scan_cmd_config *scan_cfg;
2402
2403 scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf;
2404
2405 /* Set fixed field variables in scan command */
2406 scan_cmd->bss_mode = scan_cfg->bss_mode;
2407 memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
2408 sizeof(scan_cmd->bssid));
2409 memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
2410
2411 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
2412
2413 /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
2414 cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
2415 + sizeof(scan_cmd->bssid)
2416 + scan_cfg->tlv_buf_len + S_DS_GEN));
2417
2418 return 0;
2419}
2420
2421/*
2422 * This function handles the command response of scan.
2423 *
2424 * The response buffer for the scan command has the following
2425 * memory layout:
2426 *
2427 * .-------------------------------------------------------------.
2428 * | Header (4 * sizeof(t_u16)): Standard command response hdr |
2429 * .-------------------------------------------------------------.
2430 * | BufSize (t_u16) : sizeof the BSS Description data |
2431 * .-------------------------------------------------------------.
2432 * | NumOfSet (t_u8) : Number of BSS Descs returned |
2433 * .-------------------------------------------------------------.
2434 * | BSSDescription data (variable, size given in BufSize) |
2435 * .-------------------------------------------------------------.
2436 * | TLV data (variable, size calculated using Header->Size, |
2437 * | BufSize and sizeof the fixed fields above) |
2438 * .-------------------------------------------------------------.
2439 */
2440int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
2441 struct host_cmd_ds_command *resp, void *wq_buf)
2442{
2443 int ret = 0;
2444 struct mwifiex_adapter *adapter = priv->adapter;
2445 struct mwifiex_wait_queue *wait_queue = NULL;
2446 struct cmd_ctrl_node *cmd_node = NULL;
2447 struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL;
2448 struct mwifiex_bssdescriptor *bss_new_entry = NULL;
2449 struct mwifiex_ie_types_data *tlv_data;
2450 struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
2451 u8 *bss_info;
2452 u32 scan_resp_size;
2453 u32 bytes_left;
2454 u32 num_in_table;
2455 u32 bss_idx;
2456 u32 idx;
2457 u32 tlv_buf_size;
2458 long long tsf_val;
2459 struct mwifiex_chan_freq_power *cfp;
2460 struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
2461 struct chan_band_param_set *chan_band;
2462 u8 band;
2463 u8 is_bgscan_resp;
2464 unsigned long flags;
2465
2466 is_bgscan_resp = (le16_to_cpu(resp->command)
2467 == HostCmd_CMD_802_11_BG_SCAN_QUERY);
2468 if (is_bgscan_resp)
2469 scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
2470 else
2471 scan_rsp = &resp->params.scan_resp;
2472
2473
2474 if (scan_rsp->number_of_sets > IW_MAX_AP) {
2475 dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
2476 scan_rsp->number_of_sets);
2477 ret = -1;
2478 goto done;
2479 }
2480
2481 bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
2482 dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
2483 bytes_left);
2484
2485 scan_resp_size = le16_to_cpu(resp->size);
2486
2487 dev_dbg(adapter->dev,
2488 "info: SCAN_RESP: returned %d APs before parsing\n",
2489 scan_rsp->number_of_sets);
2490
2491 num_in_table = adapter->num_in_scan_table;
2492 bss_info = scan_rsp->bss_desc_and_tlv_buffer;
2493
2494 /*
2495 * The size of the TLV buffer is equal to the entire command response
2496 * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
2497 * BSS Descriptions (bss_descript_size as bytesLef) and the command
2498 * response header (S_DS_GEN)
2499 */
2500 tlv_buf_size = scan_resp_size - (bytes_left
2501 + sizeof(scan_rsp->bss_descript_size)
2502 + sizeof(scan_rsp->number_of_sets)
2503 + S_DS_GEN);
2504
2505 tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
2506 bss_desc_and_tlv_buffer +
2507 bytes_left);
2508
2509 /* Search the TLV buffer space in the scan response for any valid
2510 TLVs */
2511 mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2512 TLV_TYPE_TSFTIMESTAMP,
2513 (struct mwifiex_ie_types_data **)
2514 &tsf_tlv);
2515
2516 /* Search the TLV buffer space in the scan response for any valid
2517 TLVs */
2518 mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2519 TLV_TYPE_CHANNELBANDLIST,
2520 (struct mwifiex_ie_types_data **)
2521 &chan_band_tlv);
2522
2523 /*
2524 * Process each scan response returned (scan_rsp->number_of_sets).
2525 * Save the information in the bss_new_entry and then insert into the
2526 * driver scan table either as an update to an existing entry
2527 * or as an addition at the end of the table
2528 */
2529 bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor),
2530 GFP_KERNEL);
2531 if (!bss_new_entry) {
2532 dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
2533 return -1;
2534 }
2535
2536 for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
2537 /* Zero out the bss_new_entry we are about to store info in */
2538 memset(bss_new_entry, 0x00,
2539 sizeof(struct mwifiex_bssdescriptor));
2540
2541 if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry,
2542 &bss_info,
2543 &bytes_left)) {
2544 /* Error parsing/interpreting scan response, skipped */
2545 dev_err(adapter->dev, "SCAN_RESP: "
2546 "mwifiex_interpret_bss_desc_with_ie "
2547 "returned ERROR\n");
2548 continue;
2549 }
2550
2551 /* Process the data fields and IEs returned for this BSS */
2552 dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n",
2553 bss_new_entry->mac_address);
2554
2555 /* Search the scan table for the same bssid */
2556 for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
2557 if (memcmp(bss_new_entry->mac_address,
2558 adapter->scan_table[bss_idx].mac_address,
2559 sizeof(bss_new_entry->mac_address))) {
2560 continue;
2561 }
2562 /*
2563 * If the SSID matches as well, it is a
2564 * duplicate of this entry. Keep the bss_idx
2565 * set to this entry so we replace the old
2566 * contents in the table
2567 */
2568 if ((bss_new_entry->ssid.ssid_len
2569 == adapter->scan_table[bss_idx]. ssid.ssid_len)
2570 && (!memcmp(bss_new_entry->ssid.ssid,
2571 adapter->scan_table[bss_idx].ssid.ssid,
2572 bss_new_entry->ssid.ssid_len))) {
2573 dev_dbg(adapter->dev, "info: SCAN_RESP:"
2574 " duplicate of index: %d\n", bss_idx);
2575 break;
2576 }
2577 }
2578 /*
2579 * If the bss_idx is equal to the number of entries in
2580 * the table, the new entry was not a duplicate; append
2581 * it to the scan table
2582 */
2583 if (bss_idx == num_in_table) {
2584 /* Range check the bss_idx, keep it limited to
2585 the last entry */
2586 if (bss_idx == IW_MAX_AP)
2587 bss_idx--;
2588 else
2589 num_in_table++;
2590 }
2591
2592 /*
2593 * Save the beacon/probe response returned for later application
2594 * retrieval. Duplicate beacon/probe responses are updated if
2595 * possible
2596 */
2597 mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx,
2598 num_in_table, bss_new_entry);
2599 /*
2600 * If the TSF TLV was appended to the scan results, save this
2601 * entry's TSF value in the networkTSF field.The networkTSF is
2602 * the firmware's TSF value at the time the beacon or probe
2603 * response was received.
2604 */
2605 if (tsf_tlv) {
2606 memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE]
2607 , sizeof(tsf_val));
2608 memcpy(&bss_new_entry->network_tsf, &tsf_val,
2609 sizeof(bss_new_entry->network_tsf));
2610 }
2611 band = BAND_G;
2612 if (chan_band_tlv) {
2613 chan_band = &chan_band_tlv->chan_band_param[idx];
2614 band = mwifiex_radio_type_to_band(chan_band->radio_type
2615 & (BIT(0) | BIT(1)));
2616 }
2617
2618 /* Save the band designation for this entry for use in join */
2619 bss_new_entry->bss_band = band;
2620 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
2621 (u8) bss_new_entry->bss_band,
2622 (u16)bss_new_entry->channel);
2623
2624 if (cfp)
2625 bss_new_entry->freq = cfp->freq;
2626 else
2627 bss_new_entry->freq = 0;
2628
2629 /* Copy the locally created bss_new_entry to the scan table */
2630 memcpy(&adapter->scan_table[bss_idx], bss_new_entry,
2631 sizeof(adapter->scan_table[bss_idx]));
2632
2633 }
2634
2635 dev_dbg(adapter->dev,
2636 "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
2637 scan_rsp->number_of_sets,
2638 num_in_table - adapter->num_in_scan_table, num_in_table);
2639
2640 /* Update the total number of BSSIDs in the scan table */
2641 adapter->num_in_scan_table = num_in_table;
2642
2643 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2644 if (list_empty(&adapter->scan_pending_q)) {
2645 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2646 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2647 adapter->scan_processing = false;
2648 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2649 /*
2650 * Process the resulting scan table:
2651 * - Remove any bad ssids
2652 * - Update our current BSS information from scan data
2653 */
2654 mwifiex_process_scan_results(priv);
2655
2656 /* Need to indicate IOCTL complete */
2657 wait_queue = (struct mwifiex_wait_queue *) wq_buf;
2658 if (wait_queue) {
2659 wait_queue->status = MWIFIEX_ERROR_NO_ERROR;
2660
2661 /* Indicate ioctl complete */
2662 mwifiex_ioctl_complete(adapter,
2663 (struct mwifiex_wait_queue *) wait_queue, 0);
2664 }
2665 if (priv->report_scan_result)
2666 priv->report_scan_result = false;
2667 if (priv->scan_pending_on_block) {
2668 priv->scan_pending_on_block = false;
2669 up(&priv->async_sem);
2670 }
2671
2672 } else {
2673 /* Get scan command from scan_pending_q and put to
2674 cmd_pending_q */
2675 cmd_node = list_first_entry(&adapter->scan_pending_q,
2676 struct cmd_ctrl_node, list);
2677 list_del(&cmd_node->list);
2678 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2679
2680 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
2681 }
2682
2683done:
2684 kfree((u8 *) bss_new_entry);
2685 return ret;
2686}
2687
2688/*
2689 * This function prepares command for background scan query.
2690 *
2691 * Preparation includes -
2692 * - Setting command ID and proper size
2693 * - Setting background scan flush parameter
2694 * - Ensuring correct endian-ness
2695 */
2696int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv,
2697 struct host_cmd_ds_command *cmd,
2698 void *data_buf)
2699{
2700 struct host_cmd_ds_802_11_bg_scan_query *bg_query =
2701 &cmd->params.bg_scan_query;
2702
2703 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
2704 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
2705 + S_DS_GEN);
2706
2707 bg_query->flush = 1;
2708
2709 return 0;
2710}
2711
2712/*
2713 * This function finds a SSID in the scan table.
2714 *
2715 * A BSSID may optionally be provided to qualify the SSID.
2716 * For non-Auto mode, further check is made to make sure the
2717 * BSS found in the scan table is compatible with the current
2718 * settings of the driver.
2719 */
2720s32
2721mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
2722 struct mwifiex_802_11_ssid *ssid, u8 *bssid,
2723 u32 mode)
2724{
2725 struct mwifiex_adapter *adapter = priv->adapter;
2726 s32 net = -1, j;
2727 u8 best_rssi = 0;
2728 u32 i;
2729
2730 dev_dbg(adapter->dev, "info: num of entries in table = %d\n",
2731 adapter->num_in_scan_table);
2732
2733 /*
2734 * Loop through the table until the maximum is reached or until a match
2735 * is found based on the bssid field comparison
2736 */
2737 for (i = 0;
2738 i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0));
2739 i++) {
2740 if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) &&
2741 (!bssid
2742 || !memcmp(adapter->scan_table[i].mac_address, bssid,
2743 ETH_ALEN))
2744 &&
2745 (mwifiex_get_cfp_by_band_and_channel_from_cfg80211
2746 (priv, (u8) adapter->scan_table[i].bss_band,
2747 (u16) adapter->scan_table[i].channel))) {
2748 switch (mode) {
2749 case MWIFIEX_BSS_MODE_INFRA:
2750 case MWIFIEX_BSS_MODE_IBSS:
2751 j = mwifiex_is_network_compatible(priv, i,
2752 mode);
2753
2754 if (j >= 0) {
2755 if (SCAN_RSSI
2756 (adapter->scan_table[i].rssi) >
2757 best_rssi) {
2758 best_rssi = SCAN_RSSI(adapter->
2759 scan_table
2760 [i].rssi);
2761 net = i;
2762 }
2763 } else {
2764 if (net == -1)
2765 net = j;
2766 }
2767 break;
2768 case MWIFIEX_BSS_MODE_AUTO:
2769 default:
2770 /*
2771 * Do not check compatibility if the mode
2772 * requested is Auto/Unknown. Allows generic
2773 * find to work without verifying against the
2774 * Adapter security settings
2775 */
2776 if (SCAN_RSSI(adapter->scan_table[i].rssi) >
2777 best_rssi) {
2778 best_rssi = SCAN_RSSI(adapter->
2779 scan_table[i].rssi);
2780 net = i;
2781 }
2782 break;
2783 }
2784 }
2785 }
2786
2787 return net;
2788}
2789
2790/*
2791 * This function finds a specific compatible BSSID in the scan list.
2792 *
2793 * This function loops through the scan table looking for a compatible
2794 * match. If a BSSID matches, but the BSS is found to be not compatible
2795 * the function ignores it and continues to search through the rest of
2796 * the entries in case there is an AP with multiple SSIDs assigned to
2797 * the same BSSID.
2798 */
2799s32
2800mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
2801 u32 mode)
2802{
2803 struct mwifiex_adapter *adapter = priv->adapter;
2804 s32 net = -1;
2805 u32 i;
2806
2807 if (!bssid)
2808 return -1;
2809
2810 dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n",
2811 adapter->num_in_scan_table);
2812
2813 /*
2814 * Look through the scan table for a compatible match. The ret return
2815 * variable will be equal to the index in the scan table (greater
2816 * than zero) if the network is compatible. The loop will continue
2817 * past a matched bssid that is not compatible in case there is an
2818 * AP with multiple SSIDs assigned to the same BSSID
2819 */
2820 for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) {
2821 if (!memcmp
2822 (adapter->scan_table[i].mac_address, bssid, ETH_ALEN)
2823 && mwifiex_get_cfp_by_band_and_channel_from_cfg80211
2824 (priv,
2825 (u8) adapter->
2826 scan_table[i].
2827 bss_band,
2828 (u16) adapter->
2829 scan_table[i].
2830 channel)) {
2831 switch (mode) {
2832 case MWIFIEX_BSS_MODE_INFRA:
2833 case MWIFIEX_BSS_MODE_IBSS:
2834 net = mwifiex_is_network_compatible(priv, i,
2835 mode);
2836 break;
2837 default:
2838 net = i;
2839 break;
2840 }
2841 }
2842 }
2843
2844 return net;
2845}
2846
2847/*
2848 * This function inserts scan command node to the scan pending queue.
2849 */
2850void
2851mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
2852 struct cmd_ctrl_node *cmd_node)
2853{
2854 struct mwifiex_adapter *adapter = priv->adapter;
2855 unsigned long flags;
2856
2857 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2858 list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
2859 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2860}
2861
2862/*
2863 * This function finds an AP with specific ssid in the scan list.
2864 */
2865int mwifiex_find_best_network(struct mwifiex_private *priv,
2866 struct mwifiex_ssid_bssid *req_ssid_bssid)
2867{
2868 struct mwifiex_adapter *adapter = priv->adapter;
2869 struct mwifiex_bssdescriptor *req_bss;
2870 s32 i;
2871
2872 memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
2873
2874 i = mwifiex_find_best_network_in_list(priv);
2875
2876 if (i >= 0) {
2877 req_bss = &adapter->scan_table[i];
2878 memcpy(&req_ssid_bssid->ssid, &req_bss->ssid,
2879 sizeof(struct mwifiex_802_11_ssid));
2880 memcpy((u8 *) &req_ssid_bssid->bssid,
2881 (u8 *) &req_bss->mac_address, ETH_ALEN);
2882
2883 /* Make sure we are in the right mode */
2884 if (priv->bss_mode == MWIFIEX_BSS_MODE_AUTO)
2885 priv->bss_mode = req_bss->bss_mode;
2886 }
2887
2888 if (!req_ssid_bssid->ssid.ssid_len)
2889 return -1;
2890
2891 dev_dbg(adapter->dev, "info: Best network found = [%s], "
2892 "[%pM]\n", req_ssid_bssid->ssid.ssid,
2893 req_ssid_bssid->bssid);
2894
2895 return 0;
2896}
2897
2898/*
2899 * This function sends a scan command for all available channels to the
2900 * firmware, filtered on a specific SSID.
2901 */
2902static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
2903 void *wait_buf, u16 action,
2904 struct mwifiex_802_11_ssid *req_ssid,
2905 struct mwifiex_scan_resp *scan_resp)
2906{
2907 struct mwifiex_adapter *adapter = priv->adapter;
2908 int ret = 0;
2909 struct mwifiex_user_scan_cfg *scan_cfg;
2910
2911 if (!req_ssid)
2912 return -1;
2913
2914 if (action == HostCmd_ACT_GEN_GET) {
2915 if (scan_resp) {
2916 scan_resp->scan_table =
2917 (u8 *) &priv->curr_bss_params.bss_descriptor;
2918 scan_resp->num_in_scan_table =
2919 adapter->num_in_scan_table;
2920 } else {
2921 ret = -1;
2922 }
2923 return ret;
2924 }
2925
2926 if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) {
2927 dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
2928 return ret;
2929 }
2930
2931 if (priv->scan_block && action == HostCmd_ACT_GEN_SET) {
2932 dev_dbg(adapter->dev,
2933 "cmd: Scan is blocked during association...\n");
2934 return ret;
2935 }
2936
2937 mwifiex_scan_delete_ssid_table_entry(priv, req_ssid);
2938
2939 scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
2940 if (!scan_cfg) {
2941 dev_err(adapter->dev, "failed to alloc scan_cfg\n");
2942 return -1;
2943 }
2944
2945 memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
2946 req_ssid->ssid_len);
2947 scan_cfg->keep_previous_scan = true;
2948
2949 ret = mwifiex_scan_networks(priv, wait_buf, action, scan_cfg, NULL);
2950
2951 kfree(scan_cfg);
2952 return ret;
2953}
2954
2955/*
2956 * Sends IOCTL request to start a scan.
2957 *
2958 * This function allocates the IOCTL request buffer, fills it
2959 * with requisite parameters and calls the IOCTL handler.
2960 *
2961 * Scan command can be issued for both normal scan and specific SSID
2962 * scan, depending upon whether an SSID is provided or not.
2963 */
2964int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option,
2965 struct mwifiex_802_11_ssid *req_ssid)
2966{
2967 int ret = 0;
2968 struct mwifiex_wait_queue *wait = NULL;
2969 int status = 0;
2970
2971 if (down_interruptible(&priv->async_sem)) {
2972 dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
2973 __func__);
2974 return -1;
2975 }
2976 priv->scan_pending_on_block = true;
2977
2978 /* Allocate wait request buffer */
2979 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
2980 if (!wait) {
2981 ret = -1;
2982 goto done;
2983 }
2984
2985 if (req_ssid && req_ssid->ssid_len != 0)
2986 /* Specific SSID scan */
2987 status = mwifiex_scan_specific_ssid(priv, wait,
2988 HostCmd_ACT_GEN_SET,
2989 req_ssid, NULL);
2990 else
2991 /* Normal scan */
2992 status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET,
2993 NULL, NULL);
2994 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
2995 if (status == -1)
2996 ret = -1;
2997done:
2998 if ((wait) && (status != -EINPROGRESS))
2999 kfree(wait);
3000 if (ret == -1) {
3001 priv->scan_pending_on_block = false;
3002 up(&priv->async_sem);
3003 }
3004 return ret;
3005}
3006
3007/*
3008 * This function appends the vendor specific IE TLV to a buffer.
3009 */
3010int
3011mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
3012 u16 vsie_mask, u8 **buffer)
3013{
3014 int id, ret_len = 0;
3015 struct mwifiex_ie_types_vendor_param_set *vs_param_set;
3016
3017 if (!buffer)
3018 return 0;
3019 if (!(*buffer))
3020 return 0;
3021
3022 /*
3023 * Traverse through the saved vendor specific IE array and append
3024 * the selected(scan/assoc/adhoc) IE as TLV to the command
3025 */
3026 for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
3027 if (priv->vs_ie[id].mask & vsie_mask) {
3028 vs_param_set =
3029 (struct mwifiex_ie_types_vendor_param_set *)
3030 *buffer;
3031 vs_param_set->header.type =
3032 cpu_to_le16(TLV_TYPE_PASSTHROUGH);
3033 vs_param_set->header.len =
3034 cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
3035 & 0x00FF) + 2);
3036 memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
3037 le16_to_cpu(vs_param_set->header.len));
3038 *buffer += le16_to_cpu(vs_param_set->header.len) +
3039 sizeof(struct mwifiex_ie_types_header);
3040 ret_len += le16_to_cpu(vs_param_set->header.len) +
3041 sizeof(struct mwifiex_ie_types_header);
3042 }
3043 }
3044 return ret_len;
3045}
3046
3047/*
3048 * This function saves a beacon buffer of the current BSS descriptor.
3049 *
3050 * The current beacon buffer is saved so that it can be restored in the
3051 * following cases that makes the beacon buffer not to contain the current
3052 * ssid's beacon buffer.
3053 * - The current ssid was not found somehow in the last scan.
3054 * - The current ssid was the last entry of the scan table and overloaded.
3055 */
3056void
3057mwifiex_save_curr_bcn(struct mwifiex_private *priv)
3058{
3059 struct mwifiex_bssdescriptor *curr_bss =
3060 &priv->curr_bss_params.bss_descriptor;
3061
3062 /* save the beacon buffer if it is not saved or updated */
3063 if ((priv->curr_bcn_buf == NULL) ||
3064 (priv->curr_bcn_size != curr_bss->beacon_buf_size) ||
3065 (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf,
3066 curr_bss->beacon_buf_size))) {
3067
3068 kfree(priv->curr_bcn_buf);
3069 priv->curr_bcn_buf = NULL;
3070
3071 priv->curr_bcn_size = curr_bss->beacon_buf_size;
3072 if (!priv->curr_bcn_size)
3073 return;
3074
3075 priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
3076 GFP_KERNEL);
3077 if (!priv->curr_bcn_buf) {
3078 dev_err(priv->adapter->dev,
3079 "failed to alloc curr_bcn_buf\n");
3080 } else {
3081 memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
3082 curr_bss->beacon_buf_size);
3083 dev_dbg(priv->adapter->dev,
3084 "info: current beacon saved %d\n",
3085 priv->curr_bcn_size);
3086 }
3087 }
3088}
3089
3090/*
3091 * This function frees the current BSS descriptor beacon buffer.
3092 */
3093void
3094mwifiex_free_curr_bcn(struct mwifiex_private *priv)
3095{
3096 kfree(priv->curr_bcn_buf);
3097 priv->curr_bcn_buf = NULL;
3098}
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
new file mode 100644
index 000000000000..f21e5cd19839
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -0,0 +1,1770 @@
1/*
2 * Marvell Wireless LAN device driver: SDIO specific handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include <linux/firmware.h>
21
22#include "decl.h"
23#include "ioctl.h"
24#include "util.h"
25#include "fw.h"
26#include "main.h"
27#include "wmm.h"
28#include "11n.h"
29#include "sdio.h"
30
31
32#define SDIO_VERSION "1.0"
33
34static struct mwifiex_if_ops sdio_ops;
35
36static struct semaphore add_remove_card_sem;
37
38/*
39 * SDIO probe.
40 *
41 * This function probes an mwifiex device and registers it. It allocates
42 * the card structure, enables SDIO function number and initiates the
43 * device registration and initialization procedure by adding a logical
44 * interface.
45 */
46static int
47mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
48{
49 int ret = 0;
50 struct sdio_mmc_card *card = NULL;
51
52 pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
53 func->vendor, func->device, func->class, func->num);
54
55 card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
56 if (!card) {
57 pr_err("%s: failed to alloc memory\n", __func__);
58 return -ENOMEM;
59 }
60
61 card->func = func;
62
63 func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
64
65 sdio_claim_host(func);
66 ret = sdio_enable_func(func);
67 sdio_release_host(func);
68
69 if (ret) {
70 pr_err("%s: failed to enable function\n", __func__);
71 return -EIO;
72 }
73
74 if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
75 pr_err("%s: add card failed\n", __func__);
76 kfree(card);
77 sdio_claim_host(func);
78 ret = sdio_disable_func(func);
79 sdio_release_host(func);
80 ret = -1;
81 }
82
83 return ret;
84}
85
86/*
87 * SDIO remove.
88 *
89 * This function removes the interface and frees up the card structure.
90 */
91static void
92mwifiex_sdio_remove(struct sdio_func *func)
93{
94 struct sdio_mmc_card *card;
95
96 pr_debug("info: SDIO func num=%d\n", func->num);
97
98 if (func) {
99 card = sdio_get_drvdata(func);
100 if (card) {
101 mwifiex_remove_card(card->adapter,
102 &add_remove_card_sem);
103 kfree(card);
104 }
105 }
106}
107
108/*
109 * SDIO suspend.
110 *
111 * Kernel needs to suspend all functions separately. Therefore all
112 * registered functions must have drivers with suspend and resume
113 * methods. Failing that the kernel simply removes the whole card.
114 *
115 * If already not suspended, this function allocates and sends a host
116 * sleep activate request to the firmware and turns off the traffic.
117 */
118static int mwifiex_sdio_suspend(struct device *dev)
119{
120 struct sdio_func *func = dev_to_sdio_func(dev);
121 struct sdio_mmc_card *card;
122 struct mwifiex_adapter *adapter = NULL;
123 mmc_pm_flag_t pm_flag = 0;
124 int hs_actived = 0;
125 int i;
126 int ret = 0;
127
128 if (func) {
129 pm_flag = sdio_get_host_pm_caps(func);
130 pr_debug("cmd: %s: suspend: PM flag = 0x%x\n",
131 sdio_func_id(func), pm_flag);
132 if (!(pm_flag & MMC_PM_KEEP_POWER)) {
133 pr_err("%s: cannot remain alive while host is"
134 " suspended\n", sdio_func_id(func));
135 return -ENOSYS;
136 }
137
138 card = sdio_get_drvdata(func);
139 if (!card || !card->adapter) {
140 pr_err("suspend: invalid card or adapter\n");
141 return 0;
142 }
143 } else {
144 pr_err("suspend: sdio_func is not specified\n");
145 return 0;
146 }
147
148 adapter = card->adapter;
149
150 /* Enable the Host Sleep */
151 hs_actived = mwifiex_enable_hs(adapter);
152 if (hs_actived) {
153 pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n");
154 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
155 }
156
157 /* Indicate device suspended */
158 adapter->is_suspended = true;
159
160 for (i = 0; i < adapter->priv_num; i++)
161 netif_carrier_off(adapter->priv[i]->netdev);
162
163 return ret;
164}
165
166/*
167 * SDIO resume.
168 *
169 * Kernel needs to suspend all functions separately. Therefore all
170 * registered functions must have drivers with suspend and resume
171 * methods. Failing that the kernel simply removes the whole card.
172 *
173 * If already not resumed, this function turns on the traffic and
174 * sends a host sleep cancel request to the firmware.
175 */
176static int mwifiex_sdio_resume(struct device *dev)
177{
178 struct sdio_func *func = dev_to_sdio_func(dev);
179 struct sdio_mmc_card *card;
180 struct mwifiex_adapter *adapter = NULL;
181 mmc_pm_flag_t pm_flag = 0;
182 int i;
183
184 if (func) {
185 pm_flag = sdio_get_host_pm_caps(func);
186 card = sdio_get_drvdata(func);
187 if (!card || !card->adapter) {
188 pr_err("resume: invalid card or adapter\n");
189 return 0;
190 }
191 } else {
192 pr_err("resume: sdio_func is not specified\n");
193 return 0;
194 }
195
196 adapter = card->adapter;
197
198 if (!adapter->is_suspended) {
199 dev_warn(adapter->dev, "device already resumed\n");
200 return 0;
201 }
202
203 adapter->is_suspended = false;
204
205 for (i = 0; i < adapter->priv_num; i++)
206 if (adapter->priv[i]->media_connected)
207 netif_carrier_on(adapter->priv[i]->netdev);
208
209 /* Disable Host Sleep */
210 mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
211 MWIFIEX_NO_WAIT);
212
213 return 0;
214}
215
216/* Device ID for SD8787 */
217#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
218
219/* WLAN IDs */
220static const struct sdio_device_id mwifiex_ids[] = {
221 {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
222 {},
223};
224
225MODULE_DEVICE_TABLE(sdio, mwifiex_ids);
226
227static const struct dev_pm_ops mwifiex_sdio_pm_ops = {
228 .suspend = mwifiex_sdio_suspend,
229 .resume = mwifiex_sdio_resume,
230};
231
232static struct sdio_driver mwifiex_sdio = {
233 .name = "mwifiex_sdio",
234 .id_table = mwifiex_ids,
235 .probe = mwifiex_sdio_probe,
236 .remove = mwifiex_sdio_remove,
237 .drv = {
238 .owner = THIS_MODULE,
239 .pm = &mwifiex_sdio_pm_ops,
240 }
241};
242
243/*
244 * This function writes data into SDIO card register.
245 */
246static int
247mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data)
248{
249 struct sdio_mmc_card *card = adapter->card;
250 int ret = -1;
251
252 sdio_claim_host(card->func);
253 sdio_writeb(card->func, (u8) data, reg, &ret);
254 sdio_release_host(card->func);
255
256 return ret;
257}
258
259/*
260 * This function reads data from SDIO card register.
261 */
262static int
263mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data)
264{
265 struct sdio_mmc_card *card = adapter->card;
266 int ret = -1;
267 u8 val;
268
269 sdio_claim_host(card->func);
270 val = sdio_readb(card->func, reg, &ret);
271 sdio_release_host(card->func);
272
273 *data = val;
274
275 return ret;
276}
277
278/*
279 * This function writes multiple data into SDIO card memory.
280 *
281 * This does not work in suspended mode.
282 */
283static int
284mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
285 u8 *buffer, u32 pkt_len, u32 port, u32 timeout)
286{
287 struct sdio_mmc_card *card = adapter->card;
288 int ret = -1;
289 u8 blk_mode =
290 (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
291 u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
292 u32 blk_cnt =
293 (blk_mode ==
294 BLOCK_MODE) ? (pkt_len /
295 MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len;
296 u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
297
298 if (adapter->is_suspended) {
299 dev_err(adapter->dev,
300 "%s: not allowed while suspended\n", __func__);
301 return -1;
302 }
303
304 sdio_claim_host(card->func);
305
306 if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size))
307 ret = 0;
308
309 sdio_release_host(card->func);
310
311 return ret;
312}
313
314/*
315 * This function reads multiple data from SDIO card memory.
316 */
317static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter,
318 u8 *buffer, u32 len,
319 u32 port, u32 timeout, u8 claim)
320{
321 struct sdio_mmc_card *card = adapter->card;
322 int ret = -1;
323 u8 blk_mode =
324 (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
325 u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
326 u32 blk_cnt =
327 (blk_mode ==
328 BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len;
329 u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
330
331 if (claim)
332 sdio_claim_host(card->func);
333
334 if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size))
335 ret = 0;
336
337 if (claim)
338 sdio_release_host(card->func);
339
340 return ret;
341}
342
343/*
344 * This function wakes up the card.
345 *
346 * A host power up command is written to the card configuration
347 * register to wake up the card.
348 */
349static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
350{
351 int ret;
352
353 dev_dbg(adapter->dev, "event: wakeup device...\n");
354 ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
355
356 return ret;
357}
358
359/*
360 * This function is called after the card has woken up.
361 *
362 * The card configuration register is reset.
363 */
364static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
365{
366 int ret;
367
368 dev_dbg(adapter->dev, "cmd: wakeup device completed\n");
369 ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
370
371 return ret;
372}
373
374/*
375 * This function initializes the IO ports.
376 *
377 * The following operations are performed -
378 * - Read the IO ports (0, 1 and 2)
379 * - Set host interrupt Reset-To-Read to clear
380 * - Set auto re-enable interrupt
381 */
382static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
383{
384 u32 reg;
385
386 adapter->ioport = 0;
387
388 /* Read the IO port */
389 if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, &reg))
390 adapter->ioport |= (reg & 0xff);
391 else
392 return -1;
393
394 if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, &reg))
395 adapter->ioport |= ((reg & 0xff) << 8);
396 else
397 return -1;
398
399 if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, &reg))
400 adapter->ioport |= ((reg & 0xff) << 16);
401 else
402 return -1;
403
404 pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
405
406 /* Set Host interrupt reset to read to clear */
407 if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, &reg))
408 mwifiex_write_reg(adapter, HOST_INT_RSR_REG,
409 reg | SDIO_INT_MASK);
410 else
411 return -1;
412
413 /* Dnld/Upld ready set to auto reset */
414 if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, &reg))
415 mwifiex_write_reg(adapter, CARD_MISC_CFG_REG,
416 reg | AUTO_RE_ENABLE_INT);
417 else
418 return -1;
419
420 return 0;
421}
422
423/*
424 * This function sends data to the card.
425 */
426static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
427 u8 *payload, u32 pkt_len, u32 port)
428{
429 u32 i = 0;
430 int ret = 0;
431
432 do {
433 ret = mwifiex_write_data_sync(adapter, payload, pkt_len,
434 port, 0);
435 if (ret) {
436 i++;
437 dev_err(adapter->dev, "host_to_card, write iomem"
438 " (%d) failed: %d\n", i, ret);
439 if (mwifiex_write_reg(adapter,
440 CONFIGURATION_REG, 0x04))
441 dev_err(adapter->dev, "write CFG reg failed\n");
442
443 ret = -1;
444 if (i > MAX_WRITE_IOMEM_RETRY)
445 return ret;
446 }
447 } while (ret == -1);
448
449 return ret;
450}
451
452/*
453 * This function gets the read port.
454 *
455 * If control port bit is set in MP read bitmap, the control port
456 * is returned, otherwise the current read port is returned and
457 * the value is increased (provided it does not reach the maximum
458 * limit, in which case it is reset to 1)
459 */
460static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
461{
462 struct sdio_mmc_card *card = adapter->card;
463 u16 rd_bitmap = card->mp_rd_bitmap;
464
465 dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap);
466
467 if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK)))
468 return -1;
469
470 if (card->mp_rd_bitmap & CTRL_PORT_MASK) {
471 card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK);
472 *port = CTRL_PORT;
473 dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n",
474 *port, card->mp_rd_bitmap);
475 } else {
476 if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) {
477 card->mp_rd_bitmap &=
478 (u16) (~(1 << card->curr_rd_port));
479 *port = card->curr_rd_port;
480
481 if (++card->curr_rd_port == MAX_PORT)
482 card->curr_rd_port = 1;
483 } else {
484 return -1;
485 }
486
487 dev_dbg(adapter->dev,
488 "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n",
489 *port, rd_bitmap, card->mp_rd_bitmap);
490 }
491 return 0;
492}
493
494/*
495 * This function gets the write port for data.
496 *
497 * The current write port is returned if available and the value is
498 * increased (provided it does not reach the maximum limit, in which
499 * case it is reset to 1)
500 */
501static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
502{
503 struct sdio_mmc_card *card = adapter->card;
504 u16 wr_bitmap = card->mp_wr_bitmap;
505
506 dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap);
507
508 if (!(wr_bitmap & card->mp_data_port_mask))
509 return -1;
510
511 if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
512 card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port));
513 *port = card->curr_wr_port;
514 if (++card->curr_wr_port == card->mp_end_port)
515 card->curr_wr_port = 1;
516 } else {
517 adapter->data_sent = true;
518 return -EBUSY;
519 }
520
521 if (*port == CTRL_PORT) {
522 dev_err(adapter->dev, "invalid data port=%d cur port=%d"
523 " mp_wr_bitmap=0x%04x -> 0x%04x\n",
524 *port, card->curr_wr_port, wr_bitmap,
525 card->mp_wr_bitmap);
526 return -1;
527 }
528
529 dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n",
530 *port, wr_bitmap, card->mp_wr_bitmap);
531
532 return 0;
533}
534
535/*
536 * This function polls the card status.
537 */
538static int
539mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
540{
541 u32 tries;
542 u32 cs = 0;
543
544 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
545 if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs))
546 break;
547 else if ((cs & bits) == bits)
548 return 0;
549
550 udelay(10);
551 }
552
553 dev_err(adapter->dev, "poll card status failed, tries = %d\n",
554 tries);
555 return -1;
556}
557
558/*
559 * This function reads the firmware status.
560 */
561static int
562mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
563{
564 u32 fws0 = 0, fws1 = 0;
565
566 if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0))
567 return -1;
568
569 if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1))
570 return -1;
571
572 *dat = (u16) ((fws1 << 8) | fws0);
573
574 return 0;
575}
576
577/*
578 * This function disables the host interrupt.
579 *
580 * The host interrupt mask is read, the disable bit is reset and
581 * written back to the card host interrupt mask register.
582 */
583static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
584{
585 u32 host_int_mask = 0;
586
587 /* Read back the host_int_mask register */
588 if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
589 return -1;
590
591 /* Update with the mask and write back to the register */
592 host_int_mask &= ~HOST_INT_DISABLE;
593
594 if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
595 dev_err(adapter->dev, "disable host interrupt failed\n");
596 return -1;
597 }
598
599 return 0;
600}
601
602/*
603 * This function enables the host interrupt.
604 *
605 * The host interrupt enable mask is written to the card
606 * host interrupt mask register.
607 */
608static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
609{
610 /* Simply write the mask to the register */
611 if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) {
612 dev_err(adapter->dev, "enable host interrupt failed\n");
613 return -1;
614 }
615 return 0;
616}
617
618/*
619 * This function sends a data buffer to the card.
620 */
621static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
622 u32 *type, u8 *buffer,
623 u32 npayload, u32 ioport)
624{
625 int ret = 0;
626 u32 nb;
627
628 if (!buffer) {
629 dev_err(adapter->dev, "%s: buffer is NULL\n", __func__);
630 return -1;
631 }
632
633 ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1);
634
635 if (ret) {
636 dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
637 ret);
638 return -1;
639 }
640
641 nb = le16_to_cpu(*(__le16 *) (buffer));
642 if (nb > npayload) {
643 dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n",
644 __func__, nb, npayload);
645 return -1;
646 }
647
648 *type = le16_to_cpu(*(__le16 *) (buffer + 2));
649
650 return ret;
651}
652
653/*
654 * This function downloads the firmware to the card.
655 *
656 * Firmware is downloaded to the card in blocks. Every block download
657 * is tested for CRC errors, and retried a number of times before
658 * returning failure.
659 */
660static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
661 struct mwifiex_fw_image *fw)
662{
663 int ret = 0;
664 u8 *firmware = fw->fw_buf;
665 u32 firmware_len = fw->fw_len;
666 u32 offset = 0;
667 u32 base0, base1;
668 u8 *fwbuf;
669 u16 len = 0;
670 u32 txlen = 0, tx_blocks = 0, tries = 0;
671 u32 i = 0;
672
673 if (!firmware_len) {
674 dev_err(adapter->dev, "firmware image not found!"
675 " Terminating download\n");
676 return -1;
677 }
678
679 dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n",
680 firmware_len);
681
682 /* Assume that the allocated buffer is 8-byte aligned */
683 fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
684 if (!fwbuf) {
685 dev_err(adapter->dev, "unable to alloc buffer for firmware."
686 " Terminating download\n");
687 return -1;
688 }
689
690 /* Perform firmware data transfer */
691 do {
692 /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY
693 bits */
694 ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY |
695 DN_LD_CARD_RDY);
696 if (ret) {
697 dev_err(adapter->dev, "FW download with helper:"
698 " poll status timeout @ %d\n", offset);
699 goto done;
700 }
701
702 /* More data? */
703 if (offset >= firmware_len)
704 break;
705
706 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
707 ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0,
708 &base0);
709 if (ret) {
710 dev_err(adapter->dev, "dev BASE0 register read"
711 " failed: base0=0x%04X(%d). Terminating "
712 "download\n", base0, base0);
713 goto done;
714 }
715 ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1,
716 &base1);
717 if (ret) {
718 dev_err(adapter->dev, "dev BASE1 register read"
719 " failed: base1=0x%04X(%d). Terminating "
720 "download\n", base1, base1);
721 goto done;
722 }
723 len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
724
725 if (len)
726 break;
727
728 udelay(10);
729 }
730
731 if (!len) {
732 break;
733 } else if (len > MWIFIEX_UPLD_SIZE) {
734 dev_err(adapter->dev, "FW download failed @ %d,"
735 " invalid length %d\n", offset, len);
736 ret = -1;
737 goto done;
738 }
739
740 txlen = len;
741
742 if (len & BIT(0)) {
743 i++;
744 if (i > MAX_WRITE_IOMEM_RETRY) {
745 dev_err(adapter->dev, "FW download failed @"
746 " %d, over max retry count\n", offset);
747 ret = -1;
748 goto done;
749 }
750 dev_err(adapter->dev, "CRC indicated by the helper:"
751 " len = 0x%04X, txlen = %d\n", len, txlen);
752 len &= ~BIT(0);
753 /* Setting this to 0 to resend from same offset */
754 txlen = 0;
755 } else {
756 i = 0;
757
758 /* Set blocksize to transfer - checking for last
759 block */
760 if (firmware_len - offset < txlen)
761 txlen = firmware_len - offset;
762
763 tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE -
764 1) / MWIFIEX_SDIO_BLOCK_SIZE;
765
766 /* Copy payload to buffer */
767 memmove(fwbuf, &firmware[offset], txlen);
768 }
769
770 ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks *
771 MWIFIEX_SDIO_BLOCK_SIZE,
772 adapter->ioport, 0);
773 if (ret) {
774 dev_err(adapter->dev, "FW download, write iomem (%d)"
775 " failed @ %d\n", i, offset);
776 if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
777 dev_err(adapter->dev, "write CFG reg failed\n");
778
779 ret = -1;
780 goto done;
781 }
782
783 offset += txlen;
784 } while (true);
785
786 dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n",
787 offset);
788
789 ret = 0;
790done:
791 kfree(fwbuf);
792 return ret;
793}
794
795/*
796 * This function checks the firmware status in card.
797 *
798 * The winner interface is also determined by this function.
799 */
800static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
801 u32 poll_num, int *winner)
802{
803 int ret = 0;
804 u16 firmware_stat;
805 u32 tries;
806 u32 winner_status;
807
808 /* Wait for firmware initialization event */
809 for (tries = 0; tries < poll_num; tries++) {
810 ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
811 if (ret)
812 continue;
813 if (firmware_stat == FIRMWARE_READY) {
814 ret = 0;
815 break;
816 } else {
817 mdelay(100);
818 ret = -1;
819 }
820 }
821
822 if (winner && ret) {
823 if (mwifiex_read_reg
824 (adapter, CARD_FW_STATUS0_REG, &winner_status))
825 winner_status = 0;
826
827 if (winner_status)
828 *winner = 0;
829 else
830 *winner = 1;
831 }
832 return ret;
833}
834
835/*
836 * This function reads the interrupt status from card.
837 */
838static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
839{
840 struct sdio_mmc_card *card = adapter->card;
841 u32 sdio_ireg = 0;
842 unsigned long flags;
843
844 if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
845 REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0,
846 0)) {
847 dev_err(adapter->dev, "read mp_regs failed\n");
848 return;
849 }
850
851 sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
852 if (sdio_ireg) {
853 /*
854 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
855 * Clear the interrupt status register
856 */
857 dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
858 spin_lock_irqsave(&adapter->int_lock, flags);
859 adapter->int_status |= sdio_ireg;
860 spin_unlock_irqrestore(&adapter->int_lock, flags);
861 }
862
863 return;
864}
865
866/*
867 * SDIO interrupt handler.
868 *
869 * This function reads the interrupt status from firmware and assigns
870 * the main process in workqueue which will handle the interrupt.
871 */
872static void
873mwifiex_sdio_interrupt(struct sdio_func *func)
874{
875 struct mwifiex_adapter *adapter;
876 struct sdio_mmc_card *card;
877
878 card = sdio_get_drvdata(func);
879 if (!card || !card->adapter) {
880 pr_debug("int: func=%p card=%p adapter=%p\n",
881 func, card, card ? card->adapter : NULL);
882 return;
883 }
884 adapter = card->adapter;
885
886 if (adapter->surprise_removed)
887 return;
888
889 if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
890 adapter->ps_state = PS_STATE_AWAKE;
891
892 mwifiex_interrupt_status(adapter);
893 queue_work(adapter->workqueue, &adapter->main_work);
894
895 return;
896}
897
898/*
899 * This function decodes a received packet.
900 *
901 * Based on the type, the packet is treated as either a data, or
902 * a command response, or an event, and the correct handler
903 * function is invoked.
904 */
905static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
906 struct sk_buff *skb, u32 upld_typ)
907{
908 u8 *cmd_buf;
909
910 skb_pull(skb, INTF_HEADER_LEN);
911
912 switch (upld_typ) {
913 case MWIFIEX_TYPE_DATA:
914 dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
915 mwifiex_handle_rx_packet(adapter, skb);
916 break;
917
918 case MWIFIEX_TYPE_CMD:
919 dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n");
920 /* take care of curr_cmd = NULL case */
921 if (!adapter->curr_cmd) {
922 cmd_buf = adapter->upld_buf;
923
924 if (adapter->ps_state == PS_STATE_SLEEP_CFM)
925 mwifiex_process_sleep_confirm_resp(adapter,
926 skb->data, skb->len);
927
928 memcpy(cmd_buf, skb->data, min_t(u32,
929 MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
930
931 dev_kfree_skb_any(skb);
932 } else {
933 adapter->cmd_resp_received = true;
934 adapter->curr_cmd->resp_skb = skb;
935 }
936 break;
937
938 case MWIFIEX_TYPE_EVENT:
939 dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
940 adapter->event_cause = *(u32 *) skb->data;
941
942 skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
943
944 if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE))
945 memcpy(adapter->event_body, skb->data, skb->len);
946
947 /* event cause has been saved to adapter->event_cause */
948 adapter->event_received = true;
949 adapter->event_skb = skb;
950
951 break;
952
953 default:
954 dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ);
955 dev_kfree_skb_any(skb);
956 break;
957 }
958
959 return 0;
960}
961
962/*
963 * This function transfers received packets from card to driver, performing
964 * aggregation if required.
965 *
966 * For data received on control port, or if aggregation is disabled, the
967 * received buffers are uploaded as separate packets. However, if aggregation
968 * is enabled and required, the buffers are copied onto an aggregation buffer,
969 * provided there is space left, processed and finally uploaded.
970 */
971static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
972 struct sk_buff *skb, u8 port)
973{
974 struct sdio_mmc_card *card = adapter->card;
975 s32 f_do_rx_aggr = 0;
976 s32 f_do_rx_cur = 0;
977 s32 f_aggr_cur = 0;
978 struct sk_buff *skb_deaggr;
979 u32 pind = 0;
980 u32 pkt_len, pkt_type = 0;
981 u8 *curr_ptr;
982 u32 rx_len = skb->len;
983
984 if (port == CTRL_PORT) {
985 /* Read the command Resp without aggr */
986 dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
987 "response\n", __func__);
988
989 f_do_rx_cur = 1;
990 goto rx_curr_single;
991 }
992
993 if (!card->mpa_rx.enabled) {
994 dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n",
995 __func__);
996
997 f_do_rx_cur = 1;
998 goto rx_curr_single;
999 }
1000
1001 if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) {
1002 /* Some more data RX pending */
1003 dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
1004
1005 if (MP_RX_AGGR_IN_PROGRESS(card)) {
1006 if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) {
1007 f_aggr_cur = 1;
1008 } else {
1009 /* No room in Aggr buf, do rx aggr now */
1010 f_do_rx_aggr = 1;
1011 f_do_rx_cur = 1;
1012 }
1013 } else {
1014 /* Rx aggr not in progress */
1015 f_aggr_cur = 1;
1016 }
1017
1018 } else {
1019 /* No more data RX pending */
1020 dev_dbg(adapter->dev, "info: %s: last packet\n", __func__);
1021
1022 if (MP_RX_AGGR_IN_PROGRESS(card)) {
1023 f_do_rx_aggr = 1;
1024 if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len))
1025 f_aggr_cur = 1;
1026 else
1027 /* No room in Aggr buf, do rx aggr now */
1028 f_do_rx_cur = 1;
1029 } else {
1030 f_do_rx_cur = 1;
1031 }
1032 }
1033
1034 if (f_aggr_cur) {
1035 dev_dbg(adapter->dev, "info: current packet aggregation\n");
1036 /* Curr pkt can be aggregated */
1037 MP_RX_AGGR_SETUP(card, skb, port);
1038
1039 if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
1040 MP_RX_AGGR_PORT_LIMIT_REACHED(card)) {
1041 dev_dbg(adapter->dev, "info: %s: aggregated packet "
1042 "limit reached\n", __func__);
1043 /* No more pkts allowed in Aggr buf, rx it */
1044 f_do_rx_aggr = 1;
1045 }
1046 }
1047
1048 if (f_do_rx_aggr) {
1049 /* do aggr RX now */
1050 dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
1051 card->mpa_rx.pkt_cnt);
1052
1053 if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
1054 card->mpa_rx.buf_len,
1055 (adapter->ioport | 0x1000 |
1056 (card->mpa_rx.ports << 4)) +
1057 card->mpa_rx.start_port, 0, 1))
1058 return -1;
1059
1060 curr_ptr = card->mpa_rx.buf;
1061
1062 for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) {
1063
1064 /* get curr PKT len & type */
1065 pkt_len = *(u16 *) &curr_ptr[0];
1066 pkt_type = *(u16 *) &curr_ptr[2];
1067
1068 /* copy pkt to deaggr buf */
1069 skb_deaggr = card->mpa_rx.skb_arr[pind];
1070
1071 if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <=
1072 card->mpa_rx.len_arr[pind])) {
1073
1074 memcpy(skb_deaggr->data, curr_ptr, pkt_len);
1075
1076 skb_trim(skb_deaggr, pkt_len);
1077
1078 /* Process de-aggr packet */
1079 mwifiex_decode_rx_packet(adapter, skb_deaggr,
1080 pkt_type);
1081 } else {
1082 dev_err(adapter->dev, "wrong aggr pkt:"
1083 " type=%d len=%d max_len=%d\n",
1084 pkt_type, pkt_len,
1085 card->mpa_rx.len_arr[pind]);
1086 dev_kfree_skb_any(skb_deaggr);
1087 }
1088 curr_ptr += card->mpa_rx.len_arr[pind];
1089 }
1090 MP_RX_AGGR_BUF_RESET(card);
1091 }
1092
1093rx_curr_single:
1094 if (f_do_rx_cur) {
1095 dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n",
1096 port, rx_len);
1097
1098 if (mwifiex_sdio_card_to_host(adapter, &pkt_type,
1099 skb->data, skb->len,
1100 adapter->ioport + port))
1101 return -1;
1102
1103 mwifiex_decode_rx_packet(adapter, skb, pkt_type);
1104 }
1105
1106 return 0;
1107}
1108
1109/*
1110 * This function checks the current interrupt status.
1111 *
1112 * The following interrupts are checked and handled by this function -
1113 * - Data sent
1114 * - Command sent
1115 * - Packets received
1116 *
1117 * Since the firmware does not generate download ready interrupt if the
1118 * port updated is command port only, command sent interrupt checking
1119 * should be done manually, and for every SDIO interrupt.
1120 *
1121 * In case of Rx packets received, the packets are uploaded from card to
1122 * host and processed accordingly.
1123 */
1124static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
1125{
1126 struct sdio_mmc_card *card = adapter->card;
1127 int ret = 0;
1128 u8 sdio_ireg;
1129 struct sk_buff *skb = NULL;
1130 u8 port = CTRL_PORT;
1131 u32 len_reg_l, len_reg_u;
1132 u32 rx_blocks;
1133 u16 rx_len;
1134 unsigned long flags;
1135
1136 spin_lock_irqsave(&adapter->int_lock, flags);
1137 sdio_ireg = adapter->int_status;
1138 adapter->int_status = 0;
1139 spin_unlock_irqrestore(&adapter->int_lock, flags);
1140
1141 if (!sdio_ireg)
1142 return ret;
1143
1144 if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
1145 card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8;
1146 card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L];
1147 dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n",
1148 card->mp_wr_bitmap);
1149 if (adapter->data_sent &&
1150 (card->mp_wr_bitmap & card->mp_data_port_mask)) {
1151 dev_dbg(adapter->dev,
1152 "info: <--- Tx DONE Interrupt --->\n");
1153 adapter->data_sent = false;
1154 }
1155 }
1156
1157 /* As firmware will not generate download ready interrupt if the port
1158 updated is command port only, cmd_sent should be done for any SDIO
1159 interrupt. */
1160 if (adapter->cmd_sent) {
1161 /* Check if firmware has attach buffer at command port and
1162 update just that in wr_bit_map. */
1163 card->mp_wr_bitmap |=
1164 (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
1165 if (card->mp_wr_bitmap & CTRL_PORT_MASK)
1166 adapter->cmd_sent = false;
1167 }
1168
1169 dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
1170 adapter->cmd_sent, adapter->data_sent);
1171 if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
1172 card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8;
1173 card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L];
1174 dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n",
1175 card->mp_rd_bitmap);
1176
1177 while (true) {
1178 ret = mwifiex_get_rd_port(adapter, &port);
1179 if (ret) {
1180 dev_dbg(adapter->dev,
1181 "info: no more rd_port available\n");
1182 break;
1183 }
1184 len_reg_l = RD_LEN_P0_L + (port << 1);
1185 len_reg_u = RD_LEN_P0_U + (port << 1);
1186 rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
1187 rx_len |= (u16) card->mp_regs[len_reg_l];
1188 dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
1189 port, rx_len);
1190 rx_blocks =
1191 (rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
1192 1) / MWIFIEX_SDIO_BLOCK_SIZE;
1193 if (rx_len <= INTF_HEADER_LEN
1194 || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
1195 MWIFIEX_RX_DATA_BUF_SIZE) {
1196 dev_err(adapter->dev, "invalid rx_len=%d\n",
1197 rx_len);
1198 return -1;
1199 }
1200 rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
1201
1202 skb = dev_alloc_skb(rx_len);
1203
1204 if (!skb) {
1205 dev_err(adapter->dev, "%s: failed to alloc skb",
1206 __func__);
1207 return -1;
1208 }
1209
1210 skb_put(skb, rx_len);
1211
1212 dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n",
1213 rx_len, skb->len);
1214
1215 if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb,
1216 port)) {
1217 u32 cr = 0;
1218
1219 dev_err(adapter->dev, "card_to_host_mpa failed:"
1220 " int status=%#x\n", sdio_ireg);
1221 if (mwifiex_read_reg(adapter,
1222 CONFIGURATION_REG, &cr))
1223 dev_err(adapter->dev,
1224 "read CFG reg failed\n");
1225
1226 dev_dbg(adapter->dev,
1227 "info: CFG reg val = %d\n", cr);
1228 if (mwifiex_write_reg(adapter,
1229 CONFIGURATION_REG,
1230 (cr | 0x04)))
1231 dev_err(adapter->dev,
1232 "write CFG reg failed\n");
1233
1234 dev_dbg(adapter->dev, "info: write success\n");
1235 if (mwifiex_read_reg(adapter,
1236 CONFIGURATION_REG, &cr))
1237 dev_err(adapter->dev,
1238 "read CFG reg failed\n");
1239
1240 dev_dbg(adapter->dev,
1241 "info: CFG reg val =%x\n", cr);
1242 dev_kfree_skb_any(skb);
1243 return -1;
1244 }
1245 }
1246 }
1247
1248 return 0;
1249}
1250
1251/*
1252 * This function aggregates transmission buffers in driver and downloads
1253 * the aggregated packet to card.
1254 *
1255 * The individual packets are aggregated by copying into an aggregation
1256 * buffer and then downloaded to the card. Previous unsent packets in the
1257 * aggregation buffer are pre-copied first before new packets are added.
1258 * Aggregation is done till there is space left in the aggregation buffer,
1259 * or till new packets are available.
1260 *
1261 * The function will only download the packet to the card when aggregation
1262 * stops, otherwise it will just aggregate the packet in aggregation buffer
1263 * and return.
1264 */
1265static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
1266 u8 *payload, u32 pkt_len, u8 port,
1267 u32 next_pkt_len)
1268{
1269 struct sdio_mmc_card *card = adapter->card;
1270 int ret = 0;
1271 s32 f_send_aggr_buf = 0;
1272 s32 f_send_cur_buf = 0;
1273 s32 f_precopy_cur_buf = 0;
1274 s32 f_postcopy_cur_buf = 0;
1275
1276 if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) {
1277 dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
1278 __func__);
1279
1280 f_send_cur_buf = 1;
1281 goto tx_curr_single;
1282 }
1283
1284 if (next_pkt_len) {
1285 /* More pkt in TX queue */
1286 dev_dbg(adapter->dev, "info: %s: more packets in queue.\n",
1287 __func__);
1288
1289 if (MP_TX_AGGR_IN_PROGRESS(card)) {
1290 if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) &&
1291 MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
1292 f_precopy_cur_buf = 1;
1293
1294 if (!(card->mp_wr_bitmap &
1295 (1 << card->curr_wr_port))
1296 || !MP_TX_AGGR_BUF_HAS_ROOM(
1297 card, next_pkt_len))
1298 f_send_aggr_buf = 1;
1299 } else {
1300 /* No room in Aggr buf, send it */
1301 f_send_aggr_buf = 1;
1302
1303 if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) ||
1304 !(card->mp_wr_bitmap &
1305 (1 << card->curr_wr_port)))
1306 f_send_cur_buf = 1;
1307 else
1308 f_postcopy_cur_buf = 1;
1309 }
1310 } else {
1311 if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)
1312 && (card->mp_wr_bitmap & (1 << card->curr_wr_port)))
1313 f_precopy_cur_buf = 1;
1314 else
1315 f_send_cur_buf = 1;
1316 }
1317 } else {
1318 /* Last pkt in TX queue */
1319 dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n",
1320 __func__);
1321
1322 if (MP_TX_AGGR_IN_PROGRESS(card)) {
1323 /* some packs in Aggr buf already */
1324 f_send_aggr_buf = 1;
1325
1326 if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len))
1327 f_precopy_cur_buf = 1;
1328 else
1329 /* No room in Aggr buf, send it */
1330 f_send_cur_buf = 1;
1331 } else {
1332 f_send_cur_buf = 1;
1333 }
1334 }
1335
1336 if (f_precopy_cur_buf) {
1337 dev_dbg(adapter->dev, "data: %s: precopy current buffer\n",
1338 __func__);
1339 MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
1340
1341 if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
1342 MP_TX_AGGR_PORT_LIMIT_REACHED(card))
1343 /* No more pkts allowed in Aggr buf, send it */
1344 f_send_aggr_buf = 1;
1345 }
1346
1347 if (f_send_aggr_buf) {
1348 dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
1349 __func__,
1350 card->mpa_tx.start_port, card->mpa_tx.ports);
1351 ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
1352 card->mpa_tx.buf_len,
1353 (adapter->ioport | 0x1000 |
1354 (card->mpa_tx.ports << 4)) +
1355 card->mpa_tx.start_port);
1356
1357 MP_TX_AGGR_BUF_RESET(card);
1358 }
1359
1360tx_curr_single:
1361 if (f_send_cur_buf) {
1362 dev_dbg(adapter->dev, "data: %s: send current buffer %d\n",
1363 __func__, port);
1364 ret = mwifiex_write_data_to_card(adapter, payload, pkt_len,
1365 adapter->ioport + port);
1366 }
1367
1368 if (f_postcopy_cur_buf) {
1369 dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n",
1370 __func__);
1371 MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
1372 }
1373
1374 return ret;
1375}
1376
1377/*
1378 * This function downloads data from driver to card.
1379 *
1380 * Both commands and data packets are transferred to the card by this
1381 * function.
1382 *
1383 * This function adds the SDIO specific header to the front of the buffer
1384 * before transferring. The header contains the length of the packet and
1385 * the type. The firmware handles the packets based upon this set type.
1386 */
1387static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
1388 u8 type, u8 *payload, u32 pkt_len,
1389 struct mwifiex_tx_param *tx_param)
1390{
1391 struct sdio_mmc_card *card = adapter->card;
1392 int ret = 0;
1393 u32 buf_block_len;
1394 u32 blk_size;
1395 u8 port = CTRL_PORT;
1396
1397 /* Allocate buffer and copy payload */
1398 blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
1399 buf_block_len = (pkt_len + blk_size - 1) / blk_size;
1400 *(u16 *) &payload[0] = (u16) pkt_len;
1401 *(u16 *) &payload[2] = type;
1402
1403 /*
1404 * This is SDIO specific header
1405 * u16 length,
1406 * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1,
1407 * MWIFIEX_TYPE_EVENT = 3)
1408 */
1409 if (type == MWIFIEX_TYPE_DATA) {
1410 ret = mwifiex_get_wr_port_data(adapter, &port);
1411 if (ret) {
1412 dev_err(adapter->dev, "%s: no wr_port available\n",
1413 __func__);
1414 return ret;
1415 }
1416 } else {
1417 adapter->cmd_sent = true;
1418 /* Type must be MWIFIEX_TYPE_CMD */
1419
1420 if (pkt_len <= INTF_HEADER_LEN ||
1421 pkt_len > MWIFIEX_UPLD_SIZE)
1422 dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
1423 __func__, payload, pkt_len);
1424 }
1425
1426 /* Transfer data to card */
1427 pkt_len = buf_block_len * blk_size;
1428
1429 if (tx_param)
1430 ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
1431 port, tx_param->next_pkt_len);
1432 else
1433 ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
1434 port, 0);
1435
1436 if (ret) {
1437 if (type == MWIFIEX_TYPE_CMD)
1438 adapter->cmd_sent = false;
1439 if (type == MWIFIEX_TYPE_DATA)
1440 adapter->data_sent = false;
1441 } else {
1442 if (type == MWIFIEX_TYPE_DATA) {
1443 if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port)))
1444 adapter->data_sent = true;
1445 else
1446 adapter->data_sent = false;
1447 }
1448 }
1449
1450 return ret;
1451}
1452
1453/*
1454 * This function allocates the MPA Tx and Rx buffers.
1455 */
1456static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
1457 u32 mpa_tx_buf_size, u32 mpa_rx_buf_size)
1458{
1459 struct sdio_mmc_card *card = adapter->card;
1460 int ret = 0;
1461
1462 card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL);
1463 if (!card->mpa_tx.buf) {
1464 dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n");
1465 ret = -1;
1466 goto error;
1467 }
1468
1469 card->mpa_tx.buf_size = mpa_tx_buf_size;
1470
1471 card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL);
1472 if (!card->mpa_rx.buf) {
1473 dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n");
1474 ret = -1;
1475 goto error;
1476 }
1477
1478 card->mpa_rx.buf_size = mpa_rx_buf_size;
1479
1480error:
1481 if (ret) {
1482 kfree(card->mpa_tx.buf);
1483 kfree(card->mpa_rx.buf);
1484 }
1485
1486 return ret;
1487}
1488
1489/*
1490 * This function unregisters the SDIO device.
1491 *
1492 * The SDIO IRQ is released, the function is disabled and driver
1493 * data is set to null.
1494 */
1495static void
1496mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
1497{
1498 struct sdio_mmc_card *card = adapter->card;
1499
1500 if (adapter->card) {
1501 /* Release the SDIO IRQ */
1502 sdio_claim_host(card->func);
1503 sdio_release_irq(card->func);
1504 sdio_disable_func(card->func);
1505 sdio_release_host(card->func);
1506 sdio_set_drvdata(card->func, NULL);
1507 }
1508}
1509
1510/*
1511 * This function registers the SDIO device.
1512 *
1513 * SDIO IRQ is claimed, block size is set and driver data is initialized.
1514 */
1515static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
1516{
1517 int ret = 0;
1518 struct sdio_mmc_card *card = adapter->card;
1519 struct sdio_func *func = card->func;
1520
1521 /* save adapter pointer in card */
1522 card->adapter = adapter;
1523
1524 sdio_claim_host(func);
1525
1526 /* Request the SDIO IRQ */
1527 ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
1528 if (ret) {
1529 pr_err("claim irq failed: ret=%d\n", ret);
1530 goto disable_func;
1531 }
1532
1533 /* Set block size */
1534 ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
1535 if (ret) {
1536 pr_err("cannot set SDIO block size\n");
1537 ret = -1;
1538 goto release_irq;
1539 }
1540
1541 sdio_release_host(func);
1542 sdio_set_drvdata(func, card);
1543
1544 adapter->dev = &func->dev;
1545
1546 return 0;
1547
1548release_irq:
1549 sdio_release_irq(func);
1550disable_func:
1551 sdio_disable_func(func);
1552 sdio_release_host(func);
1553 adapter->card = NULL;
1554
1555 return -1;
1556}
1557
1558/*
1559 * This function initializes the SDIO driver.
1560 *
1561 * The following initializations steps are followed -
1562 * - Read the Host interrupt status register to acknowledge
1563 * the first interrupt got from bootloader
1564 * - Disable host interrupt mask register
1565 * - Get SDIO port
1566 * - Get revision ID
1567 * - Initialize SDIO variables in card
1568 * - Allocate MP registers
1569 * - Allocate MPA Tx and Rx buffers
1570 */
1571static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
1572{
1573 struct sdio_mmc_card *card = adapter->card;
1574 int ret;
1575 u32 sdio_ireg = 0;
1576
1577 /*
1578 * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
1579 * from the bootloader. If we don't do this we get a interrupt
1580 * as soon as we register the irq.
1581 */
1582 mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
1583
1584 /* Disable host interrupt mask register for SDIO */
1585 mwifiex_sdio_disable_host_int(adapter);
1586
1587 /* Get SDIO ioport */
1588 mwifiex_init_sdio_ioport(adapter);
1589
1590 /* Get revision ID */
1591#define REV_ID_REG 0x5c
1592 mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id);
1593
1594 /* Initialize SDIO variables in card */
1595 card->mp_rd_bitmap = 0;
1596 card->mp_wr_bitmap = 0;
1597 card->curr_rd_port = 1;
1598 card->curr_wr_port = 1;
1599
1600 card->mp_data_port_mask = DATA_PORT_MASK;
1601
1602 card->mpa_tx.buf_len = 0;
1603 card->mpa_tx.pkt_cnt = 0;
1604 card->mpa_tx.start_port = 0;
1605
1606 card->mpa_tx.enabled = 0;
1607 card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
1608
1609 card->mpa_rx.buf_len = 0;
1610 card->mpa_rx.pkt_cnt = 0;
1611 card->mpa_rx.start_port = 0;
1612
1613 card->mpa_rx.enabled = 0;
1614 card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
1615
1616 /* Allocate buffers for SDIO MP-A */
1617 card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
1618 if (!card->mp_regs) {
1619 dev_err(adapter->dev, "failed to alloc mp_regs\n");
1620 return -1;
1621 }
1622
1623 ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
1624 SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
1625 SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
1626 if (ret) {
1627 dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
1628 kfree(card->mp_regs);
1629 return -1;
1630 }
1631
1632 return ret;
1633}
1634
1635/*
1636 * This function resets the MPA Tx and Rx buffers.
1637 */
1638static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter)
1639{
1640 struct sdio_mmc_card *card = adapter->card;
1641
1642 MP_TX_AGGR_BUF_RESET(card);
1643 MP_RX_AGGR_BUF_RESET(card);
1644}
1645
1646/*
1647 * This function cleans up the allocated card buffers.
1648 *
1649 * The following are freed by this function -
1650 * - MP registers
1651 * - MPA Tx buffer
1652 * - MPA Rx buffer
1653 */
1654static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter)
1655{
1656 struct sdio_mmc_card *card = adapter->card;
1657
1658 kfree(card->mp_regs);
1659 kfree(card->mpa_tx.buf);
1660 kfree(card->mpa_rx.buf);
1661}
1662
1663/*
1664 * This function updates the MP end port in card.
1665 */
1666static void
1667mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
1668{
1669 struct sdio_mmc_card *card = adapter->card;
1670 int i;
1671
1672 card->mp_end_port = port;
1673
1674 card->mp_data_port_mask = DATA_PORT_MASK;
1675
1676 for (i = 1; i <= MAX_PORT - card->mp_end_port; i++)
1677 card->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
1678
1679 card->curr_wr_port = 1;
1680
1681 dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
1682 port, card->mp_data_port_mask);
1683}
1684
1685static struct mwifiex_if_ops sdio_ops = {
1686 .init_if = mwifiex_init_sdio,
1687 .cleanup_if = mwifiex_cleanup_sdio,
1688 .check_fw_status = mwifiex_check_fw_status,
1689 .prog_fw = mwifiex_prog_fw_w_helper,
1690 .register_dev = mwifiex_register_dev,
1691 .unregister_dev = mwifiex_unregister_dev,
1692 .enable_int = mwifiex_sdio_enable_host_int,
1693 .process_int_status = mwifiex_process_int_status,
1694 .host_to_card = mwifiex_sdio_host_to_card,
1695 .wakeup = mwifiex_pm_wakeup_card,
1696 .wakeup_complete = mwifiex_pm_wakeup_card_complete,
1697
1698 /* SDIO specific */
1699 .update_mp_end_port = mwifiex_update_mp_end_port,
1700 .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
1701};
1702
1703/*
1704 * This function initializes the SDIO driver.
1705 *
1706 * This initiates the semaphore and registers the device with
1707 * SDIO bus.
1708 */
1709static int
1710mwifiex_sdio_init_module(void)
1711{
1712 int ret;
1713
1714 sema_init(&add_remove_card_sem, 1);
1715
1716 ret = sdio_register_driver(&mwifiex_sdio);
1717
1718 return ret;
1719}
1720
1721/*
1722 * This function cleans up the SDIO driver.
1723 *
1724 * The following major steps are followed for cleanup -
1725 * - Resume the device if its suspended
1726 * - Disconnect the device if connected
1727 * - Shutdown the firmware
1728 * - Unregister the device from SDIO bus.
1729 */
1730static void
1731mwifiex_sdio_cleanup_module(void)
1732{
1733 struct mwifiex_adapter *adapter = g_adapter;
1734 int i;
1735
1736 if (down_interruptible(&add_remove_card_sem))
1737 goto exit_sem_err;
1738
1739 if (!adapter || !adapter->priv_num)
1740 goto exit;
1741
1742 if (adapter->is_suspended)
1743 mwifiex_sdio_resume(adapter->dev);
1744
1745 for (i = 0; i < adapter->priv_num; i++)
1746 if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) &&
1747 adapter->priv[i]->media_connected)
1748 mwifiex_disconnect(adapter->priv[i], MWIFIEX_CMD_WAIT,
1749 NULL);
1750
1751 if (!adapter->surprise_removed)
1752 mwifiex_shutdown_fw(mwifiex_get_priv
1753 (adapter, MWIFIEX_BSS_ROLE_ANY),
1754 MWIFIEX_CMD_WAIT);
1755
1756exit:
1757 up(&add_remove_card_sem);
1758
1759exit_sem_err:
1760 sdio_unregister_driver(&mwifiex_sdio);
1761}
1762
1763module_init(mwifiex_sdio_init_module);
1764module_exit(mwifiex_sdio_cleanup_module);
1765
1766MODULE_AUTHOR("Marvell International Ltd.");
1767MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
1768MODULE_VERSION(SDIO_VERSION);
1769MODULE_LICENSE("GPL v2");
1770MODULE_FIRMWARE("sd8787.bin");
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
new file mode 100644
index 000000000000..a0e9bc5253e0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -0,0 +1,305 @@
1/*
2 * Marvell Wireless LAN device driver: SDIO specific definitions
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_SDIO_H
21#define _MWIFIEX_SDIO_H
22
23
24#include <linux/mmc/sdio.h>
25#include <linux/mmc/sdio_ids.h>
26#include <linux/mmc/sdio_func.h>
27#include <linux/mmc/card.h>
28
29#include "main.h"
30
31#define BLOCK_MODE 1
32#define BYTE_MODE 0
33
34#define REG_PORT 0
35#define RD_BITMAP_L 0x04
36#define RD_BITMAP_U 0x05
37#define WR_BITMAP_L 0x06
38#define WR_BITMAP_U 0x07
39#define RD_LEN_P0_L 0x08
40#define RD_LEN_P0_U 0x09
41
42#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff
43
44#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000
45
46#define CTRL_PORT 0
47#define CTRL_PORT_MASK 0x0001
48#define DATA_PORT_MASK 0xfffe
49
50#define MAX_MP_REGS 64
51#define MAX_PORT 16
52
53#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8
54
55#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
56
57/* Multi port RX aggregation buffer size */
58#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
59
60/* Misc. Config Register : Auto Re-enable interrupts */
61#define AUTO_RE_ENABLE_INT BIT(4)
62
63/* Host Control Registers */
64/* Host Control Registers : I/O port 0 */
65#define IO_PORT_0_REG 0x78
66/* Host Control Registers : I/O port 1 */
67#define IO_PORT_1_REG 0x79
68/* Host Control Registers : I/O port 2 */
69#define IO_PORT_2_REG 0x7A
70
71/* Host Control Registers : Configuration */
72#define CONFIGURATION_REG 0x00
73/* Host Control Registers : Host without Command 53 finish host*/
74#define HOST_TO_CARD_EVENT (0x1U << 3)
75/* Host Control Registers : Host without Command 53 finish host */
76#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
77/* Host Control Registers : Host power up */
78#define HOST_POWER_UP (0x1U << 1)
79/* Host Control Registers : Host power down */
80#define HOST_POWER_DOWN (0x1U << 0)
81
82/* Host Control Registers : Host interrupt mask */
83#define HOST_INT_MASK_REG 0x02
84/* Host Control Registers : Upload host interrupt mask */
85#define UP_LD_HOST_INT_MASK (0x1U)
86/* Host Control Registers : Download host interrupt mask */
87#define DN_LD_HOST_INT_MASK (0x2U)
88/* Enable Host interrupt mask */
89#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
90/* Disable Host interrupt mask */
91#define HOST_INT_DISABLE 0xff
92
93/* Host Control Registers : Host interrupt status */
94#define HOST_INTSTATUS_REG 0x03
95/* Host Control Registers : Upload host interrupt status */
96#define UP_LD_HOST_INT_STATUS (0x1U)
97/* Host Control Registers : Download host interrupt status */
98#define DN_LD_HOST_INT_STATUS (0x2U)
99
100/* Host Control Registers : Host interrupt RSR */
101#define HOST_INT_RSR_REG 0x01
102/* Host Control Registers : Upload host interrupt RSR */
103#define UP_LD_HOST_INT_RSR (0x1U)
104#define SDIO_INT_MASK 0x3F
105
106/* Host Control Registers : Host interrupt status */
107#define HOST_INT_STATUS_REG 0x28
108/* Host Control Registers : Upload CRC error */
109#define UP_LD_CRC_ERR (0x1U << 2)
110/* Host Control Registers : Upload restart */
111#define UP_LD_RESTART (0x1U << 1)
112/* Host Control Registers : Download restart */
113#define DN_LD_RESTART (0x1U << 0)
114
115/* Card Control Registers : Card status register */
116#define CARD_STATUS_REG 0x30
117/* Card Control Registers : Card I/O ready */
118#define CARD_IO_READY (0x1U << 3)
119/* Card Control Registers : CIS card ready */
120#define CIS_CARD_RDY (0x1U << 2)
121/* Card Control Registers : Upload card ready */
122#define UP_LD_CARD_RDY (0x1U << 1)
123/* Card Control Registers : Download card ready */
124#define DN_LD_CARD_RDY (0x1U << 0)
125
126/* Card Control Registers : Host interrupt mask register */
127#define HOST_INTERRUPT_MASK_REG 0x34
128/* Card Control Registers : Host power interrupt mask */
129#define HOST_POWER_INT_MASK (0x1U << 3)
130/* Card Control Registers : Abort card interrupt mask */
131#define ABORT_CARD_INT_MASK (0x1U << 2)
132/* Card Control Registers : Upload card interrupt mask */
133#define UP_LD_CARD_INT_MASK (0x1U << 1)
134/* Card Control Registers : Download card interrupt mask */
135#define DN_LD_CARD_INT_MASK (0x1U << 0)
136
137/* Card Control Registers : Card interrupt status register */
138#define CARD_INTERRUPT_STATUS_REG 0x38
139/* Card Control Registers : Power up interrupt */
140#define POWER_UP_INT (0x1U << 4)
141/* Card Control Registers : Power down interrupt */
142#define POWER_DOWN_INT (0x1U << 3)
143
144/* Card Control Registers : Card interrupt RSR register */
145#define CARD_INTERRUPT_RSR_REG 0x3c
146/* Card Control Registers : Power up RSR */
147#define POWER_UP_RSR (0x1U << 4)
148/* Card Control Registers : Power down RSR */
149#define POWER_DOWN_RSR (0x1U << 3)
150
151/* Card Control Registers : Miscellaneous Configuration Register */
152#define CARD_MISC_CFG_REG 0x6C
153
154/* Host F1 read base 0 */
155#define HOST_F1_RD_BASE_0 0x0040
156/* Host F1 read base 1 */
157#define HOST_F1_RD_BASE_1 0x0041
158/* Host F1 card ready */
159#define HOST_F1_CARD_RDY 0x0020
160
161/* Firmware status 0 register */
162#define CARD_FW_STATUS0_REG 0x60
163/* Firmware status 1 register */
164#define CARD_FW_STATUS1_REG 0x61
165/* Rx length register */
166#define CARD_RX_LEN_REG 0x62
167/* Rx unit register */
168#define CARD_RX_UNIT_REG 0x63
169
170/* Event header Len*/
171#define MWIFIEX_EVENT_HEADER_LEN 8
172
173/* Max retry number of CMD53 write */
174#define MAX_WRITE_IOMEM_RETRY 2
175
176/* SDIO Tx aggregation in progress ? */
177#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0)
178
179/* SDIO Tx aggregation buffer room for next packet ? */
180#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \
181 <= a->mpa_tx.buf_size)
182
183/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
184#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \
185 memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \
186 payload, pkt_len); \
187 a->mpa_tx.buf_len += pkt_len; \
188 if (!a->mpa_tx.pkt_cnt) \
189 a->mpa_tx.start_port = port; \
190 if (a->mpa_tx.start_port <= port) \
191 a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
192 else \
193 a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \
194 a->mp_end_port))); \
195 a->mpa_tx.pkt_cnt++; \
196} while (0);
197
198/* SDIO Tx aggregation limit ? */
199#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \
200 (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit)
201
202/* SDIO Tx aggregation port limit ? */
203#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
204 a->mpa_tx.start_port) && (((MAX_PORT - \
205 a->mpa_tx.start_port) + a->curr_wr_port) >= \
206 SDIO_MP_AGGR_DEF_PKT_LIMIT))
207
208/* Reset SDIO Tx aggregation buffer parameters */
209#define MP_TX_AGGR_BUF_RESET(a) do { \
210 a->mpa_tx.pkt_cnt = 0; \
211 a->mpa_tx.buf_len = 0; \
212 a->mpa_tx.ports = 0; \
213 a->mpa_tx.start_port = 0; \
214} while (0);
215
216/* SDIO Rx aggregation limit ? */
217#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \
218 (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit)
219
220/* SDIO Tx aggregation port limit ? */
221#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
222 a->mpa_rx.start_port) && (((MAX_PORT - \
223 a->mpa_rx.start_port) + a->curr_rd_port) >= \
224 SDIO_MP_AGGR_DEF_PKT_LIMIT))
225
226/* SDIO Rx aggregation in progress ? */
227#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0)
228
229/* SDIO Rx aggregation buffer room for next packet ? */
230#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \
231 ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size)
232
233/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
234#define MP_RX_AGGR_SETUP(a, skb, port) do { \
235 a->mpa_rx.buf_len += skb->len; \
236 if (!a->mpa_rx.pkt_cnt) \
237 a->mpa_rx.start_port = port; \
238 if (a->mpa_rx.start_port <= port) \
239 a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
240 else \
241 a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
242 a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \
243 a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \
244 a->mpa_rx.pkt_cnt++; \
245} while (0);
246
247/* Reset SDIO Rx aggregation buffer parameters */
248#define MP_RX_AGGR_BUF_RESET(a) do { \
249 a->mpa_rx.pkt_cnt = 0; \
250 a->mpa_rx.buf_len = 0; \
251 a->mpa_rx.ports = 0; \
252 a->mpa_rx.start_port = 0; \
253} while (0);
254
255
256/* data structure for SDIO MPA TX */
257struct mwifiex_sdio_mpa_tx {
258 /* multiport tx aggregation buffer pointer */
259 u8 *buf;
260 u32 buf_len;
261 u32 pkt_cnt;
262 u16 ports;
263 u16 start_port;
264 u8 enabled;
265 u32 buf_size;
266 u32 pkt_aggr_limit;
267};
268
269struct mwifiex_sdio_mpa_rx {
270 u8 *buf;
271 u32 buf_len;
272 u32 pkt_cnt;
273 u16 ports;
274 u16 start_port;
275
276 struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
277 u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
278
279 u8 enabled;
280 u32 buf_size;
281 u32 pkt_aggr_limit;
282};
283
284int mwifiex_bus_register(void);
285void mwifiex_bus_unregister(void);
286
287struct sdio_mmc_card {
288 struct sdio_func *func;
289 struct mwifiex_adapter *adapter;
290
291 u16 mp_rd_bitmap;
292 u16 mp_wr_bitmap;
293
294 u16 mp_end_port;
295 u16 mp_data_port_mask;
296
297 u8 curr_rd_port;
298 u8 curr_wr_port;
299
300 u8 *mp_regs;
301
302 struct mwifiex_sdio_mpa_tx mpa_tx;
303 struct mwifiex_sdio_mpa_rx mpa_rx;
304};
305#endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
new file mode 100644
index 000000000000..795b1eae768d
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -0,0 +1,1226 @@
1/*
2 * Marvell Wireless LAN device driver: station command handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * This function prepares command to set/get RSSI information.
30 *
31 * Preparation includes -
32 * - Setting command ID, action and proper size
33 * - Setting data/beacon average factors
34 * - Resetting SNR/NF/RSSI values in private structure
35 * - Ensuring correct endian-ness
36 */
37static int
38mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv,
39 struct host_cmd_ds_command *cmd, u16 cmd_action)
40{
41 cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO);
42 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) +
43 S_DS_GEN);
44 cmd->params.rssi_info.action = cpu_to_le16(cmd_action);
45 cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor);
46 cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor);
47
48 /* Reset SNR/NF/RSSI values in private structure */
49 priv->data_rssi_last = 0;
50 priv->data_nf_last = 0;
51 priv->data_rssi_avg = 0;
52 priv->data_nf_avg = 0;
53 priv->bcn_rssi_last = 0;
54 priv->bcn_nf_last = 0;
55 priv->bcn_rssi_avg = 0;
56 priv->bcn_nf_avg = 0;
57
58 return 0;
59}
60
61/*
62 * This function prepares command to set MAC control.
63 *
64 * Preparation includes -
65 * - Setting command ID, action and proper size
66 * - Ensuring correct endian-ness
67 */
68static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
69 struct host_cmd_ds_command *cmd,
70 u16 cmd_action, void *data_buf)
71{
72 struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
73 u16 action = *((u16 *) data_buf);
74
75 if (cmd_action != HostCmd_ACT_GEN_SET) {
76 dev_err(priv->adapter->dev,
77 "mac_control: only support set cmd\n");
78 return -1;
79 }
80
81 cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
82 cmd->size =
83 cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN);
84 mac_ctrl->action = cpu_to_le16(action);
85
86 return 0;
87}
88
89/*
90 * This function prepares command to set/get SNMP MIB.
91 *
92 * Preparation includes -
93 * - Setting command ID, action and proper size
94 * - Setting SNMP MIB OID number and value
95 * (as required)
96 * - Ensuring correct endian-ness
97 *
98 * The following SNMP MIB OIDs are supported -
99 * - FRAG_THRESH_I : Fragmentation threshold
100 * - RTS_THRESH_I : RTS threshold
101 * - SHORT_RETRY_LIM_I : Short retry limit
102 * - DOT11D_I : 11d support
103 */
104static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
105 struct host_cmd_ds_command *cmd,
106 u16 cmd_action, u32 cmd_oid,
107 void *data_buf)
108{
109 struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
110 u32 ul_temp;
111
112 dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
113 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
114 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
115 - 1 + S_DS_GEN);
116
117 if (cmd_action == HostCmd_ACT_GEN_GET) {
118 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET);
119 snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE);
120 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
121 + MAX_SNMP_BUF_SIZE);
122 }
123
124 switch (cmd_oid) {
125 case FRAG_THRESH_I:
126 snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I);
127 if (cmd_action == HostCmd_ACT_GEN_SET) {
128 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
129 snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
130 ul_temp = *((u32 *) data_buf);
131 *((__le16 *) (snmp_mib->value)) =
132 cpu_to_le16((u16) ul_temp);
133 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
134 + sizeof(u16));
135 }
136 break;
137 case RTS_THRESH_I:
138 snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I);
139 if (cmd_action == HostCmd_ACT_GEN_SET) {
140 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
141 snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
142 ul_temp = *((u32 *) data_buf);
143 *(__le16 *) (snmp_mib->value) =
144 cpu_to_le16((u16) ul_temp);
145 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
146 + sizeof(u16));
147 }
148 break;
149
150 case SHORT_RETRY_LIM_I:
151 snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I);
152 if (cmd_action == HostCmd_ACT_GEN_SET) {
153 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
154 snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
155 ul_temp = (*(u32 *) data_buf);
156 *((__le16 *) (snmp_mib->value)) =
157 cpu_to_le16((u16) ul_temp);
158 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
159 + sizeof(u16));
160 }
161 break;
162 case DOT11D_I:
163 snmp_mib->oid = cpu_to_le16((u16) DOT11D_I);
164 if (cmd_action == HostCmd_ACT_GEN_SET) {
165 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
166 snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
167 ul_temp = *(u32 *) data_buf;
168 *((__le16 *) (snmp_mib->value)) =
169 cpu_to_le16((u16) ul_temp);
170 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
171 + sizeof(u16));
172 }
173 break;
174 default:
175 break;
176 }
177 dev_dbg(priv->adapter->dev,
178 "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
179 " Value=0x%x\n",
180 cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
181 le16_to_cpu(*(__le16 *) snmp_mib->value));
182 return 0;
183}
184
185/*
186 * This function prepares command to get log.
187 *
188 * Preparation includes -
189 * - Setting command ID and proper size
190 * - Ensuring correct endian-ness
191 */
192static int
193mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv,
194 struct host_cmd_ds_command *cmd)
195{
196 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
197 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
198 S_DS_GEN);
199 return 0;
200}
201
202/*
203 * This function prepares command to set/get Tx data rate configuration.
204 *
205 * Preparation includes -
206 * - Setting command ID, action and proper size
207 * - Setting configuration index, rate scope and rate drop pattern
208 * parameters (as required)
209 * - Ensuring correct endian-ness
210 */
211static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
212 struct host_cmd_ds_command *cmd,
213 u16 cmd_action, void *data_buf)
214{
215 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
216 struct mwifiex_rate_scope *rate_scope;
217 struct mwifiex_rate_drop_pattern *rate_drop;
218 u16 *pbitmap_rates = (u16 *) data_buf;
219
220 u32 i;
221
222 cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
223
224 rate_cfg->action = cpu_to_le16(cmd_action);
225 rate_cfg->cfg_index = 0;
226
227 rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
228 sizeof(struct host_cmd_ds_tx_rate_cfg));
229 rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
230 rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) -
231 sizeof(struct mwifiex_ie_types_header));
232 if (pbitmap_rates != NULL) {
233 rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
234 rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
235 for (i = 0;
236 i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
237 i++)
238 rate_scope->ht_mcs_rate_bitmap[i] =
239 cpu_to_le16(pbitmap_rates[2 + i]);
240 } else {
241 rate_scope->hr_dsss_rate_bitmap =
242 cpu_to_le16(priv->bitmap_rates[0]);
243 rate_scope->ofdm_rate_bitmap =
244 cpu_to_le16(priv->bitmap_rates[1]);
245 for (i = 0;
246 i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
247 i++)
248 rate_scope->ht_mcs_rate_bitmap[i] =
249 cpu_to_le16(priv->bitmap_rates[2 + i]);
250 }
251
252 rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
253 sizeof(struct mwifiex_rate_scope));
254 rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
255 rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
256 rate_drop->rate_drop_mode = 0;
257
258 cmd->size =
259 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
260 sizeof(struct mwifiex_rate_scope) +
261 sizeof(struct mwifiex_rate_drop_pattern));
262
263 return 0;
264}
265
266/*
267 * This function prepares command to set/get Tx power configuration.
268 *
269 * Preparation includes -
270 * - Setting command ID, action and proper size
271 * - Setting Tx power mode, power group TLV
272 * (as required)
273 * - Ensuring correct endian-ness
274 */
275static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv,
276 struct host_cmd_ds_command *cmd,
277 u16 cmd_action, void *data_buf)
278{
279 struct mwifiex_types_power_group *pg_tlv = NULL;
280 struct host_cmd_ds_txpwr_cfg *txp = NULL;
281 struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
282
283 cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
284 cmd->size =
285 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
286 switch (cmd_action) {
287 case HostCmd_ACT_GEN_SET:
288 txp = (struct host_cmd_ds_txpwr_cfg *) data_buf;
289 if (txp->mode) {
290 pg_tlv = (struct mwifiex_types_power_group
291 *) ((unsigned long) data_buf +
292 sizeof(struct host_cmd_ds_txpwr_cfg));
293 memmove(cmd_txp_cfg, data_buf,
294 sizeof(struct host_cmd_ds_txpwr_cfg) +
295 sizeof(struct mwifiex_types_power_group) +
296 pg_tlv->length);
297
298 pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
299 cmd_txp_cfg +
300 sizeof(struct host_cmd_ds_txpwr_cfg));
301 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
302 sizeof(struct mwifiex_types_power_group) +
303 pg_tlv->length);
304 } else {
305 memmove(cmd_txp_cfg, data_buf,
306 sizeof(struct host_cmd_ds_txpwr_cfg));
307 }
308 cmd_txp_cfg->action = cpu_to_le16(cmd_action);
309 break;
310 case HostCmd_ACT_GEN_GET:
311 cmd_txp_cfg->action = cpu_to_le16(cmd_action);
312 break;
313 }
314
315 return 0;
316}
317
318/*
319 * This function prepares command to set Host Sleep configuration.
320 *
321 * Preparation includes -
322 * - Setting command ID and proper size
323 * - Setting Host Sleep action, conditions, ARP filters
324 * (as required)
325 * - Ensuring correct endian-ness
326 */
327static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
328 struct host_cmd_ds_command *cmd,
329 u16 cmd_action,
330 struct mwifiex_hs_config_param *data_buf)
331{
332 struct mwifiex_adapter *adapter = priv->adapter;
333 struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
334 u16 hs_activate = false;
335
336 if (data_buf == NULL)
337 /* New Activate command */
338 hs_activate = true;
339 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
340
341 if (!hs_activate &&
342 (data_buf->conditions
343 != cpu_to_le32(HOST_SLEEP_CFG_CANCEL))
344 && ((adapter->arp_filter_size > 0)
345 && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
346 dev_dbg(adapter->dev,
347 "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
348 adapter->arp_filter_size);
349 memcpy(((u8 *) hs_cfg) +
350 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
351 adapter->arp_filter, adapter->arp_filter_size);
352 cmd->size = cpu_to_le16(adapter->arp_filter_size +
353 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
354 + S_DS_GEN);
355 } else {
356 cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct
357 host_cmd_ds_802_11_hs_cfg_enh));
358 }
359 if (hs_activate) {
360 hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
361 hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
362 } else {
363 hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
364 hs_cfg->params.hs_config.conditions = data_buf->conditions;
365 hs_cfg->params.hs_config.gpio = data_buf->gpio;
366 hs_cfg->params.hs_config.gap = data_buf->gap;
367 dev_dbg(adapter->dev,
368 "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
369 hs_cfg->params.hs_config.conditions,
370 hs_cfg->params.hs_config.gpio,
371 hs_cfg->params.hs_config.gap);
372 }
373
374 return 0;
375}
376
377/*
378 * This function prepares command to set/get MAC address.
379 *
380 * Preparation includes -
381 * - Setting command ID, action and proper size
382 * - Setting MAC address (for SET only)
383 * - Ensuring correct endian-ness
384 */
385static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
386 struct host_cmd_ds_command *cmd,
387 u16 cmd_action)
388{
389 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
390 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
391 S_DS_GEN);
392 cmd->result = 0;
393
394 cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
395
396 if (cmd_action == HostCmd_ACT_GEN_SET)
397 memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
398 ETH_ALEN);
399 return 0;
400}
401
402/*
403 * This function prepares command to set MAC multicast address.
404 *
405 * Preparation includes -
406 * - Setting command ID, action and proper size
407 * - Setting MAC multicast address
408 * - Ensuring correct endian-ness
409 */
410static int mwifiex_cmd_mac_multicast_adr(struct mwifiex_private *priv,
411 struct host_cmd_ds_command *cmd,
412 u16 cmd_action, void *data_buf)
413{
414 struct mwifiex_multicast_list *mcast_list =
415 (struct mwifiex_multicast_list *) data_buf;
416 struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
417
418 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
419 S_DS_GEN);
420 cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
421
422 mcast_addr->action = cpu_to_le16(cmd_action);
423 mcast_addr->num_of_adrs =
424 cpu_to_le16((u16) mcast_list->num_multicast_addr);
425 memcpy(mcast_addr->mac_list, mcast_list->mac_list,
426 mcast_list->num_multicast_addr * ETH_ALEN);
427
428 return 0;
429}
430
431/*
432 * This function prepares command to deauthenticate.
433 *
434 * Preparation includes -
435 * - Setting command ID and proper size
436 * - Setting AP MAC address and reason code
437 * - Ensuring correct endian-ness
438 */
439static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
440 struct host_cmd_ds_command *cmd,
441 void *data_buf)
442{
443 struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
444
445 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
446 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
447 + S_DS_GEN);
448
449 /* Set AP MAC address */
450 memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN);
451
452 dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
453
454 deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
455
456 return 0;
457}
458
459/*
460 * This function prepares command to stop Ad-Hoc network.
461 *
462 * Preparation includes -
463 * - Setting command ID and proper size
464 * - Ensuring correct endian-ness
465 */
466static int mwifiex_cmd_802_11_ad_hoc_stop(struct mwifiex_private *priv,
467 struct host_cmd_ds_command *cmd)
468{
469 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
470 cmd->size = cpu_to_le16(S_DS_GEN);
471 return 0;
472}
473
474/*
475 * This function sets WEP key(s) to key parameter TLV(s).
476 *
477 * Multi-key parameter TLVs are supported, so we can send multiple
478 * WEP keys in a single buffer.
479 */
480static int
481mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
482 struct mwifiex_ie_type_key_param_set *key_param_set,
483 u16 *key_param_len)
484{
485 int cur_key_param_len = 0;
486 u8 i;
487
488 /* Multi-key_param_set TLV is supported */
489 for (i = 0; i < NUM_WEP_KEYS; i++) {
490 if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
491 (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
492 key_param_set->type =
493 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
494/* Key_param_set WEP fixed length */
495#define KEYPARAMSET_WEP_FIXED_LEN 8
496 key_param_set->length = cpu_to_le16((u16)
497 (priv->wep_key[i].
498 key_length +
499 KEYPARAMSET_WEP_FIXED_LEN));
500 key_param_set->key_type_id =
501 cpu_to_le16(KEY_TYPE_ID_WEP);
502 key_param_set->key_info =
503 cpu_to_le16(KEY_INFO_WEP_ENABLED |
504 KEY_INFO_WEP_UNICAST |
505 KEY_INFO_WEP_MCAST);
506 key_param_set->key_len =
507 cpu_to_le16(priv->wep_key[i].key_length);
508 /* Set WEP key index */
509 key_param_set->key[0] = i;
510 /* Set default Tx key flag */
511 if (i ==
512 (priv->
513 wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
514 key_param_set->key[1] = 1;
515 else
516 key_param_set->key[1] = 0;
517 memmove(&key_param_set->key[2],
518 priv->wep_key[i].key_material,
519 priv->wep_key[i].key_length);
520
521 cur_key_param_len = priv->wep_key[i].key_length +
522 KEYPARAMSET_WEP_FIXED_LEN +
523 sizeof(struct mwifiex_ie_types_header);
524 *key_param_len += (u16) cur_key_param_len;
525 key_param_set =
526 (struct mwifiex_ie_type_key_param_set *)
527 ((u8 *)key_param_set +
528 cur_key_param_len);
529 } else if (!priv->wep_key[i].key_length) {
530 continue;
531 } else {
532 dev_err(priv->adapter->dev,
533 "key%d Length = %d is incorrect\n",
534 (i + 1), priv->wep_key[i].key_length);
535 return -1;
536 }
537 }
538
539 return 0;
540}
541
542/*
543 * This function prepares command to set/get/reset network key(s).
544 *
545 * Preparation includes -
546 * - Setting command ID, action and proper size
547 * - Setting WEP keys, WAPI keys or WPA keys along with required
548 * encryption (TKIP, AES) (as required)
549 * - Ensuring correct endian-ness
550 */
551static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
552 struct host_cmd_ds_command *cmd,
553 u16 cmd_action,
554 u32 cmd_oid, void *data_buf)
555{
556 struct host_cmd_ds_802_11_key_material *key_material =
557 &cmd->params.key_material;
558 struct mwifiex_ds_encrypt_key *enc_key =
559 (struct mwifiex_ds_encrypt_key *) data_buf;
560 u16 key_param_len = 0;
561 int ret = 0;
562 const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
563
564 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
565 key_material->action = cpu_to_le16(cmd_action);
566
567 if (cmd_action == HostCmd_ACT_GEN_GET) {
568 cmd->size =
569 cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
570 return ret;
571 }
572
573 if (!enc_key) {
574 memset(&key_material->key_param_set, 0,
575 (NUM_WEP_KEYS *
576 sizeof(struct mwifiex_ie_type_key_param_set)));
577 ret = mwifiex_set_keyparamset_wep(priv,
578 &key_material->key_param_set,
579 &key_param_len);
580 cmd->size = cpu_to_le16(key_param_len +
581 sizeof(key_material->action) + S_DS_GEN);
582 return ret;
583 } else
584 memset(&key_material->key_param_set, 0,
585 sizeof(struct mwifiex_ie_type_key_param_set));
586 if (enc_key->is_wapi_key) {
587 dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
588 key_material->key_param_set.key_type_id =
589 cpu_to_le16(KEY_TYPE_ID_WAPI);
590 if (cmd_oid == KEY_INFO_ENABLED)
591 key_material->key_param_set.key_info =
592 cpu_to_le16(KEY_INFO_WAPI_ENABLED);
593 else
594 key_material->key_param_set.key_info =
595 cpu_to_le16(!KEY_INFO_WAPI_ENABLED);
596
597 key_material->key_param_set.key[0] = enc_key->key_index;
598 if (!priv->sec_info.wapi_key_on)
599 key_material->key_param_set.key[1] = 1;
600 else
601 /* set 0 when re-key */
602 key_material->key_param_set.key[1] = 0;
603
604 if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
605 /* WAPI pairwise key: unicast */
606 key_material->key_param_set.key_info |=
607 cpu_to_le16(KEY_INFO_WAPI_UNICAST);
608 } else { /* WAPI group key: multicast */
609 key_material->key_param_set.key_info |=
610 cpu_to_le16(KEY_INFO_WAPI_MCAST);
611 priv->sec_info.wapi_key_on = true;
612 }
613
614 key_material->key_param_set.type =
615 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
616 key_material->key_param_set.key_len =
617 cpu_to_le16(WAPI_KEY_LEN);
618 memcpy(&key_material->key_param_set.key[2],
619 enc_key->key_material, enc_key->key_len);
620 memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
621 enc_key->wapi_rxpn, WAPI_RXPN_LEN);
622 key_material->key_param_set.length =
623 cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
624
625 key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
626 sizeof(struct mwifiex_ie_types_header);
627 cmd->size = cpu_to_le16(key_param_len +
628 sizeof(key_material->action) + S_DS_GEN);
629 return ret;
630 }
631 if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
632 dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
633 key_material->key_param_set.key_type_id =
634 cpu_to_le16(KEY_TYPE_ID_AES);
635 if (cmd_oid == KEY_INFO_ENABLED)
636 key_material->key_param_set.key_info =
637 cpu_to_le16(KEY_INFO_AES_ENABLED);
638 else
639 key_material->key_param_set.key_info =
640 cpu_to_le16(!KEY_INFO_AES_ENABLED);
641
642 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
643 /* AES pairwise key: unicast */
644 key_material->key_param_set.key_info |=
645 cpu_to_le16(KEY_INFO_AES_UNICAST);
646 else /* AES group key: multicast */
647 key_material->key_param_set.key_info |=
648 cpu_to_le16(KEY_INFO_AES_MCAST);
649 } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
650 dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
651 key_material->key_param_set.key_type_id =
652 cpu_to_le16(KEY_TYPE_ID_TKIP);
653 key_material->key_param_set.key_info =
654 cpu_to_le16(KEY_INFO_TKIP_ENABLED);
655
656 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
657 /* TKIP pairwise key: unicast */
658 key_material->key_param_set.key_info |=
659 cpu_to_le16(KEY_INFO_TKIP_UNICAST);
660 else /* TKIP group key: multicast */
661 key_material->key_param_set.key_info |=
662 cpu_to_le16(KEY_INFO_TKIP_MCAST);
663 }
664
665 if (key_material->key_param_set.key_type_id) {
666 key_material->key_param_set.type =
667 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
668 key_material->key_param_set.key_len =
669 cpu_to_le16((u16) enc_key->key_len);
670 memcpy(key_material->key_param_set.key, enc_key->key_material,
671 enc_key->key_len);
672 key_material->key_param_set.length =
673 cpu_to_le16((u16) enc_key->key_len +
674 KEYPARAMSET_FIXED_LEN);
675
676 key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
677 + sizeof(struct mwifiex_ie_types_header);
678
679 cmd->size = cpu_to_le16(key_param_len +
680 sizeof(key_material->action) + S_DS_GEN);
681 }
682
683 return ret;
684}
685
686/*
687 * This function prepares command to set/get 11d domain information.
688 *
689 * Preparation includes -
690 * - Setting command ID, action and proper size
691 * - Setting domain information fields (for SET only)
692 * - Ensuring correct endian-ness
693 */
694static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
695 struct host_cmd_ds_command *cmd,
696 u16 cmd_action)
697{
698 struct mwifiex_adapter *adapter = priv->adapter;
699 struct host_cmd_ds_802_11d_domain_info *domain_info =
700 &cmd->params.domain_info;
701 struct mwifiex_ietypes_domain_param_set *domain =
702 &domain_info->domain;
703 u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
704
705 dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
706
707 cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
708 domain_info->action = cpu_to_le16(cmd_action);
709 if (cmd_action == HostCmd_ACT_GEN_GET) {
710 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
711 return 0;
712 }
713
714 /* Set domain info fields */
715 domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
716 memcpy(domain->country_code, adapter->domain_reg.country_code,
717 sizeof(domain->country_code));
718
719 domain->header.len = cpu_to_le16((no_of_triplet *
720 sizeof(struct ieee80211_country_ie_triplet)) +
721 sizeof(domain->country_code));
722
723 if (no_of_triplet) {
724 memcpy(domain->triplet, adapter->domain_reg.triplet,
725 no_of_triplet *
726 sizeof(struct ieee80211_country_ie_triplet));
727
728 cmd->size = cpu_to_le16(sizeof(domain_info->action) +
729 le16_to_cpu(domain->header.len) +
730 sizeof(struct mwifiex_ie_types_header)
731 + S_DS_GEN);
732 } else {
733 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
734 }
735
736 return 0;
737}
738
739/*
740 * This function prepares command to set/get RF channel.
741 *
742 * Preparation includes -
743 * - Setting command ID, action and proper size
744 * - Setting RF type and current RF channel (for SET only)
745 * - Ensuring correct endian-ness
746 */
747static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv,
748 struct host_cmd_ds_command *cmd,
749 u16 cmd_action, void *data_buf)
750{
751 struct host_cmd_ds_802_11_rf_channel *rf_chan =
752 &cmd->params.rf_channel;
753 uint16_t rf_type = le16_to_cpu(rf_chan->rf_type);
754
755 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
756 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel)
757 + S_DS_GEN);
758
759 if (cmd_action == HostCmd_ACT_GEN_SET) {
760 if ((priv->adapter->adhoc_start_band & BAND_A)
761 || (priv->adapter->adhoc_start_band & BAND_AN))
762 rf_chan->rf_type =
763 cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A);
764
765 rf_type = le16_to_cpu(rf_chan->rf_type);
766 SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset);
767 rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf));
768 }
769 rf_chan->action = cpu_to_le16(cmd_action);
770 return 0;
771}
772
773/*
774 * This function prepares command to set/get IBSS coalescing status.
775 *
776 * Preparation includes -
777 * - Setting command ID, action and proper size
778 * - Setting status to enable or disable (for SET only)
779 * - Ensuring correct endian-ness
780 */
781static int mwifiex_cmd_ibss_coalescing_status(struct mwifiex_private *priv,
782 struct host_cmd_ds_command *cmd,
783 u16 cmd_action, void *data_buf)
784{
785 struct host_cmd_ds_802_11_ibss_status *ibss_coal =
786 &(cmd->params.ibss_coalescing);
787 u16 enable = 0;
788
789 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
790 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
791 S_DS_GEN);
792 cmd->result = 0;
793 ibss_coal->action = cpu_to_le16(cmd_action);
794
795 switch (cmd_action) {
796 case HostCmd_ACT_GEN_SET:
797 if (data_buf != NULL)
798 enable = *(u16 *) data_buf;
799 ibss_coal->enable = cpu_to_le16(enable);
800 break;
801
802 /* In other case.. Nothing to do */
803 case HostCmd_ACT_GEN_GET:
804 default:
805 break;
806 }
807
808 return 0;
809}
810
811/*
812 * This function prepares command to set/get register value.
813 *
814 * Preparation includes -
815 * - Setting command ID, action and proper size
816 * - Setting register offset (for both GET and SET) and
817 * register value (for SET only)
818 * - Ensuring correct endian-ness
819 *
820 * The following type of registers can be accessed with this function -
821 * - MAC register
822 * - BBP register
823 * - RF register
824 * - PMIC register
825 * - CAU register
826 * - EEPROM
827 */
828static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
829 u16 cmd_action, void *data_buf)
830{
831 struct mwifiex_ds_reg_rw *reg_rw;
832
833 reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
834 switch (le16_to_cpu(cmd->command)) {
835 case HostCmd_CMD_MAC_REG_ACCESS:
836 {
837 struct host_cmd_ds_mac_reg_access *mac_reg;
838
839 cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
840 mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
841 params.mac_reg;
842 mac_reg->action = cpu_to_le16(cmd_action);
843 mac_reg->offset =
844 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
845 mac_reg->value = reg_rw->value;
846 break;
847 }
848 case HostCmd_CMD_BBP_REG_ACCESS:
849 {
850 struct host_cmd_ds_bbp_reg_access *bbp_reg;
851
852 cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
853 bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd->
854 params.bbp_reg;
855 bbp_reg->action = cpu_to_le16(cmd_action);
856 bbp_reg->offset =
857 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
858 bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
859 break;
860 }
861 case HostCmd_CMD_RF_REG_ACCESS:
862 {
863 struct host_cmd_ds_rf_reg_access *rf_reg;
864
865 cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
866 rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
867 params.rf_reg;
868 rf_reg->action = cpu_to_le16(cmd_action);
869 rf_reg->offset =
870 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
871 rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
872 break;
873 }
874 case HostCmd_CMD_PMIC_REG_ACCESS:
875 {
876 struct host_cmd_ds_pmic_reg_access *pmic_reg;
877
878 cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
879 pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
880 params.pmic_reg;
881 pmic_reg->action = cpu_to_le16(cmd_action);
882 pmic_reg->offset =
883 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
884 pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
885 break;
886 }
887 case HostCmd_CMD_CAU_REG_ACCESS:
888 {
889 struct host_cmd_ds_rf_reg_access *cau_reg;
890
891 cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
892 cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
893 params.rf_reg;
894 cau_reg->action = cpu_to_le16(cmd_action);
895 cau_reg->offset =
896 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
897 cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
898 break;
899 }
900 case HostCmd_CMD_802_11_EEPROM_ACCESS:
901 {
902 struct mwifiex_ds_read_eeprom *rd_eeprom =
903 (struct mwifiex_ds_read_eeprom *) data_buf;
904 struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
905 (struct host_cmd_ds_802_11_eeprom_access *)
906 &cmd->params.eeprom;
907
908 cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
909 cmd_eeprom->action = cpu_to_le16(cmd_action);
910 cmd_eeprom->offset = rd_eeprom->offset;
911 cmd_eeprom->byte_count = rd_eeprom->byte_count;
912 cmd_eeprom->value = 0;
913 break;
914 }
915 default:
916 return -1;
917 }
918
919 return 0;
920}
921
922/*
923 * This function prepares the commands before sending them to the firmware.
924 *
925 * This is a generic function which calls specific command preparation
926 * routines based upon the command number.
927 */
928int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
929 u16 cmd_action, u32 cmd_oid,
930 void *data_buf, void *cmd_buf)
931{
932 struct host_cmd_ds_command *cmd_ptr =
933 (struct host_cmd_ds_command *) cmd_buf;
934 int ret = 0;
935
936 /* Prepare command */
937 switch (cmd_no) {
938 case HostCmd_CMD_GET_HW_SPEC:
939 ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
940 break;
941 case HostCmd_CMD_MAC_CONTROL:
942 ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
943 data_buf);
944 break;
945 case HostCmd_CMD_802_11_MAC_ADDRESS:
946 ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
947 cmd_action);
948 break;
949 case HostCmd_CMD_MAC_MULTICAST_ADR:
950 ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action,
951 data_buf);
952 break;
953 case HostCmd_CMD_TX_RATE_CFG:
954 ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
955 data_buf);
956 break;
957 case HostCmd_CMD_TXPWR_CFG:
958 ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action,
959 data_buf);
960 break;
961 case HostCmd_CMD_802_11_PS_MODE_ENH:
962 ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
963 (uint16_t)cmd_oid, data_buf);
964 break;
965 case HostCmd_CMD_802_11_HS_CFG_ENH:
966 ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
967 (struct mwifiex_hs_config_param *) data_buf);
968 break;
969 case HostCmd_CMD_802_11_SCAN:
970 ret = mwifiex_cmd_802_11_scan(priv, cmd_ptr, data_buf);
971 break;
972 case HostCmd_CMD_802_11_BG_SCAN_QUERY:
973 ret = mwifiex_cmd_802_11_bg_scan_query(priv, cmd_ptr,
974 data_buf);
975 break;
976 case HostCmd_CMD_802_11_ASSOCIATE:
977 ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
978 break;
979 case HostCmd_CMD_802_11_DEAUTHENTICATE:
980 ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
981 data_buf);
982 break;
983 case HostCmd_CMD_802_11_AD_HOC_START:
984 ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
985 data_buf);
986 break;
987 case HostCmd_CMD_802_11_GET_LOG:
988 ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr);
989 break;
990 case HostCmd_CMD_802_11_AD_HOC_JOIN:
991 ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
992 data_buf);
993 break;
994 case HostCmd_CMD_802_11_AD_HOC_STOP:
995 ret = mwifiex_cmd_802_11_ad_hoc_stop(priv, cmd_ptr);
996 break;
997 case HostCmd_CMD_RSSI_INFO:
998 ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
999 break;
1000 case HostCmd_CMD_802_11_SNMP_MIB:
1001 ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
1002 cmd_oid, data_buf);
1003 break;
1004 case HostCmd_CMD_802_11_TX_RATE_QUERY:
1005 cmd_ptr->command =
1006 cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
1007 cmd_ptr->size =
1008 cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
1009 S_DS_GEN);
1010 priv->tx_rate = 0;
1011 ret = 0;
1012 break;
1013 case HostCmd_CMD_VERSION_EXT:
1014 cmd_ptr->command = cpu_to_le16(cmd_no);
1015 cmd_ptr->params.verext.version_str_sel =
1016 (u8) (*((u32 *) data_buf));
1017 memcpy(&cmd_ptr->params, data_buf,
1018 sizeof(struct host_cmd_ds_version_ext));
1019 cmd_ptr->size =
1020 cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
1021 S_DS_GEN);
1022 ret = 0;
1023 break;
1024 case HostCmd_CMD_802_11_RF_CHANNEL:
1025 ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action,
1026 data_buf);
1027 break;
1028 case HostCmd_CMD_FUNC_INIT:
1029 if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
1030 priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
1031 cmd_ptr->command = cpu_to_le16(cmd_no);
1032 cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1033 break;
1034 case HostCmd_CMD_FUNC_SHUTDOWN:
1035 priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
1036 cmd_ptr->command = cpu_to_le16(cmd_no);
1037 cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1038 break;
1039 case HostCmd_CMD_11N_ADDBA_REQ:
1040 ret = mwifiex_cmd_11n_addba_req(priv, cmd_ptr, data_buf);
1041 break;
1042 case HostCmd_CMD_11N_DELBA:
1043 ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf);
1044 break;
1045 case HostCmd_CMD_11N_ADDBA_RSP:
1046 ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
1047 break;
1048 case HostCmd_CMD_802_11_KEY_MATERIAL:
1049 ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
1050 cmd_action, cmd_oid,
1051 data_buf);
1052 break;
1053 case HostCmd_CMD_802_11D_DOMAIN_INFO:
1054 ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
1055 cmd_action);
1056 break;
1057 case HostCmd_CMD_RECONFIGURE_TX_BUFF:
1058 ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
1059 data_buf);
1060 break;
1061 case HostCmd_CMD_AMSDU_AGGR_CTRL:
1062 ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action,
1063 data_buf);
1064 break;
1065 case HostCmd_CMD_11N_CFG:
1066 ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action,
1067 data_buf);
1068 break;
1069 case HostCmd_CMD_WMM_GET_STATUS:
1070 dev_dbg(priv->adapter->dev,
1071 "cmd: WMM: WMM_GET_STATUS cmd sent\n");
1072 cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
1073 cmd_ptr->size =
1074 cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
1075 S_DS_GEN);
1076 ret = 0;
1077 break;
1078 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
1079 ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr,
1080 cmd_action, data_buf);
1081 break;
1082 case HostCmd_CMD_MAC_REG_ACCESS:
1083 case HostCmd_CMD_BBP_REG_ACCESS:
1084 case HostCmd_CMD_RF_REG_ACCESS:
1085 case HostCmd_CMD_PMIC_REG_ACCESS:
1086 case HostCmd_CMD_CAU_REG_ACCESS:
1087 case HostCmd_CMD_802_11_EEPROM_ACCESS:
1088 ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
1089 break;
1090 case HostCmd_CMD_SET_BSS_MODE:
1091 cmd_ptr->command = cpu_to_le16(cmd_no);
1092 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS)
1093 cmd_ptr->params.bss_mode.con_type =
1094 CONNECTION_TYPE_ADHOC;
1095 else if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA)
1096 cmd_ptr->params.bss_mode.con_type =
1097 CONNECTION_TYPE_INFRA;
1098 cmd_ptr->size = cpu_to_le16(sizeof(struct
1099 host_cmd_ds_set_bss_mode) + S_DS_GEN);
1100 ret = 0;
1101 break;
1102 default:
1103 dev_err(priv->adapter->dev,
1104 "PREP_CMD: unknown cmd- %#x\n", cmd_no);
1105 ret = -1;
1106 break;
1107 }
1108 return ret;
1109}
1110
1111/*
1112 * This function issues commands to initialize firmware.
1113 *
1114 * This is called after firmware download to bring the card to
1115 * working state.
1116 *
1117 * The following commands are issued sequentially -
1118 * - Function init (for first interface only)
1119 * - Read MAC address (for first interface only)
1120 * - Reconfigure Tx buffer size (for first interface only)
1121 * - Enable auto deep sleep (for first interface only)
1122 * - Get Tx rate
1123 * - Get Tx power
1124 * - Set IBSS coalescing status
1125 * - Set AMSDU aggregation control
1126 * - Set 11d control
1127 * - Set MAC control (this must be the last command to initialize firmware)
1128 */
1129int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
1130{
1131 int ret = 0;
1132 u16 enable = true;
1133 struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
1134 struct mwifiex_ds_auto_ds auto_ds;
1135 enum state_11d_t state_11d;
1136
1137 if (first_sta) {
1138
1139 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT,
1140 HostCmd_ACT_GEN_SET, 0, NULL, NULL);
1141 if (ret)
1142 return -1;
1143 /* Read MAC address from HW */
1144 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
1145 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
1146 if (ret)
1147 return -1;
1148
1149 /* Reconfigure tx buf size */
1150 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
1151 HostCmd_ACT_GEN_SET, 0, NULL,
1152 &priv->adapter->tx_buf_size);
1153 if (ret)
1154 return -1;
1155
1156 /* Enable IEEE PS by default */
1157 priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1158 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
1159 EN_AUTO_PS, BITMAP_STA_PS, NULL,
1160 NULL);
1161 if (ret)
1162 return -1;
1163 }
1164
1165 /* get tx rate */
1166 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
1167 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
1168 if (ret)
1169 return -1;
1170 priv->data_rate = 0;
1171
1172 /* get tx power */
1173 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG,
1174 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
1175 if (ret)
1176 return -1;
1177
1178 /* set ibss coalescing_status */
1179 ret = mwifiex_prepare_cmd(priv,
1180 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
1181 HostCmd_ACT_GEN_SET, 0, NULL, &enable);
1182 if (ret)
1183 return -1;
1184
1185 memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
1186 amsdu_aggr_ctrl.enable = true;
1187 /* Send request to firmware */
1188 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
1189 HostCmd_ACT_GEN_SET, 0, NULL,
1190 (void *) &amsdu_aggr_ctrl);
1191 if (ret)
1192 return -1;
1193 /* MAC Control must be the last command in init_fw */
1194 /* set MAC Control */
1195 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1196 HostCmd_ACT_GEN_SET, 0, NULL,
1197 &priv->curr_pkt_filter);
1198 if (ret)
1199 return -1;
1200
1201 if (first_sta) {
1202 /* Enable auto deep sleep */
1203 auto_ds.auto_ds = DEEP_SLEEP_ON;
1204 auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
1205 ret = mwifiex_prepare_cmd(priv,
1206 HostCmd_CMD_802_11_PS_MODE_ENH,
1207 EN_AUTO_PS, BITMAP_AUTO_DS, NULL,
1208 &auto_ds);
1209 if (ret)
1210 return -1;
1211 }
1212
1213 /* Send cmd to FW to enable/disable 11D function */
1214 state_11d = ENABLE_11D;
1215 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
1216 HostCmd_ACT_GEN_SET, DOT11D_I,
1217 NULL, &state_11d);
1218 if (ret)
1219 dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
1220
1221 /* set last_init_cmd */
1222 priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB;
1223 ret = -EINPROGRESS;
1224
1225 return ret;
1226}
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
new file mode 100644
index 000000000000..ae960ddf2bd4
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -0,0 +1,986 @@
1/*
2 * Marvell Wireless LAN device driver: station command response handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28
29/*
30 * This function handles the command response error case.
31 *
32 * For scan response error, the function cancels all the pending
33 * scan commands and generates an event to inform the applications
34 * of the scan completion.
35 *
36 * For Power Save command failure, we do not retry enter PS
37 * command in case of Ad-hoc mode.
38 *
39 * For all other response errors, the current command buffer is freed
40 * and returned to the free command queue.
41 */
42static void
43mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
44 struct host_cmd_ds_command *resp,
45 struct mwifiex_wait_queue *wq_buf)
46{
47 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
48 struct mwifiex_adapter *adapter = priv->adapter;
49 unsigned long flags;
50
51 dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
52 resp->command, resp->result);
53 if (wq_buf)
54 wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP;
55
56 switch (le16_to_cpu(resp->command)) {
57 case HostCmd_CMD_802_11_PS_MODE_ENH:
58 {
59 struct host_cmd_ds_802_11_ps_mode_enh *pm =
60 &resp->params.psmode_enh;
61 dev_err(adapter->dev, "PS_MODE_ENH cmd failed: "
62 "result=0x%x action=0x%X\n",
63 resp->result, le16_to_cpu(pm->action));
64 /* We do not re-try enter-ps command in ad-hoc mode. */
65 if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
66 (le16_to_cpu(pm->params.auto_ps.ps_bitmap) &
67 BITMAP_STA_PS)
68 && priv->bss_mode == MWIFIEX_BSS_MODE_IBSS)
69 adapter->ps_mode =
70 MWIFIEX_802_11_POWER_MODE_CAM;
71 }
72 break;
73 case HostCmd_CMD_802_11_SCAN:
74 /* Cancel all pending scan command */
75 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
76 list_for_each_entry_safe(cmd_node, tmp_node,
77 &adapter->scan_pending_q, list) {
78 list_del(&cmd_node->list);
79 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
80 flags);
81 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
82 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
83 }
84 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
85
86 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
87 adapter->scan_processing = false;
88 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
89 if (priv->report_scan_result)
90 priv->report_scan_result = false;
91 if (priv->scan_pending_on_block) {
92 priv->scan_pending_on_block = false;
93 up(&priv->async_sem);
94 }
95 break;
96
97 case HostCmd_CMD_MAC_CONTROL:
98 break;
99
100 default:
101 break;
102 }
103 /* Handling errors here */
104 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
105
106 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
107 adapter->curr_cmd = NULL;
108 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
109
110 return;
111}
112
113/*
114 * This function handles the command response of get RSSI info.
115 *
116 * Handling includes changing the header fields into CPU format
117 * and saving the following parameters in driver -
118 * - Last data and beacon RSSI value
119 * - Average data and beacon RSSI value
120 * - Last data and beacon NF value
121 * - Average data and beacon NF value
122 *
123 * The parameters are send to the application as well, along with
124 * calculated SNR values.
125 */
126static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
127 struct host_cmd_ds_command *resp,
128 void *data_buf)
129{
130 struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
131 &resp->params.rssi_info_rsp;
132 struct mwifiex_ds_get_signal *signal = NULL;
133
134 priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
135 priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
136
137 priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
138 priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
139
140 priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
141 priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
142
143 priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
144 priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
145
146 /* Need to indicate IOCTL complete */
147 if (data_buf) {
148 signal = (struct mwifiex_ds_get_signal *) data_buf;
149 memset(signal, 0, sizeof(struct mwifiex_ds_get_signal));
150
151 signal->selector = ALL_RSSI_INFO_MASK;
152
153 /* RSSI */
154 signal->bcn_rssi_last = priv->bcn_rssi_last;
155 signal->bcn_rssi_avg = priv->bcn_rssi_avg;
156 signal->data_rssi_last = priv->data_rssi_last;
157 signal->data_rssi_avg = priv->data_rssi_avg;
158
159 /* SNR */
160 signal->bcn_snr_last =
161 CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
162 signal->bcn_snr_avg =
163 CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
164 signal->data_snr_last =
165 CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
166 signal->data_snr_avg =
167 CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
168
169 /* NF */
170 signal->bcn_nf_last = priv->bcn_nf_last;
171 signal->bcn_nf_avg = priv->bcn_nf_avg;
172 signal->data_nf_last = priv->data_nf_last;
173 signal->data_nf_avg = priv->data_nf_avg;
174 }
175
176 return 0;
177}
178
179/*
180 * This function handles the command response of set/get SNMP
181 * MIB parameters.
182 *
183 * Handling includes changing the header fields into CPU format
184 * and saving the parameter in driver.
185 *
186 * The following parameters are supported -
187 * - Fragmentation threshold
188 * - RTS threshold
189 * - Short retry limit
190 */
191static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
192 struct host_cmd_ds_command *resp,
193 void *data_buf)
194{
195 struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
196 u16 oid = le16_to_cpu(smib->oid);
197 u16 query_type = le16_to_cpu(smib->query_type);
198 u32 ul_temp;
199
200 dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
201 " query_type = %#x, buf size = %#x\n",
202 oid, query_type, le16_to_cpu(smib->buf_size));
203 if (query_type == HostCmd_ACT_GEN_GET) {
204 ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
205 if (data_buf)
206 *(u32 *)data_buf = ul_temp;
207 switch (oid) {
208 case FRAG_THRESH_I:
209 dev_dbg(priv->adapter->dev,
210 "info: SNMP_RESP: FragThsd =%u\n", ul_temp);
211 break;
212 case RTS_THRESH_I:
213 dev_dbg(priv->adapter->dev,
214 "info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
215 break;
216 case SHORT_RETRY_LIM_I:
217 dev_dbg(priv->adapter->dev,
218 "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
219 break;
220 default:
221 break;
222 }
223 }
224
225 return 0;
226}
227
228/*
229 * This function handles the command response of get log request
230 *
231 * Handling includes changing the header fields into CPU format
232 * and sending the received parameters to application.
233 */
234static int mwifiex_ret_get_log(struct mwifiex_private *priv,
235 struct host_cmd_ds_command *resp,
236 void *data_buf)
237{
238 struct host_cmd_ds_802_11_get_log *get_log =
239 (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
240 struct mwifiex_ds_get_stats *stats = NULL;
241
242 if (data_buf) {
243 stats = (struct mwifiex_ds_get_stats *) data_buf;
244 stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
245 stats->failed = le32_to_cpu(get_log->failed);
246 stats->retry = le32_to_cpu(get_log->retry);
247 stats->multi_retry = le32_to_cpu(get_log->multi_retry);
248 stats->frame_dup = le32_to_cpu(get_log->frame_dup);
249 stats->rts_success = le32_to_cpu(get_log->rts_success);
250 stats->rts_failure = le32_to_cpu(get_log->rts_failure);
251 stats->ack_failure = le32_to_cpu(get_log->ack_failure);
252 stats->rx_frag = le32_to_cpu(get_log->rx_frag);
253 stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
254 stats->fcs_error = le32_to_cpu(get_log->fcs_error);
255 stats->tx_frame = le32_to_cpu(get_log->tx_frame);
256 stats->wep_icv_error[0] =
257 le32_to_cpu(get_log->wep_icv_err_cnt[0]);
258 stats->wep_icv_error[1] =
259 le32_to_cpu(get_log->wep_icv_err_cnt[1]);
260 stats->wep_icv_error[2] =
261 le32_to_cpu(get_log->wep_icv_err_cnt[2]);
262 stats->wep_icv_error[3] =
263 le32_to_cpu(get_log->wep_icv_err_cnt[3]);
264 }
265
266 return 0;
267}
268
269/*
270 * This function handles the command response of set/get Tx rate
271 * configurations.
272 *
273 * Handling includes changing the header fields into CPU format
274 * and saving the following parameters in driver -
275 * - DSSS rate bitmap
276 * - OFDM rate bitmap
277 * - HT MCS rate bitmaps
278 *
279 * Based on the new rate bitmaps, the function re-evaluates if
280 * auto data rate has been activated. If not, it sends another
281 * query to the firmware to get the current Tx data rate and updates
282 * the driver value.
283 */
284static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
285 struct host_cmd_ds_command *resp,
286 void *data_buf)
287{
288 struct mwifiex_adapter *adapter = priv->adapter;
289 struct mwifiex_rate_cfg *ds_rate = NULL;
290 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
291 struct mwifiex_rate_scope *rate_scope;
292 struct mwifiex_ie_types_header *head = NULL;
293 u16 tlv, tlv_buf_len;
294 u8 *tlv_buf;
295 u32 i;
296 int ret = 0;
297
298 tlv_buf = (u8 *) ((u8 *) rate_cfg) +
299 sizeof(struct host_cmd_ds_tx_rate_cfg);
300 tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
301
302 while (tlv_buf && tlv_buf_len > 0) {
303 tlv = (*tlv_buf);
304 tlv = tlv | (*(tlv_buf + 1) << 8);
305
306 switch (tlv) {
307 case TLV_TYPE_RATE_SCOPE:
308 rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
309 priv->bitmap_rates[0] =
310 le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
311 priv->bitmap_rates[1] =
312 le16_to_cpu(rate_scope->ofdm_rate_bitmap);
313 for (i = 0;
314 i <
315 sizeof(rate_scope->ht_mcs_rate_bitmap) /
316 sizeof(u16); i++)
317 priv->bitmap_rates[2 + i] =
318 le16_to_cpu(rate_scope->
319 ht_mcs_rate_bitmap[i]);
320 break;
321 /* Add RATE_DROP tlv here */
322 }
323
324 head = (struct mwifiex_ie_types_header *) tlv_buf;
325 tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
326 tlv_buf_len -= le16_to_cpu(head->len);
327 }
328
329 priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
330
331 if (priv->is_data_rate_auto)
332 priv->data_rate = 0;
333 else
334 ret = mwifiex_prepare_cmd(priv,
335 HostCmd_CMD_802_11_TX_RATE_QUERY,
336 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
337
338 if (data_buf) {
339 ds_rate = (struct mwifiex_rate_cfg *) data_buf;
340 if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) {
341 if (priv->is_data_rate_auto) {
342 ds_rate->is_rate_auto = 1;
343 } else {
344 ds_rate->rate =
345 mwifiex_get_rate_index(adapter,
346 priv->
347 bitmap_rates,
348 sizeof(priv->
349 bitmap_rates));
350 if (ds_rate->rate >=
351 MWIFIEX_RATE_BITMAP_OFDM0
352 && ds_rate->rate <=
353 MWIFIEX_RATE_BITMAP_OFDM7)
354 ds_rate->rate -=
355 (MWIFIEX_RATE_BITMAP_OFDM0 -
356 MWIFIEX_RATE_INDEX_OFDM0);
357 if (ds_rate->rate >=
358 MWIFIEX_RATE_BITMAP_MCS0
359 && ds_rate->rate <=
360 MWIFIEX_RATE_BITMAP_MCS127)
361 ds_rate->rate -=
362 (MWIFIEX_RATE_BITMAP_MCS0 -
363 MWIFIEX_RATE_INDEX_MCS0);
364 }
365 }
366 }
367
368 return ret;
369}
370
371/*
372 * This function handles the command response of get Tx power level.
373 *
374 * Handling includes saving the maximum and minimum Tx power levels
375 * in driver, as well as sending the values to user.
376 */
377static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
378{
379 int length = -1, max_power = -1, min_power = -1;
380 struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
381 struct mwifiex_power_group *pg = NULL;
382
383 if (data_buf) {
384 pg_tlv_hdr =
385 (struct mwifiex_types_power_group *) ((u8 *) data_buf
386 + sizeof(struct host_cmd_ds_txpwr_cfg));
387 pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr +
388 sizeof(struct mwifiex_types_power_group));
389 length = pg_tlv_hdr->length;
390 if (length > 0) {
391 max_power = pg->power_max;
392 min_power = pg->power_min;
393 length -= sizeof(struct mwifiex_power_group);
394 }
395 while (length) {
396 pg++;
397 if (max_power < pg->power_max)
398 max_power = pg->power_max;
399
400 if (min_power > pg->power_min)
401 min_power = pg->power_min;
402
403 length -= sizeof(struct mwifiex_power_group);
404 }
405 if (pg_tlv_hdr->length > 0) {
406 priv->min_tx_power_level = (u8) min_power;
407 priv->max_tx_power_level = (u8) max_power;
408 }
409 } else {
410 return -1;
411 }
412
413 return 0;
414}
415
416/*
417 * This function handles the command response of set/get Tx power
418 * configurations.
419 *
420 * Handling includes changing the header fields into CPU format
421 * and saving the current Tx power level in driver.
422 */
423static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
424 struct host_cmd_ds_command *resp,
425 void *data_buf)
426{
427 struct mwifiex_adapter *adapter = priv->adapter;
428 struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
429 struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
430 struct mwifiex_power_group *pg = NULL;
431 u16 action = le16_to_cpu(txp_cfg->action);
432
433 switch (action) {
434 case HostCmd_ACT_GEN_GET:
435 {
436 pg_tlv_hdr =
437 (struct mwifiex_types_power_group *) ((u8 *)
438 txp_cfg +
439 sizeof
440 (struct
441 host_cmd_ds_txpwr_cfg));
442 pg = (struct mwifiex_power_group *) ((u8 *)
443 pg_tlv_hdr +
444 sizeof(struct
445 mwifiex_types_power_group));
446 if (adapter->hw_status ==
447 MWIFIEX_HW_STATUS_INITIALIZING)
448 mwifiex_get_power_level(priv, txp_cfg);
449 priv->tx_power_level = (u16) pg->power_min;
450 break;
451 }
452 case HostCmd_ACT_GEN_SET:
453 if (le32_to_cpu(txp_cfg->mode)) {
454 pg_tlv_hdr =
455 (struct mwifiex_types_power_group *) ((u8 *)
456 txp_cfg +
457 sizeof
458 (struct
459 host_cmd_ds_txpwr_cfg));
460 pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr
461 +
462 sizeof(struct
463 mwifiex_types_power_group));
464 if (pg->power_max == pg->power_min)
465 priv->tx_power_level = (u16) pg->power_min;
466 }
467 break;
468 default:
469 dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
470 action);
471 return 0;
472 }
473 dev_dbg(adapter->dev,
474 "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
475 priv->tx_power_level, priv->max_tx_power_level,
476 priv->min_tx_power_level);
477
478 return 0;
479}
480
481/*
482 * This function handles the command response of set/get MAC address.
483 *
484 * Handling includes saving the MAC address in driver.
485 */
486static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
487 struct host_cmd_ds_command *resp)
488{
489 struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
490 &resp->params.mac_addr;
491
492 memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
493
494 dev_dbg(priv->adapter->dev,
495 "info: set mac address: %pM\n", priv->curr_addr);
496
497 return 0;
498}
499
500/*
501 * This function handles the command response of set/get MAC multicast
502 * address.
503 */
504static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
505 struct host_cmd_ds_command *resp)
506{
507 return 0;
508}
509
510/*
511 * This function handles the command response of get Tx rate query.
512 *
513 * Handling includes changing the header fields into CPU format
514 * and saving the Tx rate and HT information parameters in driver.
515 *
516 * Both rate configuration and current data rate can be retrieved
517 * with this request.
518 */
519static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
520 struct host_cmd_ds_command *resp)
521{
522 struct mwifiex_adapter *adapter = priv->adapter;
523
524 priv->tx_rate = resp->params.tx_rate.tx_rate;
525 priv->tx_htinfo = resp->params.tx_rate.ht_info;
526 if (!priv->is_data_rate_auto)
527 priv->data_rate =
528 mwifiex_index_to_data_rate(adapter, priv->tx_rate,
529 priv->tx_htinfo);
530
531 return 0;
532}
533
534/*
535 * This function handles the command response of a deauthenticate
536 * command.
537 *
538 * If the deauthenticated MAC matches the current BSS MAC, the connection
539 * state is reset.
540 */
541static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
542 struct host_cmd_ds_command *resp)
543{
544 struct mwifiex_adapter *adapter = priv->adapter;
545
546 adapter->dbg.num_cmd_deauth++;
547 if (!memcmp(resp->params.deauth.mac_addr,
548 &priv->curr_bss_params.bss_descriptor.mac_address,
549 sizeof(resp->params.deauth.mac_addr)))
550 mwifiex_reset_connect_state(priv);
551
552 return 0;
553}
554
555/*
556 * This function handles the command response of ad-hoc stop.
557 *
558 * The function resets the connection state in driver.
559 */
560static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
561 struct host_cmd_ds_command *resp)
562{
563 mwifiex_reset_connect_state(priv);
564 return 0;
565}
566
567/*
568 * This function handles the command response of set/get key material.
569 *
570 * Handling includes updating the driver parameters to reflect the
571 * changes.
572 */
573static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
574 struct host_cmd_ds_command *resp)
575{
576 struct host_cmd_ds_802_11_key_material *key =
577 &resp->params.key_material;
578
579 if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
580 if ((le16_to_cpu(key->key_param_set.key_info) &
581 KEY_INFO_TKIP_MCAST)) {
582 dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
583 priv->wpa_is_gtk_set = true;
584 priv->scan_block = false;
585 }
586 }
587
588 memset(priv->aes_key.key_param_set.key, 0,
589 sizeof(key->key_param_set.key));
590 priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
591 memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
592 le16_to_cpu(priv->aes_key.key_param_set.key_len));
593
594 return 0;
595}
596
597/*
598 * This function handles the command response of get 11d domain information.
599 */
600static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
601 struct host_cmd_ds_command *resp)
602{
603 struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
604 &resp->params.domain_info_resp;
605 struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
606 u16 action = le16_to_cpu(domain_info->action);
607 u8 no_of_triplet = 0;
608
609 no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
610 IEEE80211_COUNTRY_STRING_LEN) /
611 sizeof(struct ieee80211_country_ie_triplet));
612
613 dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
614 " no_of_triplet=%d\n", no_of_triplet);
615
616 if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
617 dev_warn(priv->adapter->dev,
618 "11D: invalid number of triplets %d "
619 "returned!!\n", no_of_triplet);
620 return -1;
621 }
622
623 switch (action) {
624 case HostCmd_ACT_GEN_SET: /* Proc Set Action */
625 break;
626 case HostCmd_ACT_GEN_GET:
627 break;
628 default:
629 dev_err(priv->adapter->dev,
630 "11D: invalid action:%d\n", domain_info->action);
631 return -1;
632 }
633
634 return 0;
635}
636
637/*
638 * This function handles the command response of get RF channel.
639 *
640 * Handling includes changing the header fields into CPU format
641 * and saving the new channel in driver.
642 */
643static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
644 struct host_cmd_ds_command *resp,
645 void *data_buf)
646{
647 struct host_cmd_ds_802_11_rf_channel *rf_channel =
648 &resp->params.rf_channel;
649 u16 new_channel = le16_to_cpu(rf_channel->current_channel);
650
651 if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
652 dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
653 priv->curr_bss_params.bss_descriptor.channel,
654 new_channel);
655 /* Update the channel again */
656 priv->curr_bss_params.bss_descriptor.channel = new_channel;
657 }
658 if (data_buf)
659 *((u16 *)data_buf) = new_channel;
660
661 return 0;
662}
663
664/*
665 * This function handles the command response of get extended version.
666 *
667 * Handling includes forming the extended version string and sending it
668 * to application.
669 */
670static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
671 struct host_cmd_ds_command *resp,
672 void *data_buf)
673{
674 struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
675 struct host_cmd_ds_version_ext *version_ext = NULL;
676
677 if (data_buf) {
678 version_ext = (struct host_cmd_ds_version_ext *)data_buf;
679 version_ext->version_str_sel = ver_ext->version_str_sel;
680 memcpy(version_ext->version_str, ver_ext->version_str,
681 sizeof(char) * 128);
682 memcpy(priv->version_str, ver_ext->version_str, 128);
683 }
684 return 0;
685}
686
687/*
688 * This function handles the command response of register access.
689 *
690 * The register value and offset are returned to the user. For EEPROM
691 * access, the byte count is also returned.
692 */
693static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
694 void *data_buf)
695{
696 struct mwifiex_ds_reg_rw *reg_rw = NULL;
697 struct mwifiex_ds_read_eeprom *eeprom = NULL;
698
699 if (data_buf) {
700 reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
701 eeprom = (struct mwifiex_ds_read_eeprom *) data_buf;
702 switch (type) {
703 case HostCmd_CMD_MAC_REG_ACCESS:
704 {
705 struct host_cmd_ds_mac_reg_access *reg;
706 reg = (struct host_cmd_ds_mac_reg_access *)
707 &resp->params.mac_reg;
708 reg_rw->offset = cpu_to_le32(
709 (u32) le16_to_cpu(reg->offset));
710 reg_rw->value = reg->value;
711 break;
712 }
713 case HostCmd_CMD_BBP_REG_ACCESS:
714 {
715 struct host_cmd_ds_bbp_reg_access *reg;
716 reg = (struct host_cmd_ds_bbp_reg_access *)
717 &resp->params.bbp_reg;
718 reg_rw->offset = cpu_to_le32(
719 (u32) le16_to_cpu(reg->offset));
720 reg_rw->value = cpu_to_le32((u32) reg->value);
721 break;
722 }
723
724 case HostCmd_CMD_RF_REG_ACCESS:
725 {
726 struct host_cmd_ds_rf_reg_access *reg;
727 reg = (struct host_cmd_ds_rf_reg_access *)
728 &resp->params.rf_reg;
729 reg_rw->offset = cpu_to_le32(
730 (u32) le16_to_cpu(reg->offset));
731 reg_rw->value = cpu_to_le32((u32) reg->value);
732 break;
733 }
734 case HostCmd_CMD_PMIC_REG_ACCESS:
735 {
736 struct host_cmd_ds_pmic_reg_access *reg;
737 reg = (struct host_cmd_ds_pmic_reg_access *)
738 &resp->params.pmic_reg;
739 reg_rw->offset = cpu_to_le32(
740 (u32) le16_to_cpu(reg->offset));
741 reg_rw->value = cpu_to_le32((u32) reg->value);
742 break;
743 }
744 case HostCmd_CMD_CAU_REG_ACCESS:
745 {
746 struct host_cmd_ds_rf_reg_access *reg;
747 reg = (struct host_cmd_ds_rf_reg_access *)
748 &resp->params.rf_reg;
749 reg_rw->offset = cpu_to_le32(
750 (u32) le16_to_cpu(reg->offset));
751 reg_rw->value = cpu_to_le32((u32) reg->value);
752 break;
753 }
754 case HostCmd_CMD_802_11_EEPROM_ACCESS:
755 {
756 struct host_cmd_ds_802_11_eeprom_access
757 *cmd_eeprom =
758 (struct host_cmd_ds_802_11_eeprom_access
759 *) &resp->params.eeprom;
760 pr_debug("info: EEPROM read len=%x\n",
761 cmd_eeprom->byte_count);
762 if (le16_to_cpu(eeprom->byte_count) <
763 le16_to_cpu(
764 cmd_eeprom->byte_count)) {
765 eeprom->byte_count = cpu_to_le16(0);
766 pr_debug("info: EEPROM read "
767 "length is too big\n");
768 return -1;
769 }
770 eeprom->offset = cmd_eeprom->offset;
771 eeprom->byte_count = cmd_eeprom->byte_count;
772 if (le16_to_cpu(eeprom->byte_count) > 0)
773 memcpy(&eeprom->value,
774 &cmd_eeprom->value,
775 le16_to_cpu(eeprom->byte_count));
776
777 break;
778 }
779 default:
780 return -1;
781 }
782 }
783 return 0;
784}
785
786/*
787 * This function handles the command response of get IBSS coalescing status.
788 *
789 * If the received BSSID is different than the current one, the current BSSID,
790 * beacon interval, ATIM window and ERP information are updated, along with
791 * changing the ad-hoc state accordingly.
792 */
793static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
794 struct host_cmd_ds_command *resp)
795{
796 struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
797 &(resp->params.ibss_coalescing);
798 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
799
800 if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
801 return 0;
802
803 dev_dbg(priv->adapter->dev,
804 "info: new BSSID %pM\n", ibss_coal_resp->bssid);
805
806 /* If rsp has NULL BSSID, Just return..... No Action */
807 if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
808 dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
809 return 0;
810 }
811
812 /* If BSSID is diff, modify current BSS parameters */
813 if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
814 ibss_coal_resp->bssid, ETH_ALEN)) {
815 /* BSSID */
816 memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
817 ibss_coal_resp->bssid, ETH_ALEN);
818
819 /* Beacon Interval */
820 priv->curr_bss_params.bss_descriptor.beacon_period
821 = le16_to_cpu(ibss_coal_resp->beacon_interval);
822
823 /* ERP Information */
824 priv->curr_bss_params.bss_descriptor.erp_flags =
825 (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
826
827 priv->adhoc_state = ADHOC_COALESCED;
828 }
829
830 return 0;
831}
832
833/*
834 * This function handles the command responses.
835 *
836 * This is a generic function, which calls command specific
837 * response handlers based on the command ID.
838 */
839int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv,
840 u16 cmdresp_no, void *cmd_buf, void *wq_buf)
841{
842 int ret = 0;
843 struct mwifiex_adapter *adapter = priv->adapter;
844 struct host_cmd_ds_command *resp =
845 (struct host_cmd_ds_command *) cmd_buf;
846 struct mwifiex_wait_queue *wait_queue =
847 (struct mwifiex_wait_queue *) wq_buf;
848 void *data_buf = adapter->curr_cmd->data_buf;
849
850 /* If the command is not successful, cleanup and return failure */
851 if (resp->result != HostCmd_RESULT_OK) {
852 mwifiex_process_cmdresp_error(priv, resp, wait_queue);
853 return -1;
854 }
855 /* Command successful, handle response */
856 switch (cmdresp_no) {
857 case HostCmd_CMD_GET_HW_SPEC:
858 ret = mwifiex_ret_get_hw_spec(priv, resp);
859 break;
860 case HostCmd_CMD_MAC_CONTROL:
861 break;
862 case HostCmd_CMD_802_11_MAC_ADDRESS:
863 ret = mwifiex_ret_802_11_mac_address(priv, resp);
864 break;
865 case HostCmd_CMD_MAC_MULTICAST_ADR:
866 ret = mwifiex_ret_mac_multicast_adr(priv, resp);
867 break;
868 case HostCmd_CMD_TX_RATE_CFG:
869 ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
870 break;
871 case HostCmd_CMD_802_11_SCAN:
872 ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
873 wait_queue = NULL;
874 adapter->curr_cmd->wq_buf = NULL;
875 break;
876 case HostCmd_CMD_802_11_BG_SCAN_QUERY:
877 ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
878 dev_dbg(adapter->dev,
879 "info: CMD_RESP: BG_SCAN result is ready!\n");
880 break;
881 case HostCmd_CMD_TXPWR_CFG:
882 ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf);
883 break;
884 case HostCmd_CMD_802_11_PS_MODE_ENH:
885 ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
886 break;
887 case HostCmd_CMD_802_11_HS_CFG_ENH:
888 ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
889 break;
890 case HostCmd_CMD_802_11_ASSOCIATE:
891 ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue);
892 break;
893 case HostCmd_CMD_802_11_DEAUTHENTICATE:
894 ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
895 break;
896 case HostCmd_CMD_802_11_AD_HOC_START:
897 case HostCmd_CMD_802_11_AD_HOC_JOIN:
898 ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue);
899 break;
900 case HostCmd_CMD_802_11_AD_HOC_STOP:
901 ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
902 break;
903 case HostCmd_CMD_802_11_GET_LOG:
904 ret = mwifiex_ret_get_log(priv, resp, data_buf);
905 break;
906 case HostCmd_CMD_RSSI_INFO:
907 ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
908 break;
909 case HostCmd_CMD_802_11_SNMP_MIB:
910 ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
911 break;
912 case HostCmd_CMD_802_11_TX_RATE_QUERY:
913 ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
914 break;
915 case HostCmd_CMD_802_11_RF_CHANNEL:
916 ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
917 break;
918 case HostCmd_CMD_VERSION_EXT:
919 ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
920 break;
921 case HostCmd_CMD_FUNC_INIT:
922 case HostCmd_CMD_FUNC_SHUTDOWN:
923 break;
924 case HostCmd_CMD_802_11_KEY_MATERIAL:
925 ret = mwifiex_ret_802_11_key_material(priv, resp);
926 break;
927 case HostCmd_CMD_802_11D_DOMAIN_INFO:
928 ret = mwifiex_ret_802_11d_domain_info(priv, resp);
929 break;
930 case HostCmd_CMD_11N_ADDBA_REQ:
931 ret = mwifiex_ret_11n_addba_req(priv, resp);
932 break;
933 case HostCmd_CMD_11N_DELBA:
934 ret = mwifiex_ret_11n_delba(priv, resp);
935 break;
936 case HostCmd_CMD_11N_ADDBA_RSP:
937 ret = mwifiex_ret_11n_addba_resp(priv, resp);
938 break;
939 case HostCmd_CMD_RECONFIGURE_TX_BUFF:
940 adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
941 tx_buf.buff_size);
942 adapter->tx_buf_size = (adapter->tx_buf_size /
943 MWIFIEX_SDIO_BLOCK_SIZE) *
944 MWIFIEX_SDIO_BLOCK_SIZE;
945 adapter->curr_tx_buf_size = adapter->tx_buf_size;
946 dev_dbg(adapter->dev,
947 "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
948 adapter->max_tx_buf_size, adapter->tx_buf_size);
949
950 if (adapter->if_ops.update_mp_end_port)
951 adapter->if_ops.update_mp_end_port(adapter,
952 le16_to_cpu(resp->
953 params.
954 tx_buf.
955 mp_end_port));
956 break;
957 case HostCmd_CMD_AMSDU_AGGR_CTRL:
958 ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf);
959 break;
960 case HostCmd_CMD_WMM_GET_STATUS:
961 ret = mwifiex_ret_wmm_get_status(priv, resp);
962 break;
963 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
964 ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
965 break;
966 case HostCmd_CMD_MAC_REG_ACCESS:
967 case HostCmd_CMD_BBP_REG_ACCESS:
968 case HostCmd_CMD_RF_REG_ACCESS:
969 case HostCmd_CMD_PMIC_REG_ACCESS:
970 case HostCmd_CMD_CAU_REG_ACCESS:
971 case HostCmd_CMD_802_11_EEPROM_ACCESS:
972 ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
973 break;
974 case HostCmd_CMD_SET_BSS_MODE:
975 break;
976 case HostCmd_CMD_11N_CFG:
977 ret = mwifiex_ret_11n_cfg(priv, resp, data_buf);
978 break;
979 default:
980 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
981 resp->command);
982 break;
983 }
984
985 return ret;
986}
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
new file mode 100644
index 000000000000..d4a5c1fcefc2
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -0,0 +1,405 @@
1/*
2 * Marvell Wireless LAN device driver: station event handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * This function resets the connection state.
30 *
31 * The function is invoked after receiving a disconnect event from firmware,
32 * and performs the following actions -
33 * - Set media status to disconnected
34 * - Clean up Tx and Rx packets
35 * - Resets SNR/NF/RSSI value in driver
36 * - Resets security configurations in driver
37 * - Enables auto data rate
38 * - Saves the previous SSID and BSSID so that they can
39 * be used for re-association, if required
40 * - Erases current SSID and BSSID information
41 * - Sends a disconnect event to upper layers/applications.
42 */
43void
44mwifiex_reset_connect_state(struct mwifiex_private *priv)
45{
46 struct mwifiex_adapter *adapter = priv->adapter;
47
48 if (!priv->media_connected)
49 return;
50
51 dev_dbg(adapter->dev, "info: handles disconnect event\n");
52
53 priv->media_connected = false;
54
55 priv->scan_block = false;
56
57 /* Free Tx and Rx packets, report disconnect to upper layer */
58 mwifiex_clean_txrx(priv);
59
60 /* Reset SNR/NF/RSSI values */
61 priv->data_rssi_last = 0;
62 priv->data_nf_last = 0;
63 priv->data_rssi_avg = 0;
64 priv->data_nf_avg = 0;
65 priv->bcn_rssi_last = 0;
66 priv->bcn_nf_last = 0;
67 priv->bcn_rssi_avg = 0;
68 priv->bcn_nf_avg = 0;
69 priv->rxpd_rate = 0;
70 priv->rxpd_htinfo = 0;
71 priv->sec_info.wpa_enabled = false;
72 priv->sec_info.wpa2_enabled = false;
73 priv->wpa_ie_len = 0;
74
75 priv->sec_info.wapi_enabled = false;
76 priv->wapi_ie_len = 0;
77 priv->sec_info.wapi_key_on = false;
78
79 priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE;
80
81 /* Enable auto data rate */
82 priv->is_data_rate_auto = true;
83 priv->data_rate = 0;
84
85 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
86 priv->adhoc_state = ADHOC_IDLE;
87 priv->adhoc_is_link_sensed = false;
88 }
89
90 /*
91 * Memorize the previous SSID and BSSID so
92 * it could be used for re-assoc
93 */
94
95 dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n",
96 priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
97
98 dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n",
99 priv->curr_bss_params.bss_descriptor.ssid.ssid,
100 priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
101
102 memcpy(&priv->prev_ssid,
103 &priv->curr_bss_params.bss_descriptor.ssid,
104 sizeof(struct mwifiex_802_11_ssid));
105
106 memcpy(priv->prev_bssid,
107 priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN);
108
109 /* Need to erase the current SSID and BSSID info */
110 memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));
111
112 adapter->tx_lock_flag = false;
113 adapter->pps_uapsd_mode = false;
114
115 if (adapter->num_cmd_timeout && adapter->curr_cmd)
116 return;
117 priv->media_connected = false;
118 if (!priv->disconnect) {
119 priv->disconnect = 1;
120 dev_dbg(adapter->dev, "info: successfully disconnected from"
121 " %pM: reason code %d\n", priv->cfg_bssid,
122 WLAN_REASON_DEAUTH_LEAVING);
123 cfg80211_disconnected(priv->netdev,
124 WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
125 GFP_KERNEL);
126 queue_work(priv->workqueue, &priv->cfg_workqueue);
127 }
128 if (!netif_queue_stopped(priv->netdev))
129 netif_stop_queue(priv->netdev);
130 if (netif_carrier_ok(priv->netdev))
131 netif_carrier_off(priv->netdev);
132 /* Reset wireless stats signal info */
133 priv->w_stats.qual.level = 0;
134 priv->w_stats.qual.noise = 0;
135}
136
137/*
138 * This function handles events generated by firmware.
139 *
140 * This is a generic function and handles all events.
141 *
142 * Event specific routines are called by this function based
143 * upon the generated event cause.
144 *
145 * For the following events, the function just forwards them to upper
146 * layers, optionally recording the change -
147 * - EVENT_LINK_SENSED
148 * - EVENT_MIC_ERR_UNICAST
149 * - EVENT_MIC_ERR_MULTICAST
150 * - EVENT_PORT_RELEASE
151 * - EVENT_RSSI_LOW
152 * - EVENT_SNR_LOW
153 * - EVENT_MAX_FAIL
154 * - EVENT_RSSI_HIGH
155 * - EVENT_SNR_HIGH
156 * - EVENT_DATA_RSSI_LOW
157 * - EVENT_DATA_SNR_LOW
158 * - EVENT_DATA_RSSI_HIGH
159 * - EVENT_DATA_SNR_HIGH
160 * - EVENT_LINK_QUALITY
161 * - EVENT_PRE_BEACON_LOST
162 * - EVENT_IBSS_COALESCED
163 * - EVENT_WEP_ICV_ERR
164 * - EVENT_BW_CHANGE
165 * - EVENT_HOSTWAKE_STAIE
166 *
167 * For the following events, no action is taken -
168 * - EVENT_MIB_CHANGED
169 * - EVENT_INIT_DONE
170 * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL
171 *
172 * Rest of the supported events requires driver handling -
173 * - EVENT_DEAUTHENTICATED
174 * - EVENT_DISASSOCIATED
175 * - EVENT_LINK_LOST
176 * - EVENT_PS_SLEEP
177 * - EVENT_PS_AWAKE
178 * - EVENT_DEEP_SLEEP_AWAKE
179 * - EVENT_HS_ACT_REQ
180 * - EVENT_ADHOC_BCN_LOST
181 * - EVENT_BG_SCAN_REPORT
182 * - EVENT_WMM_STATUS_CHANGE
183 * - EVENT_ADDBA
184 * - EVENT_DELBA
185 * - EVENT_BA_STREAM_TIEMOUT
186 * - EVENT_AMSDU_AGGR_CTRL
187 */
188int mwifiex_process_sta_event(struct mwifiex_private *priv)
189{
190 struct mwifiex_adapter *adapter = priv->adapter;
191 int ret = 0;
192 u32 eventcause = adapter->event_cause;
193
194 switch (eventcause) {
195 case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
196 dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL,"
197 " ignoring it\n");
198 break;
199 case EVENT_LINK_SENSED:
200 dev_dbg(adapter->dev, "event: LINK_SENSED\n");
201 if (!netif_carrier_ok(priv->netdev))
202 netif_carrier_on(priv->netdev);
203 if (netif_queue_stopped(priv->netdev))
204 netif_wake_queue(priv->netdev);
205 break;
206
207 case EVENT_DEAUTHENTICATED:
208 dev_dbg(adapter->dev, "event: Deauthenticated\n");
209 adapter->dbg.num_event_deauth++;
210 if (priv->media_connected)
211 mwifiex_reset_connect_state(priv);
212 break;
213
214 case EVENT_DISASSOCIATED:
215 dev_dbg(adapter->dev, "event: Disassociated\n");
216 adapter->dbg.num_event_disassoc++;
217 if (priv->media_connected)
218 mwifiex_reset_connect_state(priv);
219 break;
220
221 case EVENT_LINK_LOST:
222 dev_dbg(adapter->dev, "event: Link lost\n");
223 adapter->dbg.num_event_link_lost++;
224 if (priv->media_connected)
225 mwifiex_reset_connect_state(priv);
226 break;
227
228 case EVENT_PS_SLEEP:
229 dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
230
231 adapter->ps_state = PS_STATE_PRE_SLEEP;
232
233 mwifiex_check_ps_cond(adapter);
234 break;
235
236 case EVENT_PS_AWAKE:
237 dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
238 if (!adapter->pps_uapsd_mode &&
239 priv->media_connected &&
240 adapter->sleep_period.period) {
241 adapter->pps_uapsd_mode = true;
242 dev_dbg(adapter->dev,
243 "event: PPS/UAPSD mode activated\n");
244 }
245 adapter->tx_lock_flag = false;
246 if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
247 if (mwifiex_check_last_packet_indication(priv)) {
248 if (!adapter->data_sent) {
249 if (!mwifiex_send_null_packet(priv,
250 MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET
251 |
252 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET))
253 adapter->ps_state =
254 PS_STATE_SLEEP;
255 return 0;
256 }
257 }
258 }
259 adapter->ps_state = PS_STATE_AWAKE;
260 adapter->pm_wakeup_card_req = false;
261 adapter->pm_wakeup_fw_try = false;
262
263 break;
264
265 case EVENT_DEEP_SLEEP_AWAKE:
266 adapter->if_ops.wakeup_complete(adapter);
267 dev_dbg(adapter->dev, "event: DS_AWAKE\n");
268 if (adapter->is_deep_sleep)
269 adapter->is_deep_sleep = false;
270 break;
271
272 case EVENT_HS_ACT_REQ:
273 dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
274 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH,
275 0, 0, NULL, NULL);
276 break;
277
278 case EVENT_MIC_ERR_UNICAST:
279 dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
280 break;
281
282 case EVENT_MIC_ERR_MULTICAST:
283 dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
284 break;
285 case EVENT_MIB_CHANGED:
286 case EVENT_INIT_DONE:
287 break;
288
289 case EVENT_ADHOC_BCN_LOST:
290 dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
291 priv->adhoc_is_link_sensed = false;
292 mwifiex_clean_txrx(priv);
293 if (!netif_queue_stopped(priv->netdev))
294 netif_stop_queue(priv->netdev);
295 if (netif_carrier_ok(priv->netdev))
296 netif_carrier_off(priv->netdev);
297 break;
298
299 case EVENT_BG_SCAN_REPORT:
300 dev_dbg(adapter->dev, "event: BGS_REPORT\n");
301 /* Clear the previous scan result */
302 memset(adapter->scan_table, 0x00,
303 sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
304 adapter->num_in_scan_table = 0;
305 adapter->bcn_buf_end = adapter->bcn_buf;
306 ret = mwifiex_prepare_cmd(priv,
307 HostCmd_CMD_802_11_BG_SCAN_QUERY,
308 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
309 break;
310
311 case EVENT_PORT_RELEASE:
312 dev_dbg(adapter->dev, "event: PORT RELEASE\n");
313 break;
314
315 case EVENT_WMM_STATUS_CHANGE:
316 dev_dbg(adapter->dev, "event: WMM status changed\n");
317 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS,
318 0, 0, NULL, NULL);
319 break;
320
321 case EVENT_RSSI_LOW:
322 dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
323 break;
324 case EVENT_SNR_LOW:
325 dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n");
326 break;
327 case EVENT_MAX_FAIL:
328 dev_dbg(adapter->dev, "event: MAX_FAIL\n");
329 break;
330 case EVENT_RSSI_HIGH:
331 dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
332 break;
333 case EVENT_SNR_HIGH:
334 dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n");
335 break;
336 case EVENT_DATA_RSSI_LOW:
337 dev_dbg(adapter->dev, "event: Data RSSI_LOW\n");
338 break;
339 case EVENT_DATA_SNR_LOW:
340 dev_dbg(adapter->dev, "event: Data SNR_LOW\n");
341 break;
342 case EVENT_DATA_RSSI_HIGH:
343 dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n");
344 break;
345 case EVENT_DATA_SNR_HIGH:
346 dev_dbg(adapter->dev, "event: Data SNR_HIGH\n");
347 break;
348 case EVENT_LINK_QUALITY:
349 dev_dbg(adapter->dev, "event: Link Quality\n");
350 break;
351 case EVENT_PRE_BEACON_LOST:
352 dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n");
353 break;
354 case EVENT_IBSS_COALESCED:
355 dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
356 ret = mwifiex_prepare_cmd(priv,
357 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
358 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
359 break;
360 case EVENT_ADDBA:
361 dev_dbg(adapter->dev, "event: ADDBA Request\n");
362 mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
363 HostCmd_ACT_GEN_SET, 0, NULL,
364 adapter->event_body);
365 break;
366 case EVENT_DELBA:
367 dev_dbg(adapter->dev, "event: DELBA Request\n");
368 mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
369 break;
370 case EVENT_BA_STREAM_TIEMOUT:
371 dev_dbg(adapter->dev, "event: BA Stream timeout\n");
372 mwifiex_11n_ba_stream_timeout(priv,
373 (struct host_cmd_ds_11n_batimeout
374 *)
375 adapter->event_body);
376 break;
377 case EVENT_AMSDU_AGGR_CTRL:
378 dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n",
379 *(u16 *) adapter->event_body);
380 adapter->tx_buf_size =
381 min(adapter->curr_tx_buf_size,
382 le16_to_cpu(*(__le16 *) adapter->event_body));
383 dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
384 adapter->tx_buf_size);
385 break;
386
387 case EVENT_WEP_ICV_ERR:
388 dev_dbg(adapter->dev, "event: WEP ICV error\n");
389 break;
390
391 case EVENT_BW_CHANGE:
392 dev_dbg(adapter->dev, "event: BW Change\n");
393 break;
394
395 case EVENT_HOSTWAKE_STAIE:
396 dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
397 break;
398 default:
399 dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
400 eventcause);
401 break;
402 }
403
404 return ret;
405}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
new file mode 100644
index 000000000000..665a519b1403
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -0,0 +1,2478 @@
1/*
2 * Marvell Wireless LAN device driver: functions for station ioctl
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27#include "cfg80211.h"
28
29/*
30 * Copies the multicast address list from device to driver.
31 *
32 * This function does not validate the destination memory for
33 * size, and the calling function must ensure enough memory is
34 * available.
35 */
36static int
37mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
38 struct net_device *dev)
39{
40 int i = 0;
41 struct netdev_hw_addr *ha;
42
43 netdev_for_each_mc_addr(ha, dev)
44 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
45
46 return i;
47}
48
49/*
50 * Allocate and fills a wait queue with proper parameters.
51 *
52 * This function needs to be called before an IOCTL request can be made.
53 * It can handle the following wait options:
54 * MWIFIEX_NO_WAIT - Waiting is disabled
55 * MWIFIEX_IOCTL_WAIT - Waiting is done on IOCTL wait queue
56 * MWIFIEX_CMD_WAIT - Waiting is done on command wait queue
57 * MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue
58 */
59struct mwifiex_wait_queue *
60mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv,
61 u8 wait_option)
62{
63 struct mwifiex_wait_queue *wait = NULL;
64
65 wait = (struct mwifiex_wait_queue *)
66 kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC);
67 if (!wait) {
68 dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n",
69 __func__);
70 return wait;
71 }
72
73 wait->bss_index = priv->bss_index;
74
75 switch (wait_option) {
76 case MWIFIEX_NO_WAIT:
77 wait->enabled = 0;
78 break;
79 case MWIFIEX_IOCTL_WAIT:
80 priv->ioctl_wait_q_woken = false;
81 wait->start_time = jiffies;
82 wait->wait = &priv->ioctl_wait_q;
83 wait->condition = &priv->ioctl_wait_q_woken;
84 wait->enabled = 1;
85 break;
86 case MWIFIEX_CMD_WAIT:
87 priv->cmd_wait_q_woken = false;
88 wait->start_time = jiffies;
89 wait->wait = &priv->cmd_wait_q;
90 wait->condition = &priv->cmd_wait_q_woken;
91 wait->enabled = 1;
92 break;
93 case MWIFIEX_WSTATS_WAIT:
94 priv->w_stats_wait_q_woken = false;
95 wait->start_time = jiffies;
96 wait->wait = &priv->w_stats_wait_q;
97 wait->condition = &priv->w_stats_wait_q_woken;
98 wait->enabled = 1;
99 break;
100 }
101
102 return wait;
103}
104
105/*
106 * Wait queue completion handler.
107 *
108 * This function waits on a particular wait queue.
109 * For NO_WAIT option, it returns immediately. It also cancels the
110 * pending IOCTL request after waking up, in case of errors.
111 */
112static void
113mwifiex_wait_ioctl_complete(struct mwifiex_private *priv,
114 struct mwifiex_wait_queue *wait,
115 u8 wait_option)
116{
117 bool cancel_flag = false;
118
119 switch (wait_option) {
120 case MWIFIEX_NO_WAIT:
121 break;
122 case MWIFIEX_IOCTL_WAIT:
123 wait_event_interruptible(priv->ioctl_wait_q,
124 priv->ioctl_wait_q_woken);
125 if (!priv->ioctl_wait_q_woken)
126 cancel_flag = true;
127 break;
128 case MWIFIEX_CMD_WAIT:
129 wait_event_interruptible(priv->cmd_wait_q,
130 priv->cmd_wait_q_woken);
131 if (!priv->cmd_wait_q_woken)
132 cancel_flag = true;
133 break;
134 case MWIFIEX_WSTATS_WAIT:
135 wait_event_interruptible(priv->w_stats_wait_q,
136 priv->w_stats_wait_q_woken);
137 if (!priv->w_stats_wait_q_woken)
138 cancel_flag = true;
139 break;
140 }
141 if (cancel_flag) {
142 mwifiex_cancel_pending_ioctl(priv->adapter, wait);
143 dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n",
144 wait, wait_option);
145 }
146
147 return;
148}
149
150/*
151 * The function waits for the request to complete and issues the
152 * completion handler, if required.
153 */
154int mwifiex_request_ioctl(struct mwifiex_private *priv,
155 struct mwifiex_wait_queue *wait,
156 int status, u8 wait_option)
157{
158 switch (status) {
159 case -EINPROGRESS:
160 dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n",
161 wait, wait_option);
162 atomic_inc(&priv->adapter->ioctl_pending);
163 /* Status pending, wake up main process */
164 queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
165
166 /* Wait for completion */
167 if (wait_option) {
168 mwifiex_wait_ioctl_complete(priv, wait, wait_option);
169 status = wait->status;
170 }
171 break;
172 case 0:
173 case -1:
174 case -EBUSY:
175 default:
176 break;
177 }
178 return status;
179}
180EXPORT_SYMBOL_GPL(mwifiex_request_ioctl);
181
182/*
183 * IOCTL request handler to set/get MAC address.
184 *
185 * This function prepares the correct firmware command and
186 * issues it to get the extended version information.
187 */
188static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv,
189 struct mwifiex_wait_queue *wait,
190 u8 action, u8 *mac)
191{
192 int ret = 0;
193
194 if ((action == HostCmd_ACT_GEN_GET) && mac) {
195 memcpy(mac, priv->curr_addr, ETH_ALEN);
196 return 0;
197 }
198
199 /* Send request to firmware */
200 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
201 action, 0, wait, mac);
202 if (!ret)
203 ret = -EINPROGRESS;
204
205 return ret;
206}
207
208/*
209 * Sends IOCTL request to set MAC address.
210 *
211 * This function allocates the IOCTL request buffer, fills it
212 * with requisite parameters and calls the IOCTL handler.
213 */
214int mwifiex_request_set_mac_address(struct mwifiex_private *priv)
215{
216 struct mwifiex_wait_queue *wait = NULL;
217 int status = 0;
218 u8 wait_option = MWIFIEX_CMD_WAIT;
219
220 /* Allocate wait buffer */
221 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
222 if (!wait)
223 return -ENOMEM;
224
225 status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET,
226 NULL);
227
228 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
229 if (!status)
230 memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
231 else
232 dev_err(priv->adapter->dev, "set mac address failed: status=%d"
233 " error_code=%#x\n", status, wait->status);
234
235 kfree(wait);
236 return status;
237}
238
239/*
240 * IOCTL request handler to set multicast list.
241 *
242 * This function prepares the correct firmware command and
243 * issues it to set the multicast list.
244 *
245 * This function can be used to enable promiscuous mode, or enable all
246 * multicast packets, or to enable selective multicast.
247 */
248static int
249mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv,
250 struct mwifiex_wait_queue *wait,
251 u16 action,
252 struct mwifiex_multicast_list *mcast_list)
253{
254 int ret = 0;
255 u16 old_pkt_filter;
256
257 old_pkt_filter = priv->curr_pkt_filter;
258 if (action == HostCmd_ACT_GEN_GET)
259 return -1;
260
261 if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
262 dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
263 priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
264 priv->curr_pkt_filter &=
265 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
266 } else {
267 /* Multicast */
268 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
269 if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) {
270 dev_dbg(priv->adapter->dev,
271 "info: Enabling All Multicast!\n");
272 priv->curr_pkt_filter |=
273 HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
274 } else {
275 priv->curr_pkt_filter &=
276 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
277 if (mcast_list->num_multicast_addr) {
278 dev_dbg(priv->adapter->dev,
279 "info: Set multicast list=%d\n",
280 mcast_list->num_multicast_addr);
281 /* Set multicast addresses to firmware */
282 if (old_pkt_filter == priv->curr_pkt_filter) {
283 /* Send request to firmware */
284 ret = mwifiex_prepare_cmd(priv,
285 HostCmd_CMD_MAC_MULTICAST_ADR,
286 action, 0, wait, mcast_list);
287 if (!ret)
288 ret = -EINPROGRESS;
289 } else {
290 /* Send request to firmware */
291 ret = mwifiex_prepare_cmd(priv,
292 HostCmd_CMD_MAC_MULTICAST_ADR,
293 action, 0, NULL,
294 mcast_list);
295 }
296 }
297 }
298 }
299 dev_dbg(priv->adapter->dev,
300 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
301 old_pkt_filter, priv->curr_pkt_filter);
302 if (old_pkt_filter != priv->curr_pkt_filter) {
303 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action,
304 0, wait, &priv->curr_pkt_filter);
305 if (!ret)
306 ret = -EINPROGRESS;
307 }
308
309 return ret;
310}
311
312/*
313 * Sends IOCTL request to set multicast list.
314 *
315 * This function allocates the IOCTL request buffer, fills it
316 * with requisite parameters and calls the IOCTL handler.
317 */
318void
319mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
320 struct net_device *dev)
321{
322 struct mwifiex_wait_queue *wait = NULL;
323 struct mwifiex_multicast_list mcast_list;
324 u8 wait_option = MWIFIEX_NO_WAIT;
325 int status = 0;
326
327 /* Allocate wait buffer */
328 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
329 if (!wait)
330 return;
331
332 if (dev->flags & IFF_PROMISC) {
333 mcast_list.mode = MWIFIEX_PROMISC_MODE;
334 } else if (dev->flags & IFF_ALLMULTI ||
335 netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) {
336 mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
337 } else {
338 mcast_list.mode = MWIFIEX_MULTICAST_MODE;
339 if (netdev_mc_count(dev))
340 mcast_list.num_multicast_addr =
341 mwifiex_copy_mcast_addr(&mcast_list, dev);
342 }
343 status = mwifiex_bss_ioctl_multicast_list(priv, wait,
344 HostCmd_ACT_GEN_SET,
345 &mcast_list);
346
347 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
348 if (wait && status != -EINPROGRESS)
349 kfree(wait);
350
351 return;
352}
353
354/*
355 * IOCTL request handler to disconnect from a BSS/IBSS.
356 */
357static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv,
358 struct mwifiex_wait_queue *wait, u8 *mac)
359{
360 return mwifiex_deauthenticate(priv, wait, mac);
361}
362
363/*
364 * Sends IOCTL request to disconnect from a BSS.
365 *
366 * This function allocates the IOCTL request buffer, fills it
367 * with requisite parameters and calls the IOCTL handler.
368 */
369int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac)
370{
371 struct mwifiex_wait_queue *wait = NULL;
372 int status = 0;
373
374 /* Allocate wait buffer */
375 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
376 if (!wait)
377 return -ENOMEM;
378
379 status = mwifiex_bss_ioctl_stop(priv, wait, mac);
380
381 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
382
383 kfree(wait);
384 return status;
385}
386EXPORT_SYMBOL_GPL(mwifiex_disconnect);
387
388/*
389 * IOCTL request handler to join a BSS/IBSS.
390 *
391 * In Ad-Hoc mode, the IBSS is created if not found in scan list.
392 * In both Ad-Hoc and infra mode, an deauthentication is performed
393 * first.
394 */
395static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv,
396 struct mwifiex_wait_queue *wait,
397 struct mwifiex_ssid_bssid *ssid_bssid)
398{
399 int ret = 0;
400 struct mwifiex_adapter *adapter = priv->adapter;
401 s32 i = -1;
402
403 priv->scan_block = false;
404 if (!ssid_bssid)
405 return -1;
406
407 if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) {
408 /* Infra mode */
409 ret = mwifiex_deauthenticate(priv, NULL, NULL);
410 if (ret)
411 return ret;
412
413 /* Search for the requested SSID in the scan table */
414 if (ssid_bssid->ssid.ssid_len)
415 i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid,
416 NULL, MWIFIEX_BSS_MODE_INFRA);
417 else
418 i = mwifiex_find_bssid_in_list(priv,
419 (u8 *) &ssid_bssid->bssid,
420 MWIFIEX_BSS_MODE_INFRA);
421 if (i < 0)
422 return -1;
423
424 dev_dbg(adapter->dev,
425 "info: SSID found in scan list ... associating...\n");
426
427 /* Clear any past association response stored for
428 * application retrieval */
429 priv->assoc_rsp_size = 0;
430 ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]);
431 if (ret)
432 return ret;
433 } else {
434 /* Adhoc mode */
435 /* If the requested SSID matches current SSID, return */
436 if (ssid_bssid->ssid.ssid_len &&
437 (!mwifiex_ssid_cmp
438 (&priv->curr_bss_params.bss_descriptor.ssid,
439 &ssid_bssid->ssid)))
440 return 0;
441
442 /* Exit Adhoc mode first */
443 dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
444 ret = mwifiex_deauthenticate(priv, NULL, NULL);
445 if (ret)
446 return ret;
447
448 priv->adhoc_is_link_sensed = false;
449
450 /* Search for the requested network in the scan table */
451 if (ssid_bssid->ssid.ssid_len)
452 i = mwifiex_find_ssid_in_list(priv,
453 &ssid_bssid->ssid, NULL,
454 MWIFIEX_BSS_MODE_IBSS);
455 else
456 i = mwifiex_find_bssid_in_list(priv,
457 (u8 *)&ssid_bssid->bssid,
458 MWIFIEX_BSS_MODE_IBSS);
459
460 if (i >= 0) {
461 dev_dbg(adapter->dev, "info: network found in scan"
462 " list. Joining...\n");
463 ret = mwifiex_adhoc_join(priv, wait,
464 &adapter->scan_table[i]);
465 if (ret)
466 return ret;
467 } else { /* i >= 0 */
468 dev_dbg(adapter->dev, "info: Network not found in "
469 "the list, creating adhoc with ssid = %s\n",
470 ssid_bssid->ssid.ssid);
471 ret = mwifiex_adhoc_start(priv, wait,
472 &ssid_bssid->ssid);
473 if (ret)
474 return ret;
475 }
476 }
477
478 if (!ret)
479 ret = -EINPROGRESS;
480
481 return ret;
482}
483
484/*
485 * Sends IOCTL request to connect with a BSS.
486 *
487 * This function allocates the IOCTL request buffer, fills it
488 * with requisite parameters and calls the IOCTL handler.
489 */
490int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option,
491 struct mwifiex_ssid_bssid *ssid_bssid)
492{
493 struct mwifiex_wait_queue *wait = NULL;
494 struct mwifiex_ssid_bssid tmp_ssid_bssid;
495 int status = 0;
496
497 /* Stop the O.S. TX queue if needed */
498 if (!netif_queue_stopped(priv->netdev))
499 netif_stop_queue(priv->netdev);
500
501 /* Allocate wait buffer */
502 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
503 if (!wait)
504 return -ENOMEM;
505
506 if (ssid_bssid)
507 memcpy(&tmp_ssid_bssid, ssid_bssid,
508 sizeof(struct mwifiex_ssid_bssid));
509 status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid);
510
511 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
512
513 kfree(wait);
514 return status;
515}
516
517/*
518 * IOCTL request handler to set host sleep configuration.
519 *
520 * This function prepares the correct firmware command and
521 * issues it.
522 */
523static int
524mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv,
525 struct mwifiex_wait_queue *wait,
526 u16 action, struct mwifiex_ds_hs_cfg *hs_cfg)
527{
528 struct mwifiex_adapter *adapter = priv->adapter;
529 int status = 0;
530 u32 prev_cond = 0;
531
532 switch (action) {
533 case HostCmd_ACT_GEN_SET:
534 if (adapter->pps_uapsd_mode) {
535 dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
536 " is blocked in UAPSD/PPS mode\n");
537 status = -1;
538 break;
539 }
540 if (hs_cfg->is_invoke_hostcmd) {
541 if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
542 if (!adapter->is_hs_configured)
543 /* Already cancelled */
544 break;
545 /* Save previous condition */
546 prev_cond = le32_to_cpu(adapter->hs_cfg
547 .conditions);
548 adapter->hs_cfg.conditions =
549 cpu_to_le32(hs_cfg->conditions);
550 } else if (hs_cfg->conditions) {
551 adapter->hs_cfg.conditions =
552 cpu_to_le32(hs_cfg->conditions);
553 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
554 if (hs_cfg->gap)
555 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
556 } else if (adapter->hs_cfg.conditions ==
557 cpu_to_le32(
558 HOST_SLEEP_CFG_CANCEL)) {
559 /* Return failure if no parameters for HS
560 enable */
561 status = -1;
562 break;
563 }
564 status = mwifiex_prepare_cmd(priv,
565 HostCmd_CMD_802_11_HS_CFG_ENH,
566 HostCmd_ACT_GEN_SET,
567 0, wait, &adapter->hs_cfg);
568 if (!status)
569 status = -EINPROGRESS;
570 if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
571 /* Restore previous condition */
572 adapter->hs_cfg.conditions =
573 cpu_to_le32(prev_cond);
574 } else {
575 adapter->hs_cfg.conditions =
576 cpu_to_le32(hs_cfg->conditions);
577 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
578 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
579 }
580 break;
581 case HostCmd_ACT_GEN_GET:
582 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
583 hs_cfg->gpio = adapter->hs_cfg.gpio;
584 hs_cfg->gap = adapter->hs_cfg.gap;
585 break;
586 default:
587 status = -1;
588 break;
589 }
590
591 return status;
592}
593
594/*
595 * Sends IOCTL request to set Host Sleep parameters.
596 *
597 * This function allocates the IOCTL request buffer, fills it
598 * with requisite parameters and calls the IOCTL handler.
599 */
600int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
601 u8 wait_option,
602 struct mwifiex_ds_hs_cfg *hscfg)
603{
604 int ret = 0;
605 struct mwifiex_wait_queue *wait = NULL;
606
607 if (!hscfg)
608 return -ENOMEM;
609
610 /* Allocate wait buffer */
611 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
612 if (!wait)
613 return -ENOMEM;
614
615 ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg);
616
617 ret = mwifiex_request_ioctl(priv, wait, ret, wait_option);
618
619 if (wait && (ret != -EINPROGRESS))
620 kfree(wait);
621 return ret;
622}
623
624/*
625 * Sends IOCTL request to cancel the existing Host Sleep configuration.
626 *
627 * This function allocates the IOCTL request buffer, fills it
628 * with requisite parameters and calls the IOCTL handler.
629 */
630int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option)
631{
632 int ret = 0;
633 struct mwifiex_ds_hs_cfg hscfg;
634
635 /* Cancel Host Sleep */
636 hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
637 hscfg.is_invoke_hostcmd = true;
638 ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
639 wait_option, &hscfg);
640
641 return ret;
642}
643EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
644
645/*
646 * Sends IOCTL request to cancel the existing Host Sleep configuration.
647 *
648 * This function allocates the IOCTL request buffer, fills it
649 * with requisite parameters and calls the IOCTL handler.
650 */
651int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
652{
653 struct mwifiex_ds_hs_cfg hscfg;
654
655 if (adapter->hs_activated) {
656 dev_dbg(adapter->dev, "cmd: HS Already actived\n");
657 return true;
658 }
659
660 /* Enable Host Sleep */
661 adapter->hs_activate_wait_q_woken = false;
662
663 memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param));
664 hscfg.is_invoke_hostcmd = true;
665
666 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
667 MWIFIEX_BSS_ROLE_STA),
668 HostCmd_ACT_GEN_SET,
669 MWIFIEX_IOCTL_WAIT, &hscfg)) {
670 dev_err(adapter->dev, "IOCTL request HS enable failed\n");
671 return false;
672 }
673
674 wait_event_interruptible(adapter->hs_activate_wait_q,
675 adapter->hs_activate_wait_q_woken);
676
677 return true;
678}
679EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
680
681/*
682 * IOCTL request handler to get signal information.
683 *
684 * This function prepares the correct firmware command and
685 * issues it to get the signal (RSSI) information.
686 *
687 * This only works in the connected mode.
688 */
689static int mwifiex_get_info_signal(struct mwifiex_private *priv,
690 struct mwifiex_wait_queue *wait,
691 struct mwifiex_ds_get_signal *signal)
692{
693 int ret = 0;
694
695 if (!wait) {
696 dev_err(priv->adapter->dev, "WAIT information is not present\n");
697 return -1;
698 }
699
700 /* Signal info can be obtained only if connected */
701 if (!priv->media_connected) {
702 dev_dbg(priv->adapter->dev,
703 "info: Can not get signal in disconnected state\n");
704 return -1;
705 }
706
707 /* Send request to firmware */
708 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO,
709 HostCmd_ACT_GEN_GET, 0, wait, signal);
710
711 if (!ret)
712 ret = -EINPROGRESS;
713
714 return ret;
715}
716
717/*
718 * IOCTL request handler to get statistics.
719 *
720 * This function prepares the correct firmware command and
721 * issues it to get the statistics (RSSI) information.
722 */
723static int mwifiex_get_info_stats(struct mwifiex_private *priv,
724 struct mwifiex_wait_queue *wait,
725 struct mwifiex_ds_get_stats *log)
726{
727 int ret = 0;
728
729 if (!wait) {
730 dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n");
731 return -1;
732 }
733
734 /* Send request to firmware */
735 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
736 HostCmd_ACT_GEN_GET, 0, wait, log);
737
738 if (!ret)
739 ret = -EINPROGRESS;
740
741 return ret;
742}
743
744/*
745 * IOCTL request handler to get BSS information.
746 *
747 * This function collates the information from different driver structures
748 * to send to the user.
749 */
750int mwifiex_get_bss_info(struct mwifiex_private *priv,
751 struct mwifiex_bss_info *info)
752{
753 struct mwifiex_adapter *adapter = priv->adapter;
754 struct mwifiex_bssdescriptor *bss_desc;
755 s32 tbl_idx = 0;
756
757 if (!info)
758 return -1;
759
760 /* Get current BSS info */
761 bss_desc = &priv->curr_bss_params.bss_descriptor;
762
763 /* BSS mode */
764 info->bss_mode = priv->bss_mode;
765
766 /* SSID */
767 memcpy(&info->ssid, &bss_desc->ssid,
768 sizeof(struct mwifiex_802_11_ssid));
769
770 /* BSSID */
771 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
772
773 /* Channel */
774 info->bss_chan = bss_desc->channel;
775
776 /* Region code */
777 info->region_code = adapter->region_code;
778
779 /* Scan table index if connected */
780 info->scan_table_idx = 0;
781 if (priv->media_connected) {
782 tbl_idx =
783 mwifiex_find_ssid_in_list(priv, &bss_desc->ssid,
784 bss_desc->mac_address,
785 priv->bss_mode);
786 if (tbl_idx >= 0)
787 info->scan_table_idx = tbl_idx;
788 }
789
790 /* Connection status */
791 info->media_connected = priv->media_connected;
792
793 /* Radio status */
794 info->radio_on = adapter->radio_on;
795
796 /* Tx power information */
797 info->max_power_level = priv->max_tx_power_level;
798 info->min_power_level = priv->min_tx_power_level;
799
800 /* AdHoc state */
801 info->adhoc_state = priv->adhoc_state;
802
803 /* Last beacon NF */
804 info->bcn_nf_last = priv->bcn_nf_last;
805
806 /* wep status */
807 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
808 info->wep_status = true;
809 else
810 info->wep_status = false;
811
812 info->is_hs_configured = adapter->is_hs_configured;
813 info->is_deep_sleep = adapter->is_deep_sleep;
814
815 return 0;
816}
817
818/*
819 * IOCTL request handler to get extended version information.
820 *
821 * This function prepares the correct firmware command and
822 * issues it to get the extended version information.
823 */
824static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv,
825 struct mwifiex_wait_queue *wait,
826 struct mwifiex_ver_ext *ver_ext)
827{
828 int ret = 0;
829
830 /* Send request to firmware */
831 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT,
832 HostCmd_ACT_GEN_GET, 0, wait, ver_ext);
833 if (!ret)
834 ret = -EINPROGRESS;
835
836 return ret;
837}
838
839/*
840 * IOCTL request handler to set/get SNMP MIB parameters.
841 *
842 * This function prepares the correct firmware command and
843 * issues it.
844 *
845 * Currently the following parameters are supported -
846 * Set/get RTS Threshold
847 * Set/get fragmentation threshold
848 * Set/get retry count
849 */
850int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv,
851 struct mwifiex_wait_queue *wait,
852 u32 cmd_oid, u16 action, u32 *value)
853{
854 int ret = 0;
855
856 if (!value)
857 return -1;
858
859 /* Send request to firmware */
860 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
861 action, cmd_oid, wait, value);
862
863 if (!ret)
864 ret = -EINPROGRESS;
865
866 return ret;
867}
868
869/*
870 * IOCTL request handler to set/get band configurations.
871 *
872 * For SET operation, it performs extra checks to make sure the Ad-Hoc
873 * band and channel are compatible. Otherwise it returns an error.
874 *
875 * For GET operation, this function retrieves the following information -
876 * - Infra bands
877 * - Ad-hoc band
878 * - Ad-hoc channel
879 * - Secondary channel offset
880 */
881int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv,
882 u16 action,
883 struct mwifiex_ds_band_cfg *radio_cfg)
884{
885 struct mwifiex_adapter *adapter = priv->adapter;
886 u8 infra_band = 0;
887 u8 adhoc_band = 0;
888 u32 adhoc_channel = 0;
889
890 if (action == HostCmd_ACT_GEN_GET) {
891 /* Infra Bands */
892 radio_cfg->config_bands = adapter->config_bands;
893 /* Adhoc Band */
894 radio_cfg->adhoc_start_band = adapter->adhoc_start_band;
895 /* Adhoc channel */
896 radio_cfg->adhoc_channel = priv->adhoc_channel;
897 /* Secondary channel offset */
898 radio_cfg->sec_chan_offset = adapter->chan_offset;
899 return 0;
900 }
901
902 /* For action = SET */
903 infra_band = (u8) radio_cfg->config_bands;
904 adhoc_band = (u8) radio_cfg->adhoc_start_band;
905 adhoc_channel = radio_cfg->adhoc_channel;
906
907 /* SET Infra band */
908 if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands)
909 return -1;
910
911 adapter->config_bands = infra_band;
912
913 /* SET Ad-hoc Band */
914 if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands)
915 return -1;
916
917 if (adhoc_band)
918 adapter->adhoc_start_band = adhoc_band;
919 adapter->chan_offset = (u8) radio_cfg->sec_chan_offset;
920 /*
921 * If no adhoc_channel is supplied verify if the existing adhoc
922 * channel compiles with new adhoc_band
923 */
924 if (!adhoc_channel) {
925 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
926 (priv, adapter->adhoc_start_band,
927 priv->adhoc_channel)) {
928 /* Pass back the default channel */
929 radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
930 if ((adapter->adhoc_start_band & BAND_A)
931 || (adapter->adhoc_start_band & BAND_AN))
932 radio_cfg->adhoc_channel =
933 DEFAULT_AD_HOC_CHANNEL_A;
934 }
935 } else { /* Retrurn error if adhoc_band and
936 adhoc_channel combination is invalid */
937 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
938 (priv, adapter->adhoc_start_band, (u16) adhoc_channel))
939 return -1;
940 priv->adhoc_channel = (u8) adhoc_channel;
941 }
942 if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN))
943 adapter->adhoc_11n_enabled = true;
944 else
945 adapter->adhoc_11n_enabled = false;
946
947 return 0;
948}
949
950/*
951 * IOCTL request handler to set/get active channel.
952 *
953 * This function performs validity checking on channel/frequency
954 * compatibility and returns failure if not valid.
955 */
956int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action,
957 struct mwifiex_chan_freq_power *chan)
958{
959 struct mwifiex_adapter *adapter = priv->adapter;
960 struct mwifiex_chan_freq_power *cfp = NULL;
961
962 if (!chan)
963 return -1;
964
965 if (action == HostCmd_ACT_GEN_GET) {
966 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
967 priv->curr_bss_params.band,
968 (u16) priv->curr_bss_params.bss_descriptor.
969 channel);
970 chan->channel = cfp->channel;
971 chan->freq = cfp->freq;
972
973 return 0;
974 }
975 if (!chan->channel && !chan->freq)
976 return -1;
977 if (adapter->adhoc_start_band & BAND_AN)
978 adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
979 else if (adapter->adhoc_start_band & BAND_A)
980 adapter->adhoc_start_band = BAND_G | BAND_B;
981 if (chan->channel) {
982 if (chan->channel <= MAX_CHANNEL_BAND_BG)
983 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
984 (priv, 0, (u16) chan->channel);
985 if (!cfp) {
986 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
987 (priv, BAND_A, (u16) chan->channel);
988 if (cfp) {
989 if (adapter->adhoc_11n_enabled)
990 adapter->adhoc_start_band = BAND_A
991 | BAND_AN;
992 else
993 adapter->adhoc_start_band = BAND_A;
994 }
995 }
996 } else {
997 if (chan->freq <= MAX_FREQUENCY_BAND_BG)
998 cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
999 priv, 0, chan->freq);
1000 if (!cfp) {
1001 cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211
1002 (priv, BAND_A, chan->freq);
1003 if (cfp) {
1004 if (adapter->adhoc_11n_enabled)
1005 adapter->adhoc_start_band = BAND_A
1006 | BAND_AN;
1007 else
1008 adapter->adhoc_start_band = BAND_A;
1009 }
1010 }
1011 }
1012 if (!cfp || !cfp->channel) {
1013 dev_err(adapter->dev, "invalid channel/freq\n");
1014 return -1;
1015 }
1016 priv->adhoc_channel = (u8) cfp->channel;
1017 chan->channel = cfp->channel;
1018 chan->freq = cfp->freq;
1019
1020 return 0;
1021}
1022
1023/*
1024 * IOCTL request handler to set/get BSS mode.
1025 *
1026 * This function prepares the correct firmware command and
1027 * issues it to set or get the BSS mode.
1028 *
1029 * In case the mode is changed, a deauthentication is performed
1030 * first by the function automatically.
1031 */
1032int mwifiex_bss_ioctl_mode(struct mwifiex_private *priv,
1033 struct mwifiex_wait_queue *wait,
1034 u16 action, int *mode)
1035{
1036 int ret = 0;
1037
1038 if (!mode)
1039 return -1;
1040
1041 if (action == HostCmd_ACT_GEN_GET) {
1042 *mode = priv->bss_mode;
1043 return 0;
1044 }
1045
1046 if ((priv->bss_mode == *mode) || (*mode == MWIFIEX_BSS_MODE_AUTO)) {
1047 dev_dbg(priv->adapter->dev,
1048 "info: Already set to required mode! No change!\n");
1049 priv->bss_mode = *mode;
1050 return 0;
1051 }
1052
1053 ret = mwifiex_deauthenticate(priv, wait, NULL);
1054
1055 priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN;
1056 priv->bss_mode = *mode;
1057 if (priv->bss_mode != MWIFIEX_BSS_MODE_AUTO) {
1058 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
1059 HostCmd_ACT_GEN_SET, 0, wait, NULL);
1060 if (!ret)
1061 ret = -EINPROGRESS;
1062 }
1063
1064 return ret;
1065}
1066
1067/*
1068 * IOCTL request handler to set/get Ad-Hoc channel.
1069 *
1070 * This function prepares the correct firmware command and
1071 * issues it to set or get the ad-hoc channel.
1072 */
1073static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
1074 struct mwifiex_wait_queue *wait,
1075 u16 action, u16 *channel)
1076{
1077 int ret = 0;
1078
1079 if (action == HostCmd_ACT_GEN_GET) {
1080 if (!priv->media_connected) {
1081 *channel = priv->adhoc_channel;
1082 return ret;
1083 }
1084 } else {
1085 priv->adhoc_channel = (u8) *channel;
1086 }
1087
1088 /* Send request to firmware */
1089 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
1090 action, 0, wait, channel);
1091 if (!ret)
1092 ret = -EINPROGRESS;
1093
1094 return ret;
1095}
1096
1097/*
1098 * IOCTL request handler to find a particular BSS.
1099 *
1100 * The BSS can be searched with either a BSSID or a SSID. If none of
1101 * these are provided, just the best BSS (best RSSI) is returned.
1102 */
1103int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv,
1104 struct mwifiex_wait_queue *wait,
1105 struct mwifiex_ssid_bssid *ssid_bssid)
1106{
1107 struct mwifiex_adapter *adapter = priv->adapter;
1108 int ret = 0;
1109 struct mwifiex_bssdescriptor *bss_desc;
1110 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
1111 u8 mac[ETH_ALEN];
1112 int i = 0;
1113
1114 if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
1115 i = mwifiex_find_bssid_in_list(priv,
1116 (u8 *) ssid_bssid->bssid,
1117 priv->bss_mode);
1118 if (i < 0) {
1119 memcpy(mac, ssid_bssid->bssid, sizeof(mac));
1120 dev_err(adapter->dev, "cannot find bssid %pM\n", mac);
1121 return -1;
1122 }
1123 bss_desc = &adapter->scan_table[i];
1124 memcpy(&ssid_bssid->ssid, &bss_desc->ssid,
1125 sizeof(struct mwifiex_802_11_ssid));
1126 } else if (ssid_bssid->ssid.ssid_len) {
1127 i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL,
1128 priv->bss_mode);
1129 if (i < 0) {
1130 dev_err(adapter->dev, "cannot find ssid %s\n",
1131 ssid_bssid->ssid.ssid);
1132 return -1;
1133 }
1134 bss_desc = &adapter->scan_table[i];
1135 memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN);
1136 } else {
1137 ret = mwifiex_find_best_network(priv, ssid_bssid);
1138 }
1139
1140 return ret;
1141}
1142
1143/*
1144 * IOCTL request handler to change Ad-Hoc channel.
1145 *
1146 * This function allocates the IOCTL request buffer, fills it
1147 * with requisite parameters and calls the IOCTL handler.
1148 *
1149 * The function follows the following steps to perform the change -
1150 * - Get current IBSS information
1151 * - Get current channel
1152 * - If no change is required, return
1153 * - If not connected, change channel and return
1154 * - If connected,
1155 * - Disconnect
1156 * - Change channel
1157 * - Perform specific SSID scan with same SSID
1158 * - Start/Join the IBSS
1159 */
1160int
1161mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
1162{
1163 int ret = 0;
1164 int status = 0;
1165 struct mwifiex_bss_info bss_info;
1166 struct mwifiex_wait_queue *wait = NULL;
1167 u8 wait_option = MWIFIEX_IOCTL_WAIT;
1168 struct mwifiex_ssid_bssid ssid_bssid;
1169 u16 curr_chan = 0;
1170
1171 memset(&bss_info, 0, sizeof(bss_info));
1172
1173 /* Get BSS information */
1174 if (mwifiex_get_bss_info(priv, &bss_info))
1175 return -1;
1176
1177 /* Allocate wait buffer */
1178 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1179 if (!wait)
1180 return -ENOMEM;
1181
1182 /* Get current channel */
1183 status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET,
1184 &curr_chan);
1185
1186 if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
1187 ret = -1;
1188 goto done;
1189 }
1190 if (curr_chan == channel) {
1191 ret = 0;
1192 goto done;
1193 }
1194 dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
1195 curr_chan, channel);
1196
1197 if (!bss_info.media_connected) {
1198 ret = 0;
1199 goto done;
1200 }
1201
1202 /* Do disonnect */
1203 memset(&ssid_bssid, 0, ETH_ALEN);
1204 status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid);
1205
1206 if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
1207 ret = -1;
1208 goto done;
1209 }
1210
1211 status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET,
1212 (u16 *) &channel);
1213
1214 if (mwifiex_request_ioctl(priv, wait, status, wait_option)) {
1215 ret = -1;
1216 goto done;
1217 }
1218
1219 /* Do specific SSID scanning */
1220 if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) {
1221 ret = -1;
1222 goto done;
1223 }
1224 /* Start/Join Adhoc network */
1225 memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
1226 memcpy(&ssid_bssid.ssid, &bss_info.ssid,
1227 sizeof(struct mwifiex_802_11_ssid));
1228
1229 status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid);
1230
1231 if (mwifiex_request_ioctl(priv, wait, status, wait_option))
1232 ret = -1;
1233
1234done:
1235 kfree(wait);
1236 return ret;
1237}
1238
1239/*
1240 * IOCTL request handler to get current driver mode.
1241 *
1242 * This function allocates the IOCTL request buffer, fills it
1243 * with requisite parameters and calls the IOCTL handler.
1244 */
1245int
1246mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option)
1247{
1248 struct mwifiex_wait_queue *wait = NULL;
1249 int status = 0;
1250 int mode = -1;
1251
1252 /* Allocate wait buffer */
1253 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1254 if (!wait)
1255 return -1;
1256
1257 status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_GET, &mode);
1258
1259 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
1260
1261 if (wait && (status != -EINPROGRESS))
1262 kfree(wait);
1263 return mode;
1264}
1265
1266/*
1267 * IOCTL request handler to get rate.
1268 *
1269 * This function prepares the correct firmware command and
1270 * issues it to get the current rate if it is connected,
1271 * otherwise, the function returns the lowest supported rate
1272 * for the band.
1273 */
1274static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
1275 struct mwifiex_wait_queue *wait,
1276 struct mwifiex_rate_cfg *rate_cfg)
1277{
1278 struct mwifiex_adapter *adapter = priv->adapter;
1279 int ret = 0;
1280
1281 rate_cfg->is_rate_auto = priv->is_data_rate_auto;
1282 if (!priv->media_connected) {
1283 switch (adapter->config_bands) {
1284 case BAND_B:
1285 /* Return the lowest supported rate for B band */
1286 rate_cfg->rate = supported_rates_b[0] & 0x7f;
1287 break;
1288 case BAND_G:
1289 case BAND_G | BAND_GN:
1290 /* Return the lowest supported rate for G band */
1291 rate_cfg->rate = supported_rates_g[0] & 0x7f;
1292 break;
1293 case BAND_B | BAND_G:
1294 case BAND_A | BAND_B | BAND_G:
1295 case BAND_A | BAND_B:
1296 case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
1297 case BAND_B | BAND_G | BAND_GN:
1298 /* Return the lowest supported rate for BG band */
1299 rate_cfg->rate = supported_rates_bg[0] & 0x7f;
1300 break;
1301 case BAND_A:
1302 case BAND_A | BAND_G:
1303 case BAND_A | BAND_G | BAND_AN | BAND_GN:
1304 case BAND_A | BAND_AN:
1305 /* Return the lowest supported rate for A band */
1306 rate_cfg->rate = supported_rates_a[0] & 0x7f;
1307 break;
1308 case BAND_GN:
1309 /* Return the lowest supported rate for N band */
1310 rate_cfg->rate = supported_rates_n[0] & 0x7f;
1311 break;
1312 default:
1313 dev_warn(adapter->dev, "invalid band %#x\n",
1314 adapter->config_bands);
1315 break;
1316 }
1317 } else {
1318 /* Send request to firmware */
1319 ret = mwifiex_prepare_cmd(priv,
1320 HostCmd_CMD_802_11_TX_RATE_QUERY,
1321 HostCmd_ACT_GEN_GET, 0, wait, NULL);
1322 if (!ret)
1323 ret = -EINPROGRESS;
1324 }
1325
1326 return ret;
1327}
1328
1329/*
1330 * IOCTL request handler to set rate.
1331 *
1332 * This function prepares the correct firmware command and
1333 * issues it to set the current rate.
1334 *
1335 * The function also performs validation checking on the supplied value.
1336 */
1337static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv,
1338 struct mwifiex_wait_queue *wait,
1339 struct mwifiex_rate_cfg *rate_cfg)
1340{
1341 u8 rates[MWIFIEX_SUPPORTED_RATES];
1342 u8 *rate = NULL;
1343 int rate_index = 0;
1344 u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
1345 u32 i = 0;
1346 int ret = 0;
1347 struct mwifiex_adapter *adapter = priv->adapter;
1348
1349 if (rate_cfg->is_rate_auto) {
1350 memset(bitmap_rates, 0, sizeof(bitmap_rates));
1351 /* Support all HR/DSSS rates */
1352 bitmap_rates[0] = 0x000F;
1353 /* Support all OFDM rates */
1354 bitmap_rates[1] = 0x00FF;
1355 /* Support all HT-MCSs rate */
1356 for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++)
1357 bitmap_rates[i + 2] = 0xFFFF;
1358 bitmap_rates[9] = 0x3FFF;
1359 } else {
1360 memset(rates, 0, sizeof(rates));
1361 mwifiex_get_active_data_rates(priv, rates);
1362 rate = rates;
1363 for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) {
1364 dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n",
1365 rate[i], rate_cfg->rate);
1366 if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f))
1367 break;
1368 }
1369 if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) {
1370 dev_err(adapter->dev, "fixed data rate %#x is out "
1371 "of range\n", rate_cfg->rate);
1372 return -1;
1373 }
1374 memset(bitmap_rates, 0, sizeof(bitmap_rates));
1375
1376 rate_index =
1377 mwifiex_data_rate_to_index(adapter, rate_cfg->rate);
1378
1379 /* Only allow b/g rates to be set */
1380 if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 &&
1381 rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) {
1382 bitmap_rates[0] = 1 << rate_index;
1383 } else {
1384 rate_index -= 1; /* There is a 0x00 in the table */
1385 if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 &&
1386 rate_index <= MWIFIEX_RATE_INDEX_OFDM7)
1387 bitmap_rates[1] = 1 << (rate_index -
1388 MWIFIEX_RATE_INDEX_OFDM0);
1389 }
1390 }
1391
1392 /* Send request to firmware */
1393 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
1394 HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates);
1395 if (!ret)
1396 ret = -EINPROGRESS;
1397
1398 return ret;
1399}
1400
1401/*
1402 * IOCTL request handler to set/get rate.
1403 *
1404 * This function can be used to set/get either the rate value or the
1405 * rate index.
1406 */
1407static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv,
1408 struct mwifiex_wait_queue *wait,
1409 struct mwifiex_rate_cfg *rate_cfg)
1410{
1411 int status = 0;
1412
1413 if (!rate_cfg)
1414 return -1;
1415
1416 if (rate_cfg->action == HostCmd_ACT_GEN_GET)
1417 status = mwifiex_rate_ioctl_get_rate_value(
1418 priv, wait, rate_cfg);
1419 else
1420 status = mwifiex_rate_ioctl_set_rate_value(
1421 priv, wait, rate_cfg);
1422
1423 return status;
1424}
1425
1426/*
1427 * Sends IOCTL request to get the data rate.
1428 *
1429 * This function allocates the IOCTL request buffer, fills it
1430 * with requisite parameters and calls the IOCTL handler.
1431 */
1432int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
1433 struct mwifiex_rate_cfg *rate)
1434{
1435 int ret = 0;
1436 struct mwifiex_wait_queue *wait = NULL;
1437 u8 wait_option = MWIFIEX_IOCTL_WAIT;
1438
1439 /* Allocate wait buffer */
1440 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1441 if (!wait)
1442 return -ENOMEM;
1443
1444 memset(rate, 0, sizeof(struct mwifiex_rate_cfg));
1445 rate->action = HostCmd_ACT_GEN_GET;
1446 ret = mwifiex_rate_ioctl_cfg(priv, wait, rate);
1447
1448 ret = mwifiex_request_ioctl(priv, wait, ret, wait_option);
1449 if (!ret) {
1450 if (rate && rate->is_rate_auto)
1451 rate->rate = mwifiex_index_to_data_rate(priv->adapter,
1452 priv->tx_rate, priv->tx_htinfo);
1453 else if (rate)
1454 rate->rate = priv->data_rate;
1455 } else {
1456 ret = -1;
1457 }
1458
1459 kfree(wait);
1460 return ret;
1461}
1462
1463/*
1464 * IOCTL request handler to set tx power configuration.
1465 *
1466 * This function prepares the correct firmware command and
1467 * issues it.
1468 *
1469 * For non-auto power mode, all the following power groups are set -
1470 * - Modulation class HR/DSSS
1471 * - Modulation class OFDM
1472 * - Modulation class HTBW20
1473 * - Modulation class HTBW40
1474 */
1475static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv,
1476 struct mwifiex_wait_queue *wait,
1477 struct mwifiex_power_cfg *power_cfg)
1478{
1479 int ret = 0;
1480 struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL;
1481 struct mwifiex_types_power_group *pg_tlv = NULL;
1482 struct mwifiex_power_group *pg = NULL;
1483 u8 *buf = NULL;
1484 u16 dbm = 0;
1485
1486 if (!power_cfg->is_power_auto) {
1487 dbm = (u16) power_cfg->power_level;
1488 if ((dbm < priv->min_tx_power_level) ||
1489 (dbm > priv->max_tx_power_level)) {
1490 dev_err(priv->adapter->dev, "txpower value %d dBm"
1491 " is out of range (%d dBm-%d dBm)\n",
1492 dbm, priv->min_tx_power_level,
1493 priv->max_tx_power_level);
1494 return -1;
1495 }
1496 }
1497 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
1498 if (!buf) {
1499 dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
1500 __func__);
1501 return -1;
1502 }
1503
1504 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
1505 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
1506 if (!power_cfg->is_power_auto) {
1507 txp_cfg->mode = cpu_to_le32(1);
1508 pg_tlv = (struct mwifiex_types_power_group *) (buf +
1509 sizeof(struct host_cmd_ds_txpwr_cfg));
1510 pg_tlv->type = TLV_TYPE_POWER_GROUP;
1511 pg_tlv->length = 4 * sizeof(struct mwifiex_power_group);
1512 pg = (struct mwifiex_power_group *) (buf +
1513 sizeof(struct host_cmd_ds_txpwr_cfg) +
1514 sizeof(struct mwifiex_types_power_group));
1515 /* Power group for modulation class HR/DSSS */
1516 pg->first_rate_code = 0x00;
1517 pg->last_rate_code = 0x03;
1518 pg->modulation_class = MOD_CLASS_HR_DSSS;
1519 pg->power_step = 0;
1520 pg->power_min = (s8) dbm;
1521 pg->power_max = (s8) dbm;
1522 pg++;
1523 /* Power group for modulation class OFDM */
1524 pg->first_rate_code = 0x00;
1525 pg->last_rate_code = 0x07;
1526 pg->modulation_class = MOD_CLASS_OFDM;
1527 pg->power_step = 0;
1528 pg->power_min = (s8) dbm;
1529 pg->power_max = (s8) dbm;
1530 pg++;
1531 /* Power group for modulation class HTBW20 */
1532 pg->first_rate_code = 0x00;
1533 pg->last_rate_code = 0x20;
1534 pg->modulation_class = MOD_CLASS_HT;
1535 pg->power_step = 0;
1536 pg->power_min = (s8) dbm;
1537 pg->power_max = (s8) dbm;
1538 pg->ht_bandwidth = HT_BW_20;
1539 pg++;
1540 /* Power group for modulation class HTBW40 */
1541 pg->first_rate_code = 0x00;
1542 pg->last_rate_code = 0x20;
1543 pg->modulation_class = MOD_CLASS_HT;
1544 pg->power_step = 0;
1545 pg->power_min = (s8) dbm;
1546 pg->power_max = (s8) dbm;
1547 pg->ht_bandwidth = HT_BW_40;
1548 }
1549 /* Send request to firmware */
1550 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG,
1551 HostCmd_ACT_GEN_SET, 0, wait, buf);
1552 if (!ret)
1553 ret = -EINPROGRESS;
1554 kfree(buf);
1555
1556 return ret;
1557}
1558
1559/*
1560 * IOCTL request handler to get power save mode.
1561 *
1562 * This function prepares the correct firmware command and
1563 * issues it.
1564 */
1565static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv,
1566 struct mwifiex_wait_queue *wait,
1567 u32 *ps_mode, u16 action)
1568{
1569 int ret = 0;
1570 struct mwifiex_adapter *adapter = priv->adapter;
1571 u16 sub_cmd;
1572
1573 if (action == HostCmd_ACT_GEN_SET) {
1574 if (*ps_mode)
1575 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1576 else
1577 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
1578 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
1579 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
1580 sub_cmd, BITMAP_STA_PS, wait, NULL);
1581 if ((!ret) && (sub_cmd == DIS_AUTO_PS))
1582 ret = mwifiex_prepare_cmd(priv,
1583 HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
1584 0, NULL, NULL);
1585 } else {
1586 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
1587 GET_PS, 0, wait, NULL);
1588 }
1589
1590 if (!ret)
1591 ret = -EINPROGRESS;
1592
1593 return ret;
1594}
1595
1596/*
1597 * IOCTL request handler to set/reset WPA IE.
1598 *
1599 * The supplied WPA IE is treated as a opaque buffer. Only the first field
1600 * is checked to determine WPA version. If buffer length is zero, the existing
1601 * WPA IE is reset.
1602 */
1603static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
1604 u8 *ie_data_ptr, u16 ie_len)
1605{
1606 if (ie_len) {
1607 if (ie_len > sizeof(priv->wpa_ie)) {
1608 dev_err(priv->adapter->dev,
1609 "failed to copy WPA IE, too big\n");
1610 return -1;
1611 }
1612 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
1613 priv->wpa_ie_len = (u8) ie_len;
1614 dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
1615 priv->wpa_ie_len, priv->wpa_ie[0]);
1616
1617 if (priv->wpa_ie[0] == WLAN_EID_WPA) {
1618 priv->sec_info.wpa_enabled = true;
1619 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
1620 priv->sec_info.wpa2_enabled = true;
1621 } else {
1622 priv->sec_info.wpa_enabled = false;
1623 priv->sec_info.wpa2_enabled = false;
1624 }
1625 } else {
1626 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
1627 priv->wpa_ie_len = 0;
1628 dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
1629 priv->wpa_ie_len, priv->wpa_ie[0]);
1630 priv->sec_info.wpa_enabled = false;
1631 priv->sec_info.wpa2_enabled = false;
1632 }
1633
1634 return 0;
1635}
1636
1637/*
1638 * IOCTL request handler to set/reset WAPI IE.
1639 *
1640 * The supplied WAPI IE is treated as a opaque buffer. Only the first field
1641 * is checked to internally enable WAPI. If buffer length is zero, the existing
1642 * WAPI IE is reset.
1643 */
1644static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
1645 u8 *ie_data_ptr, u16 ie_len)
1646{
1647 if (ie_len) {
1648 if (ie_len > sizeof(priv->wapi_ie)) {
1649 dev_dbg(priv->adapter->dev,
1650 "info: failed to copy WAPI IE, too big\n");
1651 return -1;
1652 }
1653 memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
1654 priv->wapi_ie_len = ie_len;
1655 dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
1656 priv->wapi_ie_len, priv->wapi_ie[0]);
1657
1658 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
1659 priv->sec_info.wapi_enabled = true;
1660 } else {
1661 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
1662 priv->wapi_ie_len = ie_len;
1663 dev_dbg(priv->adapter->dev,
1664 "info: Reset wapi_ie_len=%d IE=%#x\n",
1665 priv->wapi_ie_len, priv->wapi_ie[0]);
1666 priv->sec_info.wapi_enabled = false;
1667 }
1668 return 0;
1669}
1670
1671/*
1672 * IOCTL request handler to set WAPI key.
1673 *
1674 * This function prepares the correct firmware command and
1675 * issues it.
1676 */
1677static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter,
1678 struct mwifiex_wait_queue *wait,
1679 struct mwifiex_ds_encrypt_key *encrypt_key)
1680{
1681 int ret = 0;
1682 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
1683
1684 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1685 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1686 wait, encrypt_key);
1687 if (!ret)
1688 ret = -EINPROGRESS;
1689
1690 return ret;
1691}
1692
1693/*
1694 * IOCTL request handler to set/get authentication mode.
1695 */
1696static int mwifiex_set_auth_mode(struct mwifiex_private *priv, u32 auth_mode)
1697{
1698 int ret = 0;
1699
1700 priv->sec_info.authentication_mode = auth_mode;
1701 if (priv->sec_info.authentication_mode == MWIFIEX_AUTH_MODE_NETWORKEAP)
1702 ret = mwifiex_set_wpa_ie_helper(priv, NULL, 0);
1703
1704 return ret;
1705}
1706
1707/*
1708 * IOCTL request handler to set WEP network key.
1709 *
1710 * This function prepares the correct firmware command and
1711 * issues it, after validation checks.
1712 */
1713static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter,
1714 struct mwifiex_wait_queue *wait,
1715 struct mwifiex_ds_encrypt_key *encrypt_key)
1716{
1717 int ret = 0;
1718 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
1719 struct mwifiex_wep_key *wep_key = NULL;
1720 int index;
1721
1722 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
1723 priv->wep_key_curr_index = 0;
1724 wep_key = &priv->wep_key[priv->wep_key_curr_index];
1725 index = encrypt_key->key_index;
1726 if (encrypt_key->key_disable) {
1727 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
1728 } else if (!encrypt_key->key_len) {
1729 /* Copy the required key as the current key */
1730 wep_key = &priv->wep_key[index];
1731 if (!wep_key->key_length) {
1732 dev_err(adapter->dev,
1733 "key not set, so cannot enable it\n");
1734 return -1;
1735 }
1736 priv->wep_key_curr_index = (u16) index;
1737 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
1738 } else {
1739 wep_key = &priv->wep_key[index];
1740 /* Cleanup */
1741 memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
1742 /* Copy the key in the driver */
1743 memcpy(wep_key->key_material,
1744 encrypt_key->key_material,
1745 encrypt_key->key_len);
1746 wep_key->key_index = index;
1747 wep_key->key_length = encrypt_key->key_len;
1748 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
1749 }
1750 if (wep_key->key_length) {
1751 /* Send request to firmware */
1752 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1753 HostCmd_ACT_GEN_SET, 0, NULL, NULL);
1754 if (ret)
1755 return ret;
1756 }
1757 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
1758 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
1759 else
1760 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
1761
1762 /* Send request to firmware */
1763 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1764 HostCmd_ACT_GEN_SET, 0, wait,
1765 &priv->curr_pkt_filter);
1766 if (!ret)
1767 ret = -EINPROGRESS;
1768
1769 return ret;
1770}
1771
1772/*
1773 * IOCTL request handler to set WPA key.
1774 *
1775 * This function prepares the correct firmware command and
1776 * issues it, after validation checks.
1777 *
1778 * Current driver only supports key length of up to 32 bytes.
1779 *
1780 * This function can also be used to disable a currently set key.
1781 */
1782static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter,
1783 struct mwifiex_wait_queue *wait,
1784 struct mwifiex_ds_encrypt_key *encrypt_key)
1785{
1786 int ret = 0;
1787 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
1788 u8 remove_key = false;
1789 struct host_cmd_ds_802_11_key_material *ibss_key;
1790
1791 /* Current driver only supports key length of up to 32 bytes */
1792 if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) {
1793 dev_err(adapter->dev, "key length too long\n");
1794 return -1;
1795 }
1796
1797 if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) {
1798 /*
1799 * IBSS/WPA-None uses only one key (Group) for both receiving
1800 * and sending unicast and multicast packets.
1801 */
1802 /* Send the key as PTK to firmware */
1803 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1804 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1805 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1806 NULL, encrypt_key);
1807 if (ret)
1808 return ret;
1809
1810 ibss_key = &priv->aes_key;
1811 memset(ibss_key, 0,
1812 sizeof(struct host_cmd_ds_802_11_key_material));
1813 /* Copy the key in the driver */
1814 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
1815 encrypt_key->key_len);
1816 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
1817 sizeof(ibss_key->key_param_set.key_len));
1818 ibss_key->key_param_set.key_type_id
1819 = cpu_to_le16(KEY_TYPE_ID_TKIP);
1820 ibss_key->key_param_set.key_info
1821 = cpu_to_le16(KEY_INFO_TKIP_ENABLED);
1822
1823 /* Send the key as GTK to firmware */
1824 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
1825 }
1826
1827 if (!encrypt_key->key_index)
1828 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1829
1830 if (remove_key)
1831 /* Send request to firmware */
1832 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1833 HostCmd_ACT_GEN_SET,
1834 !(KEY_INFO_ENABLED),
1835 wait, encrypt_key);
1836 else
1837 /* Send request to firmware */
1838 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1839 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1840 wait, encrypt_key);
1841
1842 if (!ret)
1843 ret = -EINPROGRESS;
1844
1845 return ret;
1846}
1847
1848/*
1849 * IOCTL request handler to set/get network keys.
1850 *
1851 * This is a generic key handling function which supports WEP, WPA
1852 * and WAPI.
1853 */
1854static int
1855mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
1856 struct mwifiex_wait_queue *wait,
1857 struct mwifiex_ds_encrypt_key *encrypt_key)
1858{
1859 int status = 0;
1860 struct mwifiex_adapter *adapter = priv->adapter;
1861
1862 if (encrypt_key->is_wapi_key)
1863 status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait,
1864 encrypt_key);
1865 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
1866 status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait,
1867 encrypt_key);
1868 else
1869 status = mwifiex_sec_ioctl_set_wep_key(adapter, wait,
1870 encrypt_key);
1871 return status;
1872}
1873
1874/*
1875 * This function returns the driver version.
1876 */
1877int
1878mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
1879 int max_len)
1880{
1881 union {
1882 u32 l;
1883 u8 c[4];
1884 } ver;
1885 char fw_ver[32];
1886
1887 ver.l = adapter->fw_release_number;
1888 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
1889
1890 snprintf(version, max_len, driver_version, fw_ver);
1891
1892 dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
1893
1894 return 0;
1895}
1896
1897/*
1898 * Sends IOCTL request to set Tx power. It can be set to either auto
1899 * or a fixed value.
1900 *
1901 * This function allocates the IOCTL request buffer, fills it
1902 * with requisite parameters and calls the IOCTL handler.
1903 */
1904int
1905mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm)
1906{
1907 struct mwifiex_power_cfg power_cfg;
1908 struct mwifiex_wait_queue *wait = NULL;
1909 int status = 0;
1910 int ret = 0;
1911
1912 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
1913 if (!wait)
1914 return -ENOMEM;
1915
1916 if (type == NL80211_TX_POWER_FIXED) {
1917 power_cfg.is_power_auto = 0;
1918 power_cfg.power_level = dbm;
1919 } else {
1920 power_cfg.is_power_auto = 1;
1921 }
1922 status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg);
1923
1924 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
1925
1926 kfree(wait);
1927 return ret;
1928}
1929
1930/*
1931 * Sends IOCTL request to get scan table.
1932 *
1933 * This function allocates the IOCTL request buffer, fills it
1934 * with requisite parameters and calls the IOCTL handler.
1935 */
1936int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option,
1937 struct mwifiex_scan_resp *scan_resp)
1938{
1939 struct mwifiex_wait_queue *wait = NULL;
1940 struct mwifiex_scan_resp scan;
1941 int status = 0;
1942
1943 /* Allocate wait buffer */
1944 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1945 if (!wait)
1946 return -ENOMEM;
1947
1948 status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET,
1949 NULL, &scan);
1950
1951 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
1952 if (!status) {
1953 if (scan_resp)
1954 memcpy(scan_resp, &scan,
1955 sizeof(struct mwifiex_scan_resp));
1956 }
1957
1958 if (wait && (status != -EINPROGRESS))
1959 kfree(wait);
1960 return status;
1961}
1962
1963/*
1964 * Sends IOCTL request to get signal information.
1965 *
1966 * This function allocates the IOCTL request buffer, fills it
1967 * with requisite parameters and calls the IOCTL handler.
1968 */
1969int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option,
1970 struct mwifiex_ds_get_signal *signal)
1971{
1972 struct mwifiex_ds_get_signal info;
1973 struct mwifiex_wait_queue *wait = NULL;
1974 int status = 0;
1975
1976 /* Allocate wait buffer */
1977 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
1978 if (!wait)
1979 return -ENOMEM;
1980
1981 info.selector = ALL_RSSI_INFO_MASK;
1982
1983 status = mwifiex_get_info_signal(priv, wait, &info);
1984
1985 status = mwifiex_request_ioctl(priv, wait, status, wait_option);
1986 if (!status) {
1987 if (signal)
1988 memcpy(signal, &info,
1989 sizeof(struct mwifiex_ds_get_signal));
1990 if (info.selector & BCN_RSSI_AVG_MASK)
1991 priv->w_stats.qual.level = info.bcn_rssi_avg;
1992 if (info.selector & BCN_NF_AVG_MASK)
1993 priv->w_stats.qual.noise = info.bcn_nf_avg;
1994 }
1995
1996 if (wait && (status != -EINPROGRESS))
1997 kfree(wait);
1998 return status;
1999}
2000
2001/*
2002 * Sends IOCTL request to set encryption mode.
2003 *
2004 * This function allocates the IOCTL request buffer, fills it
2005 * with requisite parameters and calls the IOCTL handler.
2006 */
2007static int mwifiex_set_encrypt_mode(struct mwifiex_private *priv,
2008 u8 wait_option, u32 encrypt_mode)
2009{
2010 priv->sec_info.encryption_mode = encrypt_mode;
2011 return 0;
2012}
2013
2014/*
2015 * This function set the authentication parameters. It sets both encryption
2016 * mode and authentication mode, and also enables WPA if required.
2017 */
2018int
2019mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode,
2020 int auth_mode, int wpa_enabled)
2021{
2022 if (mwifiex_set_encrypt_mode(priv, MWIFIEX_IOCTL_WAIT, encrypt_mode))
2023 return -EFAULT;
2024
2025 if (mwifiex_set_auth_mode(priv, auth_mode))
2026 return -EFAULT;
2027
2028 return 0;
2029}
2030
2031/*
2032 * Sends IOCTL request to set encoding parameters.
2033 *
2034 * This function allocates the IOCTL request buffer, fills it
2035 * with requisite parameters and calls the IOCTL handler.
2036 */
2037int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
2038 int key_len, u8 key_index, int disable)
2039{
2040 struct mwifiex_wait_queue *wait = NULL;
2041 struct mwifiex_ds_encrypt_key encrypt_key;
2042 int status = 0;
2043 int ret = 0;
2044
2045 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2046 if (!wait)
2047 return -ENOMEM;
2048
2049 memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
2050 encrypt_key.key_len = key_len;
2051 if (!disable) {
2052 encrypt_key.key_index = key_index;
2053 if (key_len)
2054 memcpy(encrypt_key.key_material, key, key_len);
2055 } else {
2056 encrypt_key.key_disable = true;
2057 }
2058
2059 status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key);
2060
2061 if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT))
2062 ret = -EFAULT;
2063
2064 kfree(wait);
2065 return ret;
2066}
2067
2068/*
2069 * Sends IOCTL request to set power management parameters.
2070 *
2071 * This function allocates the IOCTL request buffer, fills it
2072 * with requisite parameters and calls the IOCTL handler.
2073 */
2074int
2075mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on)
2076{
2077 int ret = 0;
2078 int status = 0;
2079 struct mwifiex_wait_queue *wait = NULL;
2080 u32 ps_mode;
2081
2082 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2083 if (!wait)
2084 return -ENOMEM;
2085
2086 ps_mode = power_on;
2087 status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode,
2088 HostCmd_ACT_GEN_SET);
2089
2090 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2091
2092 kfree(wait);
2093 return ret;
2094}
2095
2096/*
2097 * Sends IOCTL request to get extended version.
2098 *
2099 * This function allocates the IOCTL request buffer, fills it
2100 * with requisite parameters and calls the IOCTL handler.
2101 */
2102int
2103mwifiex_get_ver_ext(struct mwifiex_private *priv)
2104{
2105 struct mwifiex_ver_ext ver_ext;
2106 struct mwifiex_wait_queue *wait = NULL;
2107 int status = 0;
2108 int ret = 0;
2109 u8 wait_option = MWIFIEX_IOCTL_WAIT;
2110
2111 /* Allocate wait buffer */
2112 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
2113 if (!wait)
2114 return -ENOMEM;
2115
2116 /* get fw version */
2117 memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
2118 status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext);
2119
2120 ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
2121
2122 if (ret)
2123 ret = -1;
2124
2125 kfree(wait);
2126 return ret;
2127}
2128
2129/*
2130 * Sends IOCTL request to get statistics information.
2131 *
2132 * This function allocates the IOCTL request buffer, fills it
2133 * with requisite parameters and calls the IOCTL handler.
2134 */
2135int
2136mwifiex_get_stats_info(struct mwifiex_private *priv,
2137 struct mwifiex_ds_get_stats *log)
2138{
2139 int ret = 0;
2140 int status = 0;
2141 struct mwifiex_wait_queue *wait = NULL;
2142 struct mwifiex_ds_get_stats get_log;
2143 u8 wait_option = MWIFIEX_IOCTL_WAIT;
2144
2145 /* Allocate wait buffer */
2146 wait = mwifiex_alloc_fill_wait_queue(priv, wait_option);
2147 if (!wait)
2148 return -ENOMEM;
2149
2150 memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats));
2151 status = mwifiex_get_info_stats(priv, wait, &get_log);
2152
2153 /* Send IOCTL request to MWIFIEX */
2154 ret = mwifiex_request_ioctl(priv, wait, status, wait_option);
2155 if (!ret) {
2156 if (log)
2157 memcpy(log, &get_log, sizeof(struct
2158 mwifiex_ds_get_stats));
2159 priv->w_stats.discard.fragment = get_log.fcs_error;
2160 priv->w_stats.discard.retries = get_log.retry;
2161 priv->w_stats.discard.misc = get_log.ack_failure;
2162 }
2163
2164 kfree(wait);
2165 return ret;
2166}
2167
2168/*
2169 * IOCTL request handler to read/write register.
2170 *
2171 * This function prepares the correct firmware command and
2172 * issues it.
2173 *
2174 * Access to the following registers are supported -
2175 * - MAC
2176 * - BBP
2177 * - RF
2178 * - PMIC
2179 * - CAU
2180 */
2181static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
2182 struct mwifiex_wait_queue *wait,
2183 struct mwifiex_ds_reg_rw *reg_rw,
2184 u16 action)
2185{
2186 int ret = 0;
2187 u16 cmd_no;
2188
2189 switch (le32_to_cpu(reg_rw->type)) {
2190 case MWIFIEX_REG_MAC:
2191 cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
2192 break;
2193 case MWIFIEX_REG_BBP:
2194 cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
2195 break;
2196 case MWIFIEX_REG_RF:
2197 cmd_no = HostCmd_CMD_RF_REG_ACCESS;
2198 break;
2199 case MWIFIEX_REG_PMIC:
2200 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
2201 break;
2202 case MWIFIEX_REG_CAU:
2203 cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
2204 break;
2205 default:
2206 return -1;
2207 }
2208
2209 /* Send request to firmware */
2210 ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw);
2211
2212 if (!ret)
2213 ret = -EINPROGRESS;
2214
2215 return ret;
2216}
2217
2218/*
2219 * Sends IOCTL request to write to a register.
2220 *
2221 * This function allocates the IOCTL request buffer, fills it
2222 * with requisite parameters and calls the IOCTL handler.
2223 */
2224int
2225mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
2226 u32 reg_offset, u32 reg_value)
2227{
2228 int ret = 0;
2229 int status = 0;
2230 struct mwifiex_wait_queue *wait = NULL;
2231 struct mwifiex_ds_reg_rw reg_rw;
2232
2233 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2234 if (!wait)
2235 return -ENOMEM;
2236
2237 reg_rw.type = cpu_to_le32(reg_type);
2238 reg_rw.offset = cpu_to_le32(reg_offset);
2239 reg_rw.value = cpu_to_le32(reg_value);
2240 status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, &reg_rw,
2241 HostCmd_ACT_GEN_SET);
2242
2243 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2244
2245 kfree(wait);
2246 return ret;
2247}
2248
2249/*
2250 * Sends IOCTL request to read from a register.
2251 *
2252 * This function allocates the IOCTL request buffer, fills it
2253 * with requisite parameters and calls the IOCTL handler.
2254 */
2255int
2256mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
2257 u32 reg_offset, u32 *value)
2258{
2259 int ret = 0;
2260 int status = 0;
2261 struct mwifiex_wait_queue *wait = NULL;
2262 struct mwifiex_ds_reg_rw reg_rw;
2263
2264 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2265 if (!wait)
2266 return -ENOMEM;
2267
2268 reg_rw.type = cpu_to_le32(reg_type);
2269 reg_rw.offset = cpu_to_le32(reg_offset);
2270 status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, &reg_rw,
2271 HostCmd_ACT_GEN_GET);
2272
2273 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2274 if (ret)
2275 goto done;
2276
2277 *value = le32_to_cpu(reg_rw.value);
2278
2279done:
2280 kfree(wait);
2281 return ret;
2282}
2283
2284/*
2285 * IOCTL request handler to read EEPROM.
2286 *
2287 * This function prepares the correct firmware command and
2288 * issues it.
2289 */
2290static int
2291mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv,
2292 struct mwifiex_wait_queue *wait,
2293 struct mwifiex_ds_read_eeprom *rd_eeprom)
2294{
2295 int ret = 0;
2296
2297 /* Send request to firmware */
2298 ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
2299 HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom);
2300
2301 if (!ret)
2302 ret = -EINPROGRESS;
2303
2304 return ret;
2305}
2306
2307/*
2308 * Sends IOCTL request to read from EEPROM.
2309 *
2310 * This function allocates the IOCTL request buffer, fills it
2311 * with requisite parameters and calls the IOCTL handler.
2312 */
2313int
2314mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
2315 u8 *value)
2316{
2317 int ret = 0;
2318 int status = 0;
2319 struct mwifiex_wait_queue *wait = NULL;
2320 struct mwifiex_ds_read_eeprom rd_eeprom;
2321
2322 wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT);
2323 if (!wait)
2324 return -ENOMEM;
2325
2326 rd_eeprom.offset = cpu_to_le16((u16) offset);
2327 rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
2328 status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom);
2329
2330 ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT);
2331 if (ret)
2332 goto done;
2333
2334 memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
2335done:
2336 kfree(wait);
2337 return ret;
2338}
2339
2340/*
2341 * This function sets a generic IE. In addition to generic IE, it can
2342 * also handle WPA, WPA2 and WAPI IEs.
2343 */
2344static int
2345mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
2346 u16 ie_len)
2347{
2348 int ret = 0;
2349 struct ieee_types_vendor_header *pvendor_ie;
2350 const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
2351 const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
2352
2353 /* If the passed length is zero, reset the buffer */
2354 if (!ie_len) {
2355 priv->gen_ie_buf_len = 0;
2356 priv->wps.session_enable = false;
2357
2358 return 0;
2359 } else if (!ie_data_ptr) {
2360 return -1;
2361 }
2362 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
2363 /* Test to see if it is a WPA IE, if not, then it is a gen IE */
2364 if (((pvendor_ie->element_id == WLAN_EID_WPA)
2365 && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
2366 || (pvendor_ie->element_id == WLAN_EID_RSN)) {
2367
2368 /* IE is a WPA/WPA2 IE so call set_wpa function */
2369 ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
2370 priv->wps.session_enable = false;
2371
2372 return ret;
2373 } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
2374 /* IE is a WAPI IE so call set_wapi function */
2375 ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len);
2376
2377 return ret;
2378 }
2379 /*
2380 * Verify that the passed length is not larger than the
2381 * available space remaining in the buffer
2382 */
2383 if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
2384
2385 /* Test to see if it is a WPS IE, if so, enable
2386 * wps session flag
2387 */
2388 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
2389 if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC)
2390 && (!memcmp(pvendor_ie->oui, wps_oui,
2391 sizeof(wps_oui)))) {
2392 priv->wps.session_enable = true;
2393 dev_dbg(priv->adapter->dev,
2394 "info: WPS Session Enabled.\n");
2395 }
2396
2397 /* Append the passed data to the end of the
2398 genIeBuffer */
2399 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
2400 ie_len);
2401 /* Increment the stored buffer length by the
2402 size passed */
2403 priv->gen_ie_buf_len += ie_len;
2404 } else {
2405 /* Passed data does not fit in the remaining
2406 buffer space */
2407 ret = -1;
2408 }
2409
2410 /* Return 0, or -1 for error case */
2411 return ret;
2412}
2413
2414/*
2415 * IOCTL request handler to set/get generic IE.
2416 *
2417 * In addition to various generic IEs, this function can also be
2418 * used to set the ARP filter.
2419 */
2420static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
2421 struct mwifiex_ds_misc_gen_ie *gen_ie,
2422 u16 action)
2423{
2424 struct mwifiex_adapter *adapter = priv->adapter;
2425
2426 switch (gen_ie->type) {
2427 case MWIFIEX_IE_TYPE_GEN_IE:
2428 if (action == HostCmd_ACT_GEN_GET) {
2429 gen_ie->len = priv->wpa_ie_len;
2430 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
2431 } else {
2432 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
2433 (u16) gen_ie->len);
2434 }
2435 break;
2436 case MWIFIEX_IE_TYPE_ARP_FILTER:
2437 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
2438 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
2439 adapter->arp_filter_size = 0;
2440 dev_err(adapter->dev, "invalid ARP filter size\n");
2441 return -1;
2442 } else {
2443 memcpy(adapter->arp_filter, gen_ie->ie_data,
2444 gen_ie->len);
2445 adapter->arp_filter_size = gen_ie->len;
2446 }
2447 break;
2448 default:
2449 dev_err(adapter->dev, "invalid IE type\n");
2450 return -1;
2451 }
2452 return 0;
2453}
2454
2455/*
2456 * Sends IOCTL request to set a generic IE.
2457 *
2458 * This function allocates the IOCTL request buffer, fills it
2459 * with requisite parameters and calls the IOCTL handler.
2460 */
2461int
2462mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
2463{
2464 struct mwifiex_ds_misc_gen_ie gen_ie;
2465 int status = 0;
2466
2467 if (ie_len > IW_CUSTOM_MAX)
2468 return -EFAULT;
2469
2470 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
2471 gen_ie.len = ie_len;
2472 memcpy(gen_ie.ie_data, ie, ie_len);
2473 status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET);
2474 if (status)
2475 return -EFAULT;
2476
2477 return 0;
2478}
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
new file mode 100644
index 000000000000..8282679e64fd
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -0,0 +1,182 @@
1/*
2 * Marvell Wireless LAN device driver: station RX data handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "11n_aggr.h"
26#include "11n_rxreorder.h"
27
28/*
29 * This function processes the received packet and forwards it
30 * to kernel/upper layer.
31 *
32 * This function parses through the received packet and determines
33 * if it is a debug packet or normal packet.
34 *
35 * For non-debug packets, the function chops off unnecessary leading
36 * header bytes, reconstructs the packet as an ethernet frame or
37 * 802.2/llc/snap frame as required, and sends it to kernel/upper layer.
38 *
39 * The completion callback is called after processing in complete.
40 */
41int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
42 struct sk_buff *skb)
43{
44 int ret = 0;
45 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
46 struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
47 struct rx_packet_hdr *rx_pkt_hdr;
48 struct rxpd *local_rx_pd;
49 int hdr_chop;
50 struct ethhdr *eth_hdr;
51 u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
52
53 local_rx_pd = (struct rxpd *) (skb->data);
54
55 rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
56 local_rx_pd->rx_pkt_offset);
57
58 if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
59 rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
60 /*
61 * Replace the 803 header and rfc1042 header (llc/snap) with an
62 * EthernetII header, keep the src/dst and snap_type
63 * (ethertype).
64 * The firmware only passes up SNAP frames converting
65 * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
66 * To create the Ethernet II, just move the src, dst address
67 * right before the snap_type.
68 */
69 eth_hdr = (struct ethhdr *)
70 ((u8 *) &rx_pkt_hdr->eth803_hdr
71 + sizeof(rx_pkt_hdr->eth803_hdr) +
72 sizeof(rx_pkt_hdr->rfc1042_hdr)
73 - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
74 - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
75 - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
76
77 memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source,
78 sizeof(eth_hdr->h_source));
79 memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
80 sizeof(eth_hdr->h_dest));
81
82 /* Chop off the rxpd + the excess memory from the 802.2/llc/snap
83 header that was removed. */
84 hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd;
85 } else {
86 /* Chop off the rxpd */
87 hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr -
88 (u8 *) local_rx_pd;
89 }
90
91 /* Chop off the leading header bytes so the it points to the start of
92 either the reconstructed EthII frame or the 802.2/llc/snap frame */
93 skb_pull(skb, hdr_chop);
94
95 priv->rxpd_rate = local_rx_pd->rx_rate;
96
97 priv->rxpd_htinfo = local_rx_pd->ht_info;
98
99 ret = mwifiex_recv_packet(adapter, skb);
100 if (ret == -1)
101 dev_err(adapter->dev, "recv packet failed\n");
102
103 return ret;
104}
105
106/*
107 * This function processes the received buffer.
108 *
109 * The function looks into the RxPD and performs sanity tests on the
110 * received buffer to ensure its a valid packet, before processing it
111 * further. If the packet is determined to be aggregated, it is
112 * de-aggregated accordingly. Non-unicast packets are sent directly to
113 * the kernel/upper layers. Unicast packets are handed over to the
114 * Rx reordering routine if 11n is enabled.
115 *
116 * The completion callback is called after processing in complete.
117 */
118int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
119 struct sk_buff *skb)
120{
121 int ret = 0;
122 struct rxpd *local_rx_pd;
123 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
124 struct rx_packet_hdr *rx_pkt_hdr;
125 u8 ta[ETH_ALEN];
126 u16 rx_pkt_type = 0;
127 struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
128
129 local_rx_pd = (struct rxpd *) (skb->data);
130 rx_pkt_type = local_rx_pd->rx_pkt_type;
131
132 rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
133 local_rx_pd->rx_pkt_offset);
134
135 if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) >
136 (u16) skb->len) {
137 dev_err(adapter->dev, "wrong rx packet: len=%d,"
138 " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len,
139 local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
140 priv->stats.rx_dropped++;
141 dev_kfree_skb_any(skb);
142 return ret;
143 }
144 if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
145 mwifiex_11n_deaggregate_pkt(priv, skb);
146 return ret;
147 }
148 /*
149 * If the packet is not an unicast packet then send the packet
150 * directly to os. Don't pass thru rx reordering
151 */
152 if (!IS_11N_ENABLED(priv) ||
153 memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) {
154 mwifiex_process_rx_packet(adapter, skb);
155 return ret;
156 }
157
158 if (mwifiex_queuing_ra_based(priv)) {
159 memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
160 } else {
161 if (rx_pkt_type != PKT_TYPE_BAR)
162 priv->rx_seq[local_rx_pd->priority] =
163 local_rx_pd->seq_num;
164 memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
165 ETH_ALEN);
166 }
167
168 /* Reorder and send to OS */
169 ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
170 local_rx_pd->priority, ta,
171 (u8) local_rx_pd->rx_pkt_type,
172 (void *) skb);
173
174 if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
175 if (priv && (ret == -1))
176 priv->stats.rx_dropped++;
177
178 dev_kfree_skb_any(skb);
179 }
180
181 return ret;
182}
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
new file mode 100644
index 000000000000..e8db6bd021c6
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -0,0 +1,202 @@
1/*
2 * Marvell Wireless LAN device driver: station TX data handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26
27/*
28 * This function fills the TxPD for tx packets.
29 *
30 * The Tx buffer received by this function should already have the
31 * header space allocated for TxPD.
32 *
33 * This function inserts the TxPD in between interface header and actual
34 * data and adjusts the buffer pointers accordingly.
35 *
36 * The following TxPD fields are set by this function, as required -
37 * - BSS number
38 * - Tx packet length and offset
39 * - Priority
40 * - Packet delay
41 * - Priority specific Tx control
42 * - Flags
43 */
44void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
45 struct sk_buff *skb)
46{
47 struct mwifiex_adapter *adapter = priv->adapter;
48 struct txpd *local_tx_pd;
49 struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
50
51 if (!skb->len) {
52 dev_err(adapter->dev, "Tx: bad packet length: %d\n",
53 skb->len);
54 tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID;
55 return skb->data;
56 }
57
58 BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN));
59 skb_push(skb, sizeof(*local_tx_pd));
60
61 local_tx_pd = (struct txpd *) skb->data;
62 memset(local_tx_pd, 0, sizeof(struct txpd));
63 local_tx_pd->bss_num = priv->bss_num;
64 local_tx_pd->bss_type = priv->bss_type;
65 local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len -
66 sizeof(struct txpd)));
67
68 local_tx_pd->priority = (u8) skb->priority;
69 local_tx_pd->pkt_delay_2ms =
70 mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
71
72 if (local_tx_pd->priority <
73 ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
74 /*
75 * Set the priority specific tx_control field, setting of 0 will
76 * cause the default value to be used later in this function
77 */
78 local_tx_pd->tx_control =
79 cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd->
80 priority]);
81
82 if (adapter->pps_uapsd_mode) {
83 if (mwifiex_check_last_packet_indication(priv)) {
84 adapter->tx_lock_flag = true;
85 local_tx_pd->flags =
86 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
87 }
88 }
89
90 /* Offset of actual data */
91 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
92
93 /* make space for INTF_HEADER_LEN */
94 skb_push(skb, INTF_HEADER_LEN);
95
96 if (!local_tx_pd->tx_control)
97 /* TxCtrl set by user or default */
98 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
99
100 return skb->data;
101}
102
103/*
104 * This function tells firmware to send a NULL data packet.
105 *
106 * The function creates a NULL data packet with TxPD and sends to the
107 * firmware for transmission, with highest priority setting.
108 */
109int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
110{
111 struct mwifiex_adapter *adapter = priv->adapter;
112 struct txpd *local_tx_pd;
113/* sizeof(struct txpd) + Interface specific header */
114#define NULL_PACKET_HDR 64
115 u32 data_len = NULL_PACKET_HDR;
116 struct sk_buff *skb = NULL;
117 int ret = 0;
118 struct mwifiex_txinfo *tx_info = NULL;
119
120 if (adapter->surprise_removed)
121 return -1;
122
123 if (!priv->media_connected)
124 return -1;
125
126 if (adapter->data_sent)
127 return -1;
128
129 skb = dev_alloc_skb(data_len);
130 if (!skb)
131 return -1;
132
133 tx_info = MWIFIEX_SKB_TXCB(skb);
134 tx_info->bss_index = priv->bss_index;
135 skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN);
136 skb_push(skb, sizeof(struct txpd));
137
138 local_tx_pd = (struct txpd *) skb->data;
139 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
140 local_tx_pd->flags = flags;
141 local_tx_pd->priority = WMM_HIGHEST_PRIORITY;
142 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
143 local_tx_pd->bss_num = priv->bss_num;
144 local_tx_pd->bss_type = priv->bss_type;
145
146 skb_push(skb, INTF_HEADER_LEN);
147
148 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
149 skb->data, skb->len, NULL);
150 switch (ret) {
151 case -EBUSY:
152 adapter->data_sent = true;
153 /* Fall through FAILURE handling */
154 case -1:
155 dev_kfree_skb_any(skb);
156 dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
157 __func__, ret);
158 adapter->dbg.num_tx_host_to_card_failure++;
159 break;
160 case 0:
161 dev_kfree_skb_any(skb);
162 dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n",
163 __func__);
164 adapter->tx_lock_flag = true;
165 break;
166 case -EINPROGRESS:
167 break;
168 default:
169 break;
170 }
171
172 return ret;
173}
174
175/*
176 * This function checks if we need to send last packet indication.
177 */
178u8
179mwifiex_check_last_packet_indication(struct mwifiex_private *priv)
180{
181 struct mwifiex_adapter *adapter = priv->adapter;
182 u8 ret = false;
183 u8 prop_ps = true;
184
185 if (!adapter->sleep_period.period)
186 return ret;
187 if (mwifiex_wmm_lists_empty(adapter)) {
188 if ((priv->curr_bss_params.wmm_uapsd_enabled &&
189 priv->wmm_qosinfo) || prop_ps)
190 ret = true;
191 }
192
193 if (ret && !adapter->cmd_sent && !adapter->curr_cmd
194 && !is_command_pending(adapter)) {
195 adapter->delay_null_pkt = false;
196 ret = true;
197 } else {
198 ret = false;
199 adapter->delay_null_pkt = true;
200 }
201 return ret;
202}
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
new file mode 100644
index 000000000000..f06923cb1c4b
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -0,0 +1,202 @@
1/*
2 * Marvell Wireless LAN device driver: generic TX/RX data handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26
27/*
28 * This function processes the received buffer.
29 *
30 * Main responsibility of this function is to parse the RxPD to
31 * identify the correct interface this packet is headed for and
32 * forwarding it to the associated handling function, where the
33 * packet will be further processed and sent to kernel/upper layer
34 * if required.
35 */
36int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
37 struct sk_buff *skb)
38{
39 int ret = 0;
40 struct mwifiex_private *priv =
41 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
42 struct rxpd *local_rx_pd;
43 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
44
45 local_rx_pd = (struct rxpd *) (skb->data);
46 /* Get the BSS number from rxpd, get corresponding priv */
47 priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
48 BSS_NUM_MASK, local_rx_pd->bss_type);
49 if (!priv)
50 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
51
52 rx_info->bss_index = priv->bss_index;
53 ret = mwifiex_process_sta_rx_packet(adapter, skb);
54
55 return ret;
56}
57EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
58
59/*
60 * This function sends a packet to device.
61 *
62 * It processes the packet to add the TxPD, checks condition and
63 * sends the processed packet to firmware for transmission.
64 *
65 * On successful completion, the function calls the completion callback
66 * and logs the time.
67 */
68int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
69 struct mwifiex_tx_param *tx_param)
70{
71 int ret = -1;
72 struct mwifiex_adapter *adapter = priv->adapter;
73 u8 *head_ptr = NULL;
74 struct txpd *local_tx_pd = NULL;
75
76 head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb);
77 if (head_ptr) {
78 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
79 local_tx_pd =
80 (struct txpd *) (head_ptr + INTF_HEADER_LEN);
81
82 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
83 skb->data, skb->len, tx_param);
84 }
85
86 switch (ret) {
87 case -EBUSY:
88 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
89 (adapter->pps_uapsd_mode) &&
90 (adapter->tx_lock_flag)) {
91 priv->adapter->tx_lock_flag = false;
92 local_tx_pd->flags = 0;
93 }
94 dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
95 break;
96 case -1:
97 adapter->data_sent = false;
98 dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
99 ret);
100 adapter->dbg.num_tx_host_to_card_failure++;
101 mwifiex_write_data_complete(adapter, skb, ret);
102 break;
103 case -EINPROGRESS:
104 adapter->data_sent = false;
105 break;
106 case 0:
107 mwifiex_write_data_complete(adapter, skb, ret);
108 break;
109 default:
110 break;
111 }
112
113 return ret;
114}
115
116/*
117 * Packet send completion callback handler.
118 *
119 * It either frees the buffer directly or forwards it to another
120 * completion callback which checks conditions, updates statistics,
121 * wakes up stalled traffic queue if required, and then frees the buffer.
122 */
123int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
124 struct sk_buff *skb, int status)
125{
126 struct mwifiex_private *priv = NULL, *tpriv = NULL;
127 struct mwifiex_txinfo *tx_info = NULL;
128 int i;
129
130 if (!skb)
131 return 0;
132
133 tx_info = MWIFIEX_SKB_TXCB(skb);
134 priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index);
135 if (!priv)
136 goto done;
137
138 priv->netdev->trans_start = jiffies;
139 if (!status) {
140 priv->stats.tx_packets++;
141 priv->stats.tx_bytes += skb->len;
142 } else {
143 priv->stats.tx_errors++;
144 }
145 atomic_dec(&adapter->tx_pending);
146
147 for (i = 0; i < adapter->priv_num; i++) {
148
149 tpriv = adapter->priv[i];
150
151 if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA)
152 && (tpriv->media_connected)) {
153 if (netif_queue_stopped(tpriv->netdev))
154 netif_wake_queue(tpriv->netdev);
155 }
156 }
157done:
158 dev_kfree_skb_any(skb);
159
160 return 0;
161}
162
163/*
164 * Packet receive completion callback handler.
165 *
166 * This function calls another completion callback handler which
167 * updates the statistics, and optionally updates the parent buffer
168 * use count before freeing the received packet.
169 */
170int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter,
171 struct sk_buff *skb, int status)
172{
173 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
174 struct mwifiex_rxinfo *rx_info_parent = NULL;
175 struct mwifiex_private *priv;
176 struct sk_buff *skb_parent = NULL;
177 unsigned long flags;
178
179 priv = adapter->priv[rx_info->bss_index];
180
181 if (priv && (status == -1))
182 priv->stats.rx_dropped++;
183
184 if (rx_info->parent) {
185 skb_parent = rx_info->parent;
186 rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent);
187
188 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
189 --rx_info_parent->use_count;
190
191 if (!rx_info_parent->use_count) {
192 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
193 dev_kfree_skb_any(skb_parent);
194 } else {
195 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
196 }
197 } else {
198 dev_kfree_skb_any(skb);
199 }
200
201 return 0;
202}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
new file mode 100644
index 000000000000..205022aa52f5
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -0,0 +1,252 @@
1/*
2 * Marvell Wireless LAN device driver: utility functions
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28/*
29 * Firmware initialization complete callback handler.
30 *
31 * This function wakes up the function waiting on the init
32 * wait queue for the firmware initialization to complete.
33 */
34int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)
35{
36
37 adapter->init_wait_q_woken = true;
38 wake_up_interruptible(&adapter->init_wait_q);
39 return 0;
40}
41
42/*
43 * Firmware shutdown complete callback handler.
44 *
45 * This function sets the hardware status to not ready and wakes up
46 * the function waiting on the init wait queue for the firmware
47 * shutdown to complete.
48 */
49int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter)
50{
51 adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY;
52 adapter->init_wait_q_woken = true;
53 wake_up_interruptible(&adapter->init_wait_q);
54 return 0;
55}
56
57/*
58 * IOCTL request handler to send function init/shutdown command
59 * to firmware.
60 *
61 * This function prepares the correct firmware command and
62 * issues it.
63 */
64int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter,
65 struct mwifiex_wait_queue *wait,
66 u32 func_init_shutdown)
67{
68 struct mwifiex_private *priv = adapter->priv[wait->bss_index];
69 int ret;
70 u16 cmd;
71
72 if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
73 cmd = HostCmd_CMD_FUNC_INIT;
74 } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
75 cmd = HostCmd_CMD_FUNC_SHUTDOWN;
76 } else {
77 dev_err(adapter->dev, "unsupported parameter\n");
78 return -1;
79 }
80
81 /* Send command to firmware */
82 ret = mwifiex_prepare_cmd(priv, cmd, HostCmd_ACT_GEN_SET,
83 0, wait, NULL);
84
85 if (!ret)
86 ret = -EINPROGRESS;
87
88 return ret;
89}
90
91/*
92 * IOCTL request handler to set/get debug information.
93 *
94 * This function collates/sets the information from/to different driver
95 * structures.
96 */
97int mwifiex_get_debug_info(struct mwifiex_private *priv,
98 struct mwifiex_debug_info *info)
99{
100 struct mwifiex_adapter *adapter = priv->adapter;
101
102 if (info) {
103 memcpy(info->packets_out,
104 priv->wmm.packets_out,
105 sizeof(priv->wmm.packets_out));
106 info->max_tx_buf_size = (u32) adapter->max_tx_buf_size;
107 info->tx_buf_size = (u32) adapter->tx_buf_size;
108 info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(
109 priv, info->rx_tbl);
110 info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(
111 priv, info->tx_tbl);
112 info->ps_mode = adapter->ps_mode;
113 info->ps_state = adapter->ps_state;
114 info->is_deep_sleep = adapter->is_deep_sleep;
115 info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
116 info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
117 info->is_hs_configured = adapter->is_hs_configured;
118 info->hs_activated = adapter->hs_activated;
119 info->num_cmd_host_to_card_failure
120 = adapter->dbg.num_cmd_host_to_card_failure;
121 info->num_cmd_sleep_cfm_host_to_card_failure
122 = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
123 info->num_tx_host_to_card_failure
124 = adapter->dbg.num_tx_host_to_card_failure;
125 info->num_event_deauth = adapter->dbg.num_event_deauth;
126 info->num_event_disassoc = adapter->dbg.num_event_disassoc;
127 info->num_event_link_lost = adapter->dbg.num_event_link_lost;
128 info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
129 info->num_cmd_assoc_success =
130 adapter->dbg.num_cmd_assoc_success;
131 info->num_cmd_assoc_failure =
132 adapter->dbg.num_cmd_assoc_failure;
133 info->num_tx_timeout = adapter->dbg.num_tx_timeout;
134 info->num_cmd_timeout = adapter->dbg.num_cmd_timeout;
135 info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
136 info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
137 memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
138 sizeof(adapter->dbg.last_cmd_id));
139 memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
140 sizeof(adapter->dbg.last_cmd_act));
141 info->last_cmd_index = adapter->dbg.last_cmd_index;
142 memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
143 sizeof(adapter->dbg.last_cmd_resp_id));
144 info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
145 memcpy(info->last_event, adapter->dbg.last_event,
146 sizeof(adapter->dbg.last_event));
147 info->last_event_index = adapter->dbg.last_event_index;
148 info->data_sent = adapter->data_sent;
149 info->cmd_sent = adapter->cmd_sent;
150 info->cmd_resp_received = adapter->cmd_resp_received;
151 }
152
153 return 0;
154}
155
156/*
157 * This function processes the received packet before sending it to the
158 * kernel.
159 *
160 * It extracts the SKB from the received buffer and sends it to kernel.
161 * In case the received buffer does not contain the data in SKB format,
162 * the function creates a blank SKB, fills it with the data from the
163 * received buffer and then sends this new SKB to the kernel.
164 */
165int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
166{
167 struct mwifiex_rxinfo *rx_info = NULL;
168 struct mwifiex_private *priv = NULL;
169
170 if (!skb)
171 return -1;
172
173 rx_info = MWIFIEX_SKB_RXCB(skb);
174 priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
175 if (!priv)
176 return -1;
177
178 skb->dev = priv->netdev;
179 skb->protocol = eth_type_trans(skb, priv->netdev);
180 skb->ip_summed = CHECKSUM_NONE;
181 priv->stats.rx_bytes += skb->len;
182 priv->stats.rx_packets++;
183 if (in_interrupt())
184 netif_rx(skb);
185 else
186 netif_rx_ni(skb);
187
188 return 0;
189}
190
191/*
192 * Receive packet completion callback handler.
193 *
194 * This function updates the statistics and frees the buffer SKB.
195 */
196int mwifiex_recv_complete(struct mwifiex_adapter *adapter,
197 struct sk_buff *skb, int status)
198{
199 struct mwifiex_private *priv = NULL;
200 struct mwifiex_rxinfo *rx_info = NULL;
201
202 if (!skb)
203 return 0;
204
205 rx_info = MWIFIEX_SKB_RXCB(skb);
206 priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
207
208 if (priv && (status == -1))
209 priv->stats.rx_dropped++;
210
211 dev_kfree_skb_any(skb);
212
213 return 0;
214}
215
216/*
217 * IOCTL completion callback handler.
218 *
219 * This function is called when a pending IOCTL is completed.
220 *
221 * If work queue support is enabled, the function wakes up the
222 * corresponding waiting function. Otherwise, it processes the
223 * IOCTL response and frees the response buffer.
224 */
225int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter,
226 struct mwifiex_wait_queue *wait_queue,
227 int status)
228{
229 enum mwifiex_error_code status_code =
230 (enum mwifiex_error_code) wait_queue->status;
231
232 atomic_dec(&adapter->ioctl_pending);
233
234 dev_dbg(adapter->dev, "cmd: IOCTL completed: status=%d,"
235 " status_code=%#x\n", status, status_code);
236
237 if (wait_queue->enabled) {
238 *wait_queue->condition = true;
239 wait_queue->status = status;
240 if (status && (status_code == MWIFIEX_ERROR_CMD_TIMEOUT))
241 dev_err(adapter->dev, "cmd timeout\n");
242 else
243 wake_up_interruptible(wait_queue->wait);
244 } else {
245 if (status)
246 dev_err(adapter->dev, "cmd failed: status_code=%#x\n",
247 status_code);
248 kfree(wait_queue);
249 }
250
251 return 0;
252}
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
new file mode 100644
index 000000000000..9506afc6c0e4
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -0,0 +1,32 @@
1/*
2 * Marvell Wireless LAN device driver: utility functions
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_UTIL_H_
21#define _MWIFIEX_UTIL_H_
22
23static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
24{
25 return (struct mwifiex_rxinfo *)skb->cb;
26}
27
28static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
29{
30 return (struct mwifiex_txinfo *)skb->cb;
31}
32#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
new file mode 100644
index 000000000000..1cfbc6bed692
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -0,0 +1,1237 @@
1/*
2 * Marvell Wireless LAN device driver: WMM
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28
29/* Maximum value FW can accept for driver delay in packet transmission */
30#define DRV_PKT_DELAY_TO_FW_MAX 512
31
32
33#define WMM_QUEUED_PACKET_LOWER_LIMIT 180
34
35#define WMM_QUEUED_PACKET_UPPER_LIMIT 200
36
37/* Offset for TOS field in the IP header */
38#define IPTOS_OFFSET 5
39
40/* WMM information IE */
41static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
42 0x00, 0x50, 0xf2, 0x02,
43 0x00, 0x01, 0x00
44};
45
46static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
47 WMM_AC_BK,
48 WMM_AC_VI,
49 WMM_AC_VO
50};
51
52static u8 tos_to_tid[] = {
53 /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
54 0x01, /* 0 1 0 AC_BK */
55 0x02, /* 0 0 0 AC_BK */
56 0x00, /* 0 0 1 AC_BE */
57 0x03, /* 0 1 1 AC_BE */
58 0x04, /* 1 0 0 AC_VI */
59 0x05, /* 1 0 1 AC_VI */
60 0x06, /* 1 1 0 AC_VO */
61 0x07 /* 1 1 1 AC_VO */
62};
63
64/*
65 * This table inverses the tos_to_tid operation to get a priority
66 * which is in sequential order, and can be compared.
67 * Use this to compare the priority of two different TIDs.
68 */
69static u8 tos_to_tid_inv[] = {
70 0x02, /* from tos_to_tid[2] = 0 */
71 0x00, /* from tos_to_tid[0] = 1 */
72 0x01, /* from tos_to_tid[1] = 2 */
73 0x03,
74 0x04,
75 0x05,
76 0x06,
77 0x07};
78
79static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
80
81/*
82 * This function debug prints the priority parameters for a WMM AC.
83 */
84static void
85mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param)
86{
87 const char *ac_str[] = { "BK", "BE", "VI", "VO" };
88
89 pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
90 "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
91 ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap
92 & MWIFIEX_ACI) >> 5]],
93 (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5,
94 (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4,
95 ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN,
96 ac_param->ecw_bitmap & MWIFIEX_ECW_MIN,
97 (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4,
98 le16_to_cpu(ac_param->tx_op_limit));
99}
100
101/*
102 * This function allocates a route address list.
103 *
104 * The function also initializes the list with the provided RA.
105 */
106static struct mwifiex_ra_list_tbl *
107mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
108{
109 struct mwifiex_ra_list_tbl *ra_list;
110
111 ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC);
112
113 if (!ra_list) {
114 dev_err(adapter->dev, "%s: failed to alloc ra_list\n",
115 __func__);
116 return NULL;
117 }
118 INIT_LIST_HEAD(&ra_list->list);
119 skb_queue_head_init(&ra_list->skb_head);
120
121 memcpy(ra_list->ra, ra, ETH_ALEN);
122
123 ra_list->total_pkts_size = 0;
124
125 dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
126
127 return ra_list;
128}
129
130/*
131 * This function allocates and adds a RA list for all TIDs
132 * with the given RA.
133 */
134void
135mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
136{
137 int i;
138 struct mwifiex_ra_list_tbl *ra_list;
139 struct mwifiex_adapter *adapter = priv->adapter;
140
141 for (i = 0; i < MAX_NUM_TID; ++i) {
142 ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
143 dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list);
144
145 if (!ra_list)
146 break;
147
148 if (!mwifiex_queuing_ra_based(priv))
149 ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
150 else
151 ra_list->is_11n_enabled = false;
152
153 dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
154 ra_list, ra_list->is_11n_enabled);
155
156 list_add_tail(&ra_list->list,
157 &priv->wmm.tid_tbl_ptr[i].ra_list);
158
159 if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
160 priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
161 }
162}
163
164/*
165 * This function sets the WMM queue priorities to their default values.
166 */
167static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
168{
169 /* Default queue priorities: VO->VI->BE->BK */
170 priv->wmm.queue_priority[0] = WMM_AC_VO;
171 priv->wmm.queue_priority[1] = WMM_AC_VI;
172 priv->wmm.queue_priority[2] = WMM_AC_BE;
173 priv->wmm.queue_priority[3] = WMM_AC_BK;
174}
175
176/*
177 * This function map ACs to TIDs.
178 */
179static void
180mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv,
181 u8 queue_priority[])
182{
183 int i;
184
185 for (i = 0; i < 4; ++i) {
186 tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
187 tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
188 }
189}
190
191/*
192 * This function initializes WMM priority queues.
193 */
194void
195mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
196 struct ieee_types_wmm_parameter *wmm_ie)
197{
198 u16 cw_min, avg_back_off, tmp[4];
199 u32 i, j, num_ac;
200 u8 ac_idx;
201
202 if (!wmm_ie || !priv->wmm_enabled) {
203 /* WMM is not enabled, just set the defaults and return */
204 mwifiex_wmm_default_queue_priorities(priv);
205 return;
206 }
207
208 dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, "
209 "qos_info Parameter Set Count=%d, Reserved=%#x\n",
210 wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
211 IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
212 wmm_ie->reserved);
213
214 for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) {
215 cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap &
216 MWIFIEX_ECW_MIN)) - 1;
217 avg_back_off = (cw_min >> 1) +
218 (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap &
219 MWIFIEX_AIFSN);
220
221 ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac].
222 aci_aifsn_bitmap &
223 MWIFIEX_ACI) >> 5];
224 priv->wmm.queue_priority[ac_idx] = ac_idx;
225 tmp[ac_idx] = avg_back_off;
226
227 dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
228 (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap &
229 MWIFIEX_ECW_MAX) >> 4)) - 1,
230 cw_min, avg_back_off);
231 mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]);
232 }
233
234 /* Bubble sort */
235 for (i = 0; i < num_ac; i++) {
236 for (j = 1; j < num_ac - i; j++) {
237 if (tmp[j - 1] > tmp[j]) {
238 swap(tmp[j - 1], tmp[j]);
239 swap(priv->wmm.queue_priority[j - 1],
240 priv->wmm.queue_priority[j]);
241 } else if (tmp[j - 1] == tmp[j]) {
242 if (priv->wmm.queue_priority[j - 1]
243 < priv->wmm.queue_priority[j])
244 swap(priv->wmm.queue_priority[j - 1],
245 priv->wmm.queue_priority[j]);
246 }
247 }
248 }
249
250 mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
251}
252
253/*
254 * This function evaluates whether or not an AC is to be downgraded.
255 *
256 * In case the AC is not enabled, the highest AC is returned that is
257 * enabled and does not require admission control.
258 */
259static enum mwifiex_wmm_ac_e
260mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv,
261 enum mwifiex_wmm_ac_e eval_ac)
262{
263 int down_ac;
264 enum mwifiex_wmm_ac_e ret_ac;
265 struct mwifiex_wmm_ac_status *ac_status;
266
267 ac_status = &priv->wmm.ac_status[eval_ac];
268
269 if (!ac_status->disabled)
270 /* Okay to use this AC, its enabled */
271 return eval_ac;
272
273 /* Setup a default return value of the lowest priority */
274 ret_ac = WMM_AC_BK;
275
276 /*
277 * Find the highest AC that is enabled and does not require
278 * admission control. The spec disallows downgrading to an AC,
279 * which is enabled due to a completed admission control.
280 * Unadmitted traffic is not to be sent on an AC with admitted
281 * traffic.
282 */
283 for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
284 ac_status = &priv->wmm.ac_status[down_ac];
285
286 if (!ac_status->disabled && !ac_status->flow_required)
287 /* AC is enabled and does not require admission
288 control */
289 ret_ac = (enum mwifiex_wmm_ac_e) down_ac;
290 }
291
292 return ret_ac;
293}
294
295/*
296 * This function downgrades WMM priority queue.
297 */
298void
299mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
300{
301 int ac_val;
302
303 dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:"
304 "BK(0), BE(1), VI(2), VO(3)\n");
305
306 if (!priv->wmm_enabled) {
307 /* WMM is not enabled, default priorities */
308 for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++)
309 priv->wmm.ac_down_graded_vals[ac_val] =
310 (enum mwifiex_wmm_ac_e) ac_val;
311 } else {
312 for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
313 priv->wmm.ac_down_graded_vals[ac_val]
314 = mwifiex_wmm_eval_downgrade_ac(priv,
315 (enum mwifiex_wmm_ac_e) ac_val);
316 dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n",
317 ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
318 }
319 }
320}
321
322/*
323 * This function converts the IP TOS field to an WMM AC
324 * Queue assignment.
325 */
326static enum mwifiex_wmm_ac_e
327mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
328{
329 /* Map of TOS UP values to WMM AC */
330 const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
331 WMM_AC_BK,
332 WMM_AC_BK,
333 WMM_AC_BE,
334 WMM_AC_VI,
335 WMM_AC_VI,
336 WMM_AC_VO,
337 WMM_AC_VO
338 };
339
340 if (tos >= ARRAY_SIZE(tos_to_ac))
341 return WMM_AC_BE;
342
343 return tos_to_ac[tos];
344}
345
346/*
347 * This function evaluates a given TID and downgrades it to a lower
348 * TID if the WMM Parameter IE received from the AP indicates that the
349 * AP is disabled (due to call admission control (ACM bit). Mapping
350 * of TID to AC is taken care of internally.
351 */
352static u8
353mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
354{
355 enum mwifiex_wmm_ac_e ac, ac_down;
356 u8 new_tid;
357
358 ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid);
359 ac_down = priv->wmm.ac_down_graded_vals[ac];
360
361 /* Send the index to tid array, picking from the array will be
362 * taken care by dequeuing function
363 */
364 new_tid = ac_to_tid[ac_down][tid % 2];
365
366 return new_tid;
367}
368
369/*
370 * This function initializes the WMM state information and the
371 * WMM data path queues.
372 */
373void
374mwifiex_wmm_init(struct mwifiex_adapter *adapter)
375{
376 int i, j;
377 struct mwifiex_private *priv;
378
379 for (j = 0; j < adapter->priv_num; ++j) {
380 priv = adapter->priv[j];
381 if (!priv)
382 continue;
383
384 for (i = 0; i < MAX_NUM_TID; ++i) {
385 priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
386 priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i];
387 priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
388 priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
389 }
390
391 priv->aggr_prio_tbl[6].amsdu
392 = priv->aggr_prio_tbl[6].ampdu_ap
393 = priv->aggr_prio_tbl[6].ampdu_user
394 = BA_STREAM_NOT_ALLOWED;
395
396 priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
397 = priv->aggr_prio_tbl[7].ampdu_user
398 = BA_STREAM_NOT_ALLOWED;
399
400 priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
401 priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
402 priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
403 }
404}
405
406/*
407 * This function checks if WMM Tx queue is empty.
408 */
409int
410mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
411{
412 int i, j;
413 struct mwifiex_private *priv;
414
415 for (j = 0; j < adapter->priv_num; ++j) {
416 priv = adapter->priv[j];
417 if (priv) {
418 for (i = 0; i < MAX_NUM_TID; i++)
419 if (!mwifiex_wmm_is_ra_list_empty(adapter,
420 &priv->wmm.tid_tbl_ptr[i].ra_list))
421 return false;
422 }
423 }
424
425 return true;
426}
427
428/*
429 * This function deletes all packets in an RA list node.
430 *
431 * The packet sent completion callback handler are called with
432 * status failure, after they are dequeued to ensure proper
433 * cleanup. The RA list node itself is freed at the end.
434 */
435static void
436mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,
437 struct mwifiex_ra_list_tbl *ra_list)
438{
439 struct mwifiex_adapter *adapter = priv->adapter;
440 struct sk_buff *skb, *tmp;
441
442 skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
443 mwifiex_write_data_complete(adapter, skb, -1);
444}
445
446/*
447 * This function deletes all packets in an RA list.
448 *
449 * Each nodes in the RA list are freed individually first, and then
450 * the RA list itself is freed.
451 */
452static void
453mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv,
454 struct list_head *ra_list_head)
455{
456 struct mwifiex_ra_list_tbl *ra_list;
457
458 list_for_each_entry(ra_list, ra_list_head, list)
459 mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list);
460}
461
462/*
463 * This function deletes all packets in all RA lists.
464 */
465static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
466{
467 int i;
468
469 for (i = 0; i < MAX_NUM_TID; i++)
470 mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
471 ra_list);
472}
473
474/*
475 * This function deletes all route addresses from all RA lists.
476 */
477static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
478{
479 struct mwifiex_ra_list_tbl *ra_list, *tmp_node;
480 int i;
481
482 for (i = 0; i < MAX_NUM_TID; ++i) {
483 dev_dbg(priv->adapter->dev,
484 "info: ra_list: freeing buf for tid %d\n", i);
485 list_for_each_entry_safe(ra_list, tmp_node,
486 &priv->wmm.tid_tbl_ptr[i].ra_list, list) {
487 list_del(&ra_list->list);
488 kfree(ra_list);
489 }
490
491 INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list);
492
493 priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
494 }
495}
496
497/*
498 * This function cleans up the Tx and Rx queues.
499 *
500 * Cleanup includes -
501 * - All packets in RA lists
502 * - All entries in Rx reorder table
503 * - All entries in Tx BA stream table
504 * - MPA buffer (if required)
505 * - All RA lists
506 */
507void
508mwifiex_clean_txrx(struct mwifiex_private *priv)
509{
510 unsigned long flags;
511
512 mwifiex_11n_cleanup_reorder_tbl(priv);
513 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
514
515 mwifiex_wmm_cleanup_queues(priv);
516 mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
517
518 if (priv->adapter->if_ops.cleanup_mpa_buf)
519 priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter);
520
521 mwifiex_wmm_delete_all_ralist(priv);
522 memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
523
524 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
525}
526
527/*
528 * This function retrieves a particular RA list node, matching with the
529 * given TID and RA address.
530 */
531static struct mwifiex_ra_list_tbl *
532mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
533 u8 *ra_addr)
534{
535 struct mwifiex_ra_list_tbl *ra_list;
536
537 list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list,
538 list) {
539 if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN))
540 return ra_list;
541 }
542
543 return NULL;
544}
545
546/*
547 * This function retrieves an RA list node for a given TID and
548 * RA address pair.
549 *
550 * If no such node is found, a new node is added first and then
551 * retrieved.
552 */
553static struct mwifiex_ra_list_tbl *
554mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
555{
556 struct mwifiex_ra_list_tbl *ra_list;
557
558 ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
559 if (ra_list)
560 return ra_list;
561 mwifiex_ralist_add(priv, ra_addr);
562
563 return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
564}
565
566/*
567 * This function checks if a particular RA list node exists in a given TID
568 * table index.
569 */
570int
571mwifiex_is_ralist_valid(struct mwifiex_private *priv,
572 struct mwifiex_ra_list_tbl *ra_list, int ptr_index)
573{
574 struct mwifiex_ra_list_tbl *rlist;
575
576 list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list,
577 list) {
578 if (rlist == ra_list)
579 return true;
580 }
581
582 return false;
583}
584
585/*
586 * This function adds a packet to WMM queue.
587 *
588 * In disconnected state the packet is immediately dropped and the
589 * packet send completion callback is called with status failure.
590 *
591 * Otherwise, the correct RA list node is located and the packet
592 * is queued at the list tail.
593 */
594void
595mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
596 struct sk_buff *skb)
597{
598 struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
599 struct mwifiex_private *priv = adapter->priv[tx_info->bss_index];
600 u32 tid;
601 struct mwifiex_ra_list_tbl *ra_list;
602 u8 ra[ETH_ALEN], tid_down;
603 unsigned long flags;
604
605 if (!priv->media_connected) {
606 dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
607 mwifiex_write_data_complete(adapter, skb, -1);
608 return;
609 }
610
611 tid = skb->priority;
612
613 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
614
615 tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
616
617 /* In case of infra as we have already created the list during
618 association we just don't have to call get_queue_raptr, we will
619 have only 1 raptr for a tid in case of infra */
620 if (!mwifiex_queuing_ra_based(priv)) {
621 if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
622 ra_list = list_first_entry(
623 &priv->wmm.tid_tbl_ptr[tid_down].ra_list,
624 struct mwifiex_ra_list_tbl, list);
625 else
626 ra_list = NULL;
627 } else {
628 memcpy(ra, skb->data, ETH_ALEN);
629 ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
630 }
631
632 if (!ra_list) {
633 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
634 mwifiex_write_data_complete(adapter, skb, -1);
635 return;
636 }
637
638 skb_queue_tail(&ra_list->skb_head, skb);
639
640 ra_list->total_pkts_size += skb->len;
641
642 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
643}
644
645/*
646 * This function processes the get WMM status command response from firmware.
647 *
648 * The response may contain multiple TLVs -
649 * - AC Queue status TLVs
650 * - Current WMM Parameter IE TLV
651 * - Admission Control action frame TLVs
652 *
653 * This function parses the TLVs and then calls further specific functions
654 * to process any changes in the queue prioritize or state.
655 */
656int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
657 const struct host_cmd_ds_command *resp)
658{
659 u8 *curr = (u8 *) &resp->params.get_wmm_status;
660 uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
661 int valid = true;
662
663 struct mwifiex_ie_types_data *tlv_hdr;
664 struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus;
665 struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
666 struct mwifiex_wmm_ac_status *ac_status;
667
668 dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
669 resp_len);
670
671 while ((resp_len >= sizeof(tlv_hdr->header)) && valid) {
672 tlv_hdr = (struct mwifiex_ie_types_data *) curr;
673 tlv_len = le16_to_cpu(tlv_hdr->header.len);
674
675 switch (le16_to_cpu(tlv_hdr->header.type)) {
676 case TLV_TYPE_WMMQSTATUS:
677 tlv_wmm_qstatus =
678 (struct mwifiex_ie_types_wmm_queue_status *)
679 tlv_hdr;
680 dev_dbg(priv->adapter->dev,
681 "info: CMD_RESP: WMM_GET_STATUS:"
682 " QSTATUS TLV: %d, %d, %d\n",
683 tlv_wmm_qstatus->queue_index,
684 tlv_wmm_qstatus->flow_required,
685 tlv_wmm_qstatus->disabled);
686
687 ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus->
688 queue_index];
689 ac_status->disabled = tlv_wmm_qstatus->disabled;
690 ac_status->flow_required =
691 tlv_wmm_qstatus->flow_required;
692 ac_status->flow_created = tlv_wmm_qstatus->flow_created;
693 break;
694
695 case WLAN_EID_VENDOR_SPECIFIC:
696 /*
697 * Point the regular IEEE IE 2 bytes into the Marvell IE
698 * and setup the IEEE IE type and length byte fields
699 */
700
701 wmm_param_ie =
702 (struct ieee_types_wmm_parameter *) (curr +
703 2);
704 wmm_param_ie->vend_hdr.len = (u8) tlv_len;
705 wmm_param_ie->vend_hdr.element_id =
706 WLAN_EID_VENDOR_SPECIFIC;
707
708 dev_dbg(priv->adapter->dev,
709 "info: CMD_RESP: WMM_GET_STATUS:"
710 " WMM Parameter Set Count: %d\n",
711 wmm_param_ie->qos_info_bitmap &
712 IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
713
714 memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
715 wmm_ie, wmm_param_ie,
716 wmm_param_ie->vend_hdr.len + 2);
717
718 break;
719
720 default:
721 valid = false;
722 break;
723 }
724
725 curr += (tlv_len + sizeof(tlv_hdr->header));
726 resp_len -= (tlv_len + sizeof(tlv_hdr->header));
727 }
728
729 mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
730 mwifiex_wmm_setup_ac_downgrade(priv);
731
732 return 0;
733}
734
735/*
736 * Callback handler from the command module to allow insertion of a WMM TLV.
737 *
738 * If the BSS we are associating to supports WMM, this function adds the
739 * required WMM Information IE to the association request command buffer in
740 * the form of a Marvell extended IEEE IE.
741 */
742u32
743mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
744 u8 **assoc_buf,
745 struct ieee_types_wmm_parameter *wmm_ie,
746 struct ieee80211_ht_cap *ht_cap)
747{
748 struct mwifiex_ie_types_wmm_param_set *wmm_tlv;
749 u32 ret_len = 0;
750
751 /* Null checks */
752 if (!assoc_buf)
753 return 0;
754 if (!(*assoc_buf))
755 return 0;
756
757 if (!wmm_ie)
758 return 0;
759
760 dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:"
761 "bss->wmmIe=0x%x\n",
762 wmm_ie->vend_hdr.element_id);
763
764 if ((priv->wmm_required
765 || (ht_cap && (priv->adapter->config_bands & BAND_GN
766 || priv->adapter->config_bands & BAND_AN))
767 )
768 && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) {
769 wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf;
770 wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]);
771 wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]);
772 memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2],
773 le16_to_cpu(wmm_tlv->header.len));
774 if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD)
775 memcpy((u8 *) (wmm_tlv->wmm_ie
776 + le16_to_cpu(wmm_tlv->header.len)
777 - sizeof(priv->wmm_qosinfo)),
778 &priv->wmm_qosinfo,
779 sizeof(priv->wmm_qosinfo));
780
781 ret_len = sizeof(wmm_tlv->header)
782 + le16_to_cpu(wmm_tlv->header.len);
783
784 *assoc_buf += ret_len;
785 }
786
787 return ret_len;
788}
789
790/*
791 * This function computes the time delay in the driver queues for a
792 * given packet.
793 *
794 * When the packet is received at the OS/Driver interface, the current
795 * time is set in the packet structure. The difference between the present
796 * time and that received time is computed in this function and limited
797 * based on pre-compiled limits in the driver.
798 */
799u8
800mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
801 const struct sk_buff *skb)
802{
803 u8 ret_val = 0;
804 struct timeval out_tstamp, in_tstamp;
805 u32 queue_delay;
806
807 do_gettimeofday(&out_tstamp);
808 in_tstamp = ktime_to_timeval(skb->tstamp);
809
810 queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000;
811 queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000;
812
813 /*
814 * Queue delay is passed as a uint8 in units of 2ms (ms shifted
815 * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
816 *
817 * Pass max value if queue_delay is beyond the uint8 range
818 */
819 ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
820
821 dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms,"
822 " %d ms sent to FW\n", queue_delay, ret_val);
823
824 return ret_val;
825}
826
827/*
828 * This function retrieves the highest priority RA list table pointer.
829 */
830static struct mwifiex_ra_list_tbl *
831mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
832 struct mwifiex_private **priv, int *tid)
833{
834 struct mwifiex_private *priv_tmp;
835 struct mwifiex_ra_list_tbl *ptr, *head;
836 struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head;
837 struct mwifiex_tid_tbl *tid_ptr;
838 int is_list_empty;
839 unsigned long flags;
840 int i, j;
841
842 for (j = adapter->priv_num - 1; j >= 0; --j) {
843 spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock,
844 flags);
845 is_list_empty = list_empty(&adapter->bss_prio_tbl[j]
846 .bss_prio_head);
847 spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
848 flags);
849 if (is_list_empty)
850 continue;
851
852 if (adapter->bss_prio_tbl[j].bss_prio_cur ==
853 (struct mwifiex_bss_prio_node *)
854 &adapter->bss_prio_tbl[j].bss_prio_head) {
855 bssprio_node =
856 list_first_entry(&adapter->bss_prio_tbl[j]
857 .bss_prio_head,
858 struct mwifiex_bss_prio_node,
859 list);
860 bssprio_head = bssprio_node;
861 } else {
862 bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur;
863 bssprio_head = bssprio_node;
864 }
865
866 do {
867 priv_tmp = bssprio_node->priv;
868
869 for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) {
870
871 tid_ptr = &(priv_tmp)->wmm.
872 tid_tbl_ptr[tos_to_tid[i]];
873
874 spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
875 flags);
876 is_list_empty =
877 list_empty(&adapter->bss_prio_tbl[j]
878 .bss_prio_head);
879 spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock,
880 flags);
881 if (is_list_empty)
882 continue;
883
884 /*
885 * Always choose the next ra we transmitted
886 * last time, this way we pick the ra's in
887 * round robin fashion.
888 */
889 ptr = list_first_entry(
890 &tid_ptr->ra_list_curr->list,
891 struct mwifiex_ra_list_tbl,
892 list);
893
894 head = ptr;
895 if (ptr == (struct mwifiex_ra_list_tbl *)
896 &tid_ptr->ra_list) {
897 /* Get next ra */
898 ptr = list_first_entry(&ptr->list,
899 struct mwifiex_ra_list_tbl, list);
900 head = ptr;
901 }
902
903 do {
904 is_list_empty =
905 skb_queue_empty(&ptr->skb_head);
906 if (!is_list_empty) {
907 *priv = priv_tmp;
908 *tid = tos_to_tid[i];
909 return ptr;
910 }
911 /* Get next ra */
912 ptr = list_first_entry(&ptr->list,
913 struct mwifiex_ra_list_tbl,
914 list);
915 if (ptr ==
916 (struct mwifiex_ra_list_tbl *)
917 &tid_ptr->ra_list)
918 ptr = list_first_entry(
919 &ptr->list,
920 struct mwifiex_ra_list_tbl,
921 list);
922 } while (ptr != head);
923 }
924
925 /* Get next bss priority node */
926 bssprio_node = list_first_entry(&bssprio_node->list,
927 struct mwifiex_bss_prio_node,
928 list);
929
930 if (bssprio_node ==
931 (struct mwifiex_bss_prio_node *)
932 &adapter->bss_prio_tbl[j].bss_prio_head)
933 /* Get next bss priority node */
934 bssprio_node = list_first_entry(
935 &bssprio_node->list,
936 struct mwifiex_bss_prio_node,
937 list);
938 } while (bssprio_node != bssprio_head);
939 }
940 return NULL;
941}
942
943/*
944 * This function gets the number of packets in the Tx queue of a
945 * particular RA list.
946 */
947static int
948mwifiex_num_pkts_in_txq(struct mwifiex_private *priv,
949 struct mwifiex_ra_list_tbl *ptr, int max_buf_size)
950{
951 int count = 0, total_size = 0;
952 struct sk_buff *skb, *tmp;
953
954 skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
955 total_size += skb->len;
956 if (total_size < max_buf_size)
957 ++count;
958 else
959 break;
960 }
961
962 return count;
963}
964
965/*
966 * This function sends a single packet to firmware for transmission.
967 */
968static void
969mwifiex_send_single_packet(struct mwifiex_private *priv,
970 struct mwifiex_ra_list_tbl *ptr, int ptr_index,
971 unsigned long ra_list_flags)
972 __releases(&priv->wmm.ra_list_spinlock)
973{
974 struct sk_buff *skb, *skb_next;
975 struct mwifiex_tx_param tx_param;
976 struct mwifiex_adapter *adapter = priv->adapter;
977 int status = 0;
978 struct mwifiex_txinfo *tx_info;
979
980 if (skb_queue_empty(&ptr->skb_head)) {
981 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
982 ra_list_flags);
983 dev_dbg(adapter->dev, "data: nothing to send\n");
984 return;
985 }
986
987 skb = skb_dequeue(&ptr->skb_head);
988
989 tx_info = MWIFIEX_SKB_TXCB(skb);
990 dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
991
992 ptr->total_pkts_size -= skb->len;
993
994 if (!skb_queue_empty(&ptr->skb_head))
995 skb_next = skb_peek(&ptr->skb_head);
996 else
997 skb_next = NULL;
998
999 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
1000
1001 tx_param.next_pkt_len = ((skb_next) ? skb_next->len +
1002 sizeof(struct txpd) : 0);
1003
1004 status = mwifiex_process_tx(priv, skb, &tx_param);
1005
1006 if (status == -EBUSY) {
1007 /* Queue the packet back at the head */
1008 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1009
1010 if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1011 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1012 ra_list_flags);
1013 mwifiex_write_data_complete(adapter, skb, -1);
1014 return;
1015 }
1016
1017 skb_queue_tail(&ptr->skb_head, skb);
1018
1019 ptr->total_pkts_size += skb->len;
1020 tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
1021 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1022 ra_list_flags);
1023 } else {
1024 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1025 if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1026 priv->wmm.packets_out[ptr_index]++;
1027 priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
1028 }
1029 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
1030 list_first_entry(
1031 &adapter->bss_prio_tbl[priv->bss_priority]
1032 .bss_prio_cur->list,
1033 struct mwifiex_bss_prio_node,
1034 list);
1035 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1036 ra_list_flags);
1037 }
1038}
1039
1040/*
1041 * This function checks if the first packet in the given RA list
1042 * is already processed or not.
1043 */
1044static int
1045mwifiex_is_ptr_processed(struct mwifiex_private *priv,
1046 struct mwifiex_ra_list_tbl *ptr)
1047{
1048 struct sk_buff *skb;
1049 struct mwifiex_txinfo *tx_info;
1050
1051 if (skb_queue_empty(&ptr->skb_head))
1052 return false;
1053
1054 skb = skb_peek(&ptr->skb_head);
1055
1056 tx_info = MWIFIEX_SKB_TXCB(skb);
1057 if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT)
1058 return true;
1059
1060 return false;
1061}
1062
1063/*
1064 * This function sends a single processed packet to firmware for
1065 * transmission.
1066 */
1067static void
1068mwifiex_send_processed_packet(struct mwifiex_private *priv,
1069 struct mwifiex_ra_list_tbl *ptr, int ptr_index,
1070 unsigned long ra_list_flags)
1071 __releases(&priv->wmm.ra_list_spinlock)
1072{
1073 struct mwifiex_tx_param tx_param;
1074 struct mwifiex_adapter *adapter = priv->adapter;
1075 int ret = -1;
1076 struct sk_buff *skb, *skb_next;
1077 struct mwifiex_txinfo *tx_info;
1078
1079 if (skb_queue_empty(&ptr->skb_head)) {
1080 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1081 ra_list_flags);
1082 return;
1083 }
1084
1085 skb = skb_dequeue(&ptr->skb_head);
1086
1087 if (!skb_queue_empty(&ptr->skb_head))
1088 skb_next = skb_peek(&ptr->skb_head);
1089 else
1090 skb_next = NULL;
1091
1092 tx_info = MWIFIEX_SKB_TXCB(skb);
1093
1094 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
1095 tx_param.next_pkt_len =
1096 ((skb_next) ? skb_next->len +
1097 sizeof(struct txpd) : 0);
1098 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
1099 skb->data, skb->len, &tx_param);
1100 switch (ret) {
1101 case -EBUSY:
1102 dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
1103 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1104
1105 if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1106 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1107 ra_list_flags);
1108 mwifiex_write_data_complete(adapter, skb, -1);
1109 return;
1110 }
1111
1112 skb_queue_tail(&ptr->skb_head, skb);
1113
1114 tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
1115 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1116 ra_list_flags);
1117 break;
1118 case -1:
1119 adapter->data_sent = false;
1120 dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
1121 adapter->dbg.num_tx_host_to_card_failure++;
1122 mwifiex_write_data_complete(adapter, skb, ret);
1123 break;
1124 case -EINPROGRESS:
1125 adapter->data_sent = false;
1126 default:
1127 break;
1128 }
1129 if (ret != -EBUSY) {
1130 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1131 if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1132 priv->wmm.packets_out[ptr_index]++;
1133 priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
1134 }
1135 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
1136 list_first_entry(
1137 &adapter->bss_prio_tbl[priv->bss_priority]
1138 .bss_prio_cur->list,
1139 struct mwifiex_bss_prio_node,
1140 list);
1141 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1142 ra_list_flags);
1143 }
1144}
1145
1146/*
1147 * This function dequeues a packet from the highest priority list
1148 * and transmits it.
1149 */
1150static int
1151mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
1152{
1153 struct mwifiex_ra_list_tbl *ptr;
1154 struct mwifiex_private *priv = NULL;
1155 int ptr_index = 0;
1156 u8 ra[ETH_ALEN];
1157 int tid_del = 0, tid = 0;
1158 unsigned long flags;
1159
1160 ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index);
1161 if (!ptr)
1162 return -1;
1163
1164 tid = mwifiex_get_tid(priv->adapter, ptr);
1165
1166 dev_dbg(adapter->dev, "data: tid=%d\n", tid);
1167
1168 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
1169 if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1170 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
1171 return -1;
1172 }
1173
1174 if (mwifiex_is_ptr_processed(priv, ptr)) {
1175 mwifiex_send_processed_packet(priv, ptr, ptr_index, flags);
1176 /* ra_list_spinlock has been freed in
1177 mwifiex_send_processed_packet() */
1178 return 0;
1179 }
1180
1181 if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid)
1182 || ((priv->sec_info.wpa_enabled
1183 || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set)
1184 ) {
1185 mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
1186 /* ra_list_spinlock has been freed in
1187 mwifiex_send_single_packet() */
1188 } else {
1189 if (mwifiex_is_ampdu_allowed(priv, ptr, tid)) {
1190 if (mwifiex_is_ba_stream_avail(priv)) {
1191 mwifiex_11n_create_tx_ba_stream_tbl(priv,
1192 ptr->ra, tid,
1193 BA_STREAM_SETUP_INPROGRESS);
1194 mwifiex_send_addba(priv, tid, ptr->ra);
1195 } else if (mwifiex_find_stream_to_delete
1196 (priv, ptr, tid, &tid_del, ra)) {
1197 mwifiex_11n_create_tx_ba_stream_tbl(priv,
1198 ptr->ra, tid,
1199 BA_STREAM_SETUP_INPROGRESS);
1200 mwifiex_send_delba(priv, tid_del, ra, 1);
1201 }
1202 }
1203/* Minimum number of AMSDU */
1204#define MIN_NUM_AMSDU 2
1205 if (mwifiex_is_amsdu_allowed(priv, ptr, tid) &&
1206 (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >=
1207 MIN_NUM_AMSDU))
1208 mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
1209 ptr_index, flags);
1210 /* ra_list_spinlock has been freed in
1211 mwifiex_11n_aggregate_pkt() */
1212 else
1213 mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
1214 /* ra_list_spinlock has been freed in
1215 mwifiex_send_single_packet() */
1216 }
1217 return 0;
1218}
1219
1220/*
1221 * This function transmits the highest priority packet awaiting in the
1222 * WMM Queues.
1223 */
1224void
1225mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
1226{
1227 do {
1228 /* Check if busy */
1229 if (adapter->data_sent || adapter->tx_lock_flag)
1230 break;
1231
1232 if (mwifiex_dequeue_tx_packet(adapter))
1233 break;
1234 } while (true);
1235
1236 return;
1237}
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h
new file mode 100644
index 000000000000..241f1b0b77f9
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -0,0 +1,112 @@
1/*
2 * Marvell Wireless LAN device driver: WMM
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#ifndef _MWIFIEX_WMM_H_
21#define _MWIFIEX_WMM_H_
22
23enum ieee_types_wmm_aciaifsn_bitmasks {
24 MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)),
25 MWIFIEX_ACM = BIT(4),
26 MWIFIEX_ACI = (BIT(5) | BIT(6)),
27};
28
29enum ieee_types_wmm_ecw_bitmasks {
30 MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)),
31 MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)),
32};
33
34/*
35 * This function retrieves the TID of the given RA list.
36 */
37static inline int
38mwifiex_get_tid(struct mwifiex_adapter *adapter,
39 struct mwifiex_ra_list_tbl *ptr)
40{
41 struct sk_buff *skb;
42
43 if (skb_queue_empty(&ptr->skb_head))
44 return 0;
45
46 skb = skb_peek(&ptr->skb_head);
47
48 return skb->priority;
49}
50
51/*
52 * This function gets the length of a list.
53 */
54static inline int
55mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head)
56{
57 struct list_head *pos;
58 int count = 0;
59
60 list_for_each(pos, head)
61 ++count;
62
63 return count;
64}
65
66/*
67 * This function checks if a RA list is empty or not.
68 */
69static inline u8
70mwifiex_wmm_is_ra_list_empty(struct mwifiex_adapter *adapter,
71 struct list_head *ra_list_hhead)
72{
73 struct mwifiex_ra_list_tbl *ra_list;
74 int is_list_empty;
75
76 list_for_each_entry(ra_list, ra_list_hhead, list) {
77 is_list_empty = skb_queue_empty(&ra_list->skb_head);
78 if (!is_list_empty)
79 return false;
80 }
81
82 return true;
83}
84
85void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
86 struct sk_buff *skb);
87void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra);
88
89int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter);
90void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter);
91int mwifiex_is_ralist_valid(struct mwifiex_private *priv,
92 struct mwifiex_ra_list_tbl *ra_list, int tid);
93
94u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
95 const struct sk_buff *skb);
96void mwifiex_wmm_init(struct mwifiex_adapter *adapter);
97
98extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
99 u8 **assoc_buf,
100 struct ieee_types_wmm_parameter
101 *wmmie,
102 struct ieee80211_ht_cap
103 *htcap);
104
105void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
106 struct ieee_types_wmm_parameter
107 *wmm_ie);
108void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
109extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
110 const struct host_cmd_ds_command *resp);
111
112#endif /* !_MWIFIEX_WMM_H_ */