aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/net/wireless/mwifiex
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/11n.c744
-rw-r--r--drivers/net/wireless/mwifiex/11n.h161
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c302
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.h32
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c616
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.h65
-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.c1419
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.h31
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c360
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c1414
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c770
-rw-r--r--drivers/net/wireless/mwifiex/decl.h129
-rw-r--r--drivers/net/wireless/mwifiex/fw.h1187
-rw-r--r--drivers/net/wireless/mwifiex/init.c645
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h331
-rw-r--r--drivers/net/wireless/mwifiex/join.c1423
-rw-r--r--drivers/net/wireless/mwifiex/main.c1055
-rw-r--r--drivers/net/wireless/mwifiex/main.h1009
-rw-r--r--drivers/net/wireless/mwifiex/scan.c3025
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c1754
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h305
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c1219
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c972
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c406
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c1593
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c200
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c198
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c202
-rw-r--r--drivers/net/wireless/mwifiex/util.c202
-rw-r--r--drivers/net/wireless/mwifiex/util.h32
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c1264
-rw-r--r--drivers/net/wireless/mwifiex/wmm.h110
35 files changed, 23441 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
new file mode 100644
index 000000000000..916183d39009
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -0,0 +1,744 @@
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 * HT capability information field, AMPDU Parameters field, supported MCS set
33 * fields are retrieved from cfg80211 stack
34 *
35 * RD responder bit to set to clear in the extended capability header.
36 */
37void
38mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
39 struct mwifiex_ie_types_htcap *ht_cap)
40{
41 uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
42 struct ieee80211_supported_band *sband =
43 priv->wdev->wiphy->bands[radio_type];
44
45 ht_cap->ht_cap.ampdu_params_info =
46 (sband->ht_cap.ampdu_factor &
47 IEEE80211_HT_AMPDU_PARM_FACTOR)|
48 ((sband->ht_cap.ampdu_density <<
49 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) &
50 IEEE80211_HT_AMPDU_PARM_DENSITY);
51
52 memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs,
53 sizeof(sband->ht_cap.mcs));
54
55 if (priv->bss_mode == NL80211_IFTYPE_STATION ||
56 (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
57 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
58 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
59
60 /* Clear RD responder bit */
61 ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER;
62
63 ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap);
64 ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
65}
66
67/*
68 * This function returns the pointer to an entry in BA Stream
69 * table which matches the requested BA status.
70 */
71static struct mwifiex_tx_ba_stream_tbl *
72mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv,
73 enum mwifiex_ba_status ba_status)
74{
75 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
76 unsigned long flags;
77
78 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
79 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
80 if (tx_ba_tsr_tbl->ba_status == ba_status) {
81 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
82 flags);
83 return tx_ba_tsr_tbl;
84 }
85 }
86 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
87 return NULL;
88}
89
90/*
91 * This function handles the command response of delete a block
92 * ack request.
93 *
94 * The function checks the response success status and takes action
95 * accordingly (send an add BA request in case of success, or recreate
96 * the deleted stream in case of failure, if the add BA was also
97 * initiated by us).
98 */
99int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
100 struct host_cmd_ds_command *resp)
101{
102 int tid;
103 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
104 struct host_cmd_ds_11n_delba *del_ba =
105 (struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
106 uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
107
108 tid = del_ba_param_set >> DELBA_TID_POS;
109 if (del_ba->del_result == BA_RESULT_SUCCESS) {
110 mwifiex_11n_delete_ba_stream_tbl(priv, tid,
111 del_ba->peer_mac_addr, TYPE_DELBA_SENT,
112 INITIATOR_BIT(del_ba_param_set));
113
114 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
115 BA_STREAM_SETUP_INPROGRESS);
116 if (tx_ba_tbl)
117 mwifiex_send_addba(priv, tx_ba_tbl->tid,
118 tx_ba_tbl->ra);
119 } else { /*
120 * In case of failure, recreate the deleted stream in case
121 * we initiated the ADDBA
122 */
123 if (INITIATOR_BIT(del_ba_param_set)) {
124 mwifiex_11n_create_tx_ba_stream_tbl(priv,
125 del_ba->peer_mac_addr, tid,
126 BA_STREAM_SETUP_INPROGRESS);
127
128 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
129 BA_STREAM_SETUP_INPROGRESS);
130 if (tx_ba_tbl)
131 mwifiex_11n_delete_ba_stream_tbl(priv,
132 tx_ba_tbl->tid, tx_ba_tbl->ra,
133 TYPE_DELBA_SENT, true);
134 }
135 }
136
137 return 0;
138}
139
140/*
141 * This function handles the command response of add a block
142 * ack request.
143 *
144 * Handling includes changing the header fields to CPU formats, checking
145 * the response success status and taking actions accordingly (delete the
146 * BA stream table in case of failure).
147 */
148int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
149 struct host_cmd_ds_command *resp)
150{
151 int tid;
152 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
153 (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
154 struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
155
156 add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
157 & SSN_MASK);
158
159 tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
160 & IEEE80211_ADDBA_PARAM_TID_MASK)
161 >> BLOCKACKPARAM_TID_POS;
162 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
163 tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid,
164 add_ba_rsp->peer_mac_addr);
165 if (tx_ba_tbl) {
166 dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
167 tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
168 } else {
169 dev_err(priv->adapter->dev, "BA stream not created\n");
170 }
171 } else {
172 mwifiex_11n_delete_ba_stream_tbl(priv, tid,
173 add_ba_rsp->peer_mac_addr,
174 TYPE_DELBA_SENT, true);
175 if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
176 priv->aggr_prio_tbl[tid].ampdu_ap =
177 BA_STREAM_NOT_ALLOWED;
178 }
179
180 return 0;
181}
182
183/*
184 * This function handles the command response of 11n configuration request.
185 *
186 * Handling includes changing the header fields into CPU format.
187 */
188int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf)
189{
190 struct mwifiex_ds_11n_tx_cfg *tx_cfg;
191 struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
192
193 if (data_buf) {
194 tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
195 tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
196 tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
197 }
198 return 0;
199}
200
201/*
202 * This function prepares command of reconfigure Tx buffer.
203 *
204 * Preparation includes -
205 * - Setting command ID, action and proper size
206 * - Setting Tx buffer size (for SET only)
207 * - Ensuring correct endian-ness
208 */
209int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
210 struct host_cmd_ds_command *cmd, int cmd_action,
211 void *data_buf)
212{
213 struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
214 u16 action = (u16) cmd_action;
215 u16 buf_size = *((u16 *) data_buf);
216
217 cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
218 cmd->size =
219 cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
220 tx_buf->action = cpu_to_le16(action);
221 switch (action) {
222 case HostCmd_ACT_GEN_SET:
223 dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
224 tx_buf->buff_size = cpu_to_le16(buf_size);
225 break;
226 case HostCmd_ACT_GEN_GET:
227 default:
228 tx_buf->buff_size = 0;
229 break;
230 }
231 return 0;
232}
233
234/*
235 * This function prepares command of AMSDU aggregation control.
236 *
237 * Preparation includes -
238 * - Setting command ID, action and proper size
239 * - Setting AMSDU control parameters (for SET only)
240 * - Ensuring correct endian-ness
241 */
242int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
243 int cmd_action, void *data_buf)
244{
245 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
246 &cmd->params.amsdu_aggr_ctrl;
247 u16 action = (u16) cmd_action;
248 struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
249 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
250
251 cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
252 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
253 + S_DS_GEN);
254 amsdu_ctrl->action = cpu_to_le16(action);
255 switch (action) {
256 case HostCmd_ACT_GEN_SET:
257 amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
258 amsdu_ctrl->curr_buf_size = 0;
259 break;
260 case HostCmd_ACT_GEN_GET:
261 default:
262 amsdu_ctrl->curr_buf_size = 0;
263 break;
264 }
265 return 0;
266}
267
268/*
269 * This function handles the command response of AMSDU aggregation
270 * control request.
271 *
272 * Handling includes changing the header fields into CPU format.
273 */
274int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
275 void *data_buf)
276{
277 struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl;
278 struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
279 &resp->params.amsdu_aggr_ctrl;
280
281 if (data_buf) {
282 amsdu_aggr_ctrl =
283 (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
284 amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
285 amsdu_aggr_ctrl->curr_buf_size =
286 le16_to_cpu(amsdu_ctrl->curr_buf_size);
287 }
288 return 0;
289}
290
291/*
292 * This function prepares 11n configuration command.
293 *
294 * Preparation includes -
295 * - Setting command ID, action and proper size
296 * - Setting HT Tx capability and HT Tx information fields
297 * - Ensuring correct endian-ness
298 */
299int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
300 u16 cmd_action, void *data_buf)
301{
302 struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
303 struct mwifiex_ds_11n_tx_cfg *txcfg =
304 (struct mwifiex_ds_11n_tx_cfg *) data_buf;
305
306 cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
307 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
308 htcfg->action = cpu_to_le16(cmd_action);
309 htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
310 htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
311 return 0;
312}
313
314/*
315 * This function appends an 11n TLV to a buffer.
316 *
317 * Buffer allocation is responsibility of the calling
318 * function. No size validation is made here.
319 *
320 * The function fills up the following sections, if applicable -
321 * - HT capability IE
322 * - HT information IE (with channel list)
323 * - 20/40 BSS Coexistence IE
324 * - HT Extended Capabilities IE
325 */
326int
327mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
328 struct mwifiex_bssdescriptor *bss_desc,
329 u8 **buffer)
330{
331 struct mwifiex_ie_types_htcap *ht_cap;
332 struct mwifiex_ie_types_htinfo *ht_info;
333 struct mwifiex_ie_types_chan_list_param_set *chan_list;
334 struct mwifiex_ie_types_2040bssco *bss_co_2040;
335 struct mwifiex_ie_types_extcap *ext_cap;
336 int ret_len = 0;
337 struct ieee80211_supported_band *sband;
338 u8 radio_type;
339
340 if (!buffer || !*buffer)
341 return ret_len;
342
343 radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
344 sband = priv->wdev->wiphy->bands[radio_type];
345
346 if (bss_desc->bcn_ht_cap) {
347 ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
348 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
349 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
350 ht_cap->header.len =
351 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
352 memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
353 (u8 *) bss_desc->bcn_ht_cap +
354 sizeof(struct ieee_types_header),
355 le16_to_cpu(ht_cap->header.len));
356
357 mwifiex_fill_cap_info(priv, radio_type, ht_cap);
358
359 *buffer += sizeof(struct mwifiex_ie_types_htcap);
360 ret_len += sizeof(struct mwifiex_ie_types_htcap);
361 }
362
363 if (bss_desc->bcn_ht_info) {
364 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
365 ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
366 memset(ht_info, 0,
367 sizeof(struct mwifiex_ie_types_htinfo));
368 ht_info->header.type =
369 cpu_to_le16(WLAN_EID_HT_INFORMATION);
370 ht_info->header.len =
371 cpu_to_le16(sizeof(struct ieee80211_ht_info));
372
373 memcpy((u8 *) ht_info +
374 sizeof(struct mwifiex_ie_types_header),
375 (u8 *) bss_desc->bcn_ht_info +
376 sizeof(struct ieee_types_header),
377 le16_to_cpu(ht_info->header.len));
378
379 if (!(sband->ht_cap.cap &
380 IEEE80211_HT_CAP_SUP_WIDTH_20_40))
381 ht_info->ht_info.ht_param &=
382 ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY |
383 IEEE80211_HT_PARAM_CHA_SEC_OFFSET);
384
385 *buffer += sizeof(struct mwifiex_ie_types_htinfo);
386 ret_len += sizeof(struct mwifiex_ie_types_htinfo);
387 }
388
389 chan_list =
390 (struct mwifiex_ie_types_chan_list_param_set *) *buffer;
391 memset(chan_list, 0,
392 sizeof(struct mwifiex_ie_types_chan_list_param_set));
393 chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
394 chan_list->header.len = cpu_to_le16(
395 sizeof(struct mwifiex_ie_types_chan_list_param_set) -
396 sizeof(struct mwifiex_ie_types_header));
397 chan_list->chan_scan_param[0].chan_number =
398 bss_desc->bcn_ht_info->control_chan;
399 chan_list->chan_scan_param[0].radio_type =
400 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
401
402 if ((sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
403 && (bss_desc->bcn_ht_info->ht_param &
404 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
405 SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
406 radio_type,
407 (bss_desc->bcn_ht_info->ht_param &
408 IEEE80211_HT_PARAM_CHA_SEC_OFFSET));
409
410 *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
411 ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
412 }
413
414 if (bss_desc->bcn_bss_co_2040) {
415 bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
416 memset(bss_co_2040, 0,
417 sizeof(struct mwifiex_ie_types_2040bssco));
418 bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
419 bss_co_2040->header.len =
420 cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
421
422 memcpy((u8 *) bss_co_2040 +
423 sizeof(struct mwifiex_ie_types_header),
424 (u8 *) bss_desc->bcn_bss_co_2040 +
425 sizeof(struct ieee_types_header),
426 le16_to_cpu(bss_co_2040->header.len));
427
428 *buffer += sizeof(struct mwifiex_ie_types_2040bssco);
429 ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
430 }
431
432 if (bss_desc->bcn_ext_cap) {
433 ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
434 memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
435 ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
436 ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
437
438 memcpy((u8 *) ext_cap +
439 sizeof(struct mwifiex_ie_types_header),
440 (u8 *) bss_desc->bcn_ext_cap +
441 sizeof(struct ieee_types_header),
442 le16_to_cpu(ext_cap->header.len));
443
444 *buffer += sizeof(struct mwifiex_ie_types_extcap);
445 ret_len += sizeof(struct mwifiex_ie_types_extcap);
446 }
447
448 return ret_len;
449}
450
451/*
452 * This function reconfigures the Tx buffer size in firmware.
453 *
454 * This function prepares a firmware command and issues it, if
455 * the current Tx buffer size is different from the one requested.
456 * Maximum configurable Tx buffer size is limited by the HT capability
457 * field value.
458 */
459void
460mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
461 struct mwifiex_bssdescriptor *bss_desc)
462{
463 u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
464 u16 tx_buf, curr_tx_buf_size = 0;
465
466 if (bss_desc->bcn_ht_cap) {
467 if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
468 IEEE80211_HT_CAP_MAX_AMSDU)
469 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
470 else
471 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
472 }
473
474 tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
475
476 dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
477 max_amsdu, priv->adapter->max_tx_buf_size);
478
479 if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
480 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
481 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
482 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
483 else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
484 curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
485 if (curr_tx_buf_size != tx_buf)
486 mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
487 HostCmd_ACT_GEN_SET, 0, &tx_buf);
488}
489
490/*
491 * This function checks if the given pointer is valid entry of
492 * Tx BA Stream table.
493 */
494static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
495 struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
496{
497 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
498
499 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
500 if (tx_ba_tsr_tbl == tx_tbl_ptr)
501 return true;
502 }
503
504 return false;
505}
506
507/*
508 * This function deletes the given entry in Tx BA Stream table.
509 *
510 * The function also performs a validity check on the supplied
511 * pointer before trying to delete.
512 */
513void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
514 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
515{
516 if (!tx_ba_tsr_tbl &&
517 mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
518 return;
519
520 dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
521
522 list_del(&tx_ba_tsr_tbl->list);
523
524 kfree(tx_ba_tsr_tbl);
525}
526
527/*
528 * This function deletes all the entries in Tx BA Stream table.
529 */
530void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
531{
532 int i;
533 struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
534 unsigned long flags;
535
536 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
537 list_for_each_entry_safe(del_tbl_ptr, tmp_node,
538 &priv->tx_ba_stream_tbl_ptr, list)
539 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
540 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
541
542 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
543
544 for (i = 0; i < MAX_NUM_TID; ++i)
545 priv->aggr_prio_tbl[i].ampdu_ap =
546 priv->aggr_prio_tbl[i].ampdu_user;
547}
548
549/*
550 * This function returns the pointer to an entry in BA Stream
551 * table which matches the given RA/TID pair.
552 */
553struct mwifiex_tx_ba_stream_tbl *
554mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
555 int tid, u8 *ra)
556{
557 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
558 unsigned long flags;
559
560 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
561 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
562 if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
563 && (tx_ba_tsr_tbl->tid == tid)) {
564 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
565 flags);
566 return tx_ba_tsr_tbl;
567 }
568 }
569 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
570 return NULL;
571}
572
573/*
574 * This function creates an entry in Tx BA stream table for the
575 * given RA/TID pair.
576 */
577void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
578 u8 *ra, int tid,
579 enum mwifiex_ba_status ba_status)
580{
581 struct mwifiex_tx_ba_stream_tbl *new_node;
582 unsigned long flags;
583
584 if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
585 new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
586 GFP_ATOMIC);
587 if (!new_node) {
588 dev_err(priv->adapter->dev,
589 "%s: failed to alloc new_node\n", __func__);
590 return;
591 }
592
593 INIT_LIST_HEAD(&new_node->list);
594
595 new_node->tid = tid;
596 new_node->ba_status = ba_status;
597 memcpy(new_node->ra, ra, ETH_ALEN);
598
599 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
600 list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
601 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
602 }
603}
604
605/*
606 * This function sends an add BA request to the given TID/RA pair.
607 */
608int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
609{
610 struct host_cmd_ds_11n_addba_req add_ba_req;
611 static u8 dialog_tok;
612 int ret;
613
614 dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
615
616 add_ba_req.block_ack_param_set = cpu_to_le16(
617 (u16) ((tid << BLOCKACKPARAM_TID_POS) |
618 (priv->add_ba_param.
619 tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
620 IMMEDIATE_BLOCK_ACK));
621 add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
622
623 ++dialog_tok;
624
625 if (dialog_tok == 0)
626 dialog_tok = 1;
627
628 add_ba_req.dialog_token = dialog_tok;
629 memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
630
631 /* We don't wait for the response of this command */
632 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
633 0, 0, &add_ba_req);
634
635 return ret;
636}
637
638/*
639 * This function sends a delete BA request to the given TID/RA pair.
640 */
641int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
642 int initiator)
643{
644 struct host_cmd_ds_11n_delba delba;
645 int ret;
646 uint16_t del_ba_param_set;
647
648 memset(&delba, 0, sizeof(delba));
649 delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
650
651 del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
652 if (initiator)
653 del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
654 else
655 del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
656
657 memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
658
659 /* We don't wait for the response of this command */
660 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
661 HostCmd_ACT_GEN_SET, 0, &delba);
662
663 return ret;
664}
665
666/*
667 * This function handles the command response of a delete BA request.
668 */
669void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
670{
671 struct host_cmd_ds_11n_delba *cmd_del_ba =
672 (struct host_cmd_ds_11n_delba *) del_ba;
673 uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
674 int tid;
675
676 tid = del_ba_param_set >> DELBA_TID_POS;
677
678 mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
679 TYPE_DELBA_RECEIVE,
680 INITIATOR_BIT(del_ba_param_set));
681}
682
683/*
684 * This function retrieves the Rx reordering table.
685 */
686int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
687 struct mwifiex_ds_rx_reorder_tbl *buf)
688{
689 int i;
690 struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
691 struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
692 int count = 0;
693 unsigned long flags;
694
695 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
696 list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
697 list) {
698 rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
699 memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
700 rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
701 rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
702 for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
703 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
704 rx_reo_tbl->buffer[i] = true;
705 else
706 rx_reo_tbl->buffer[i] = false;
707 }
708 rx_reo_tbl++;
709 count++;
710
711 if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
712 break;
713 }
714 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
715
716 return count;
717}
718
719/*
720 * This function retrieves the Tx BA stream table.
721 */
722int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
723 struct mwifiex_ds_tx_ba_stream_tbl *buf)
724{
725 struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
726 struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
727 int count = 0;
728 unsigned long flags;
729
730 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
731 list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
732 rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
733 dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
734 __func__, rx_reo_tbl->tid);
735 memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
736 rx_reo_tbl++;
737 count++;
738 if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
739 break;
740 }
741 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
742
743 return count;
744}
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
new file mode 100644
index 000000000000..a4390a1a2a9f
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -0,0 +1,161 @@
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
27int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
28 struct host_cmd_ds_command *resp);
29int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
30 struct host_cmd_ds_command *resp);
31int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp,
32 void *data_buf);
33int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
34 u16 cmd_action, void *data_buf);
35
36int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
37 struct mwifiex_bssdescriptor *bss_desc,
38 u8 **buffer);
39void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
40 struct mwifiex_bssdescriptor *bss_desc);
41void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
42 struct mwifiex_ie_types_htcap *);
43int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
44 u16 action, int *htcap_cfg);
45void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
46 struct mwifiex_tx_ba_stream_tbl
47 *tx_tbl);
48void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv);
49struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct
50 mwifiex_private
51 *priv, int tid,
52 u8 *ra);
53void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra,
54 int tid,
55 enum mwifiex_ba_status ba_status);
56int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac);
57int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
58 int initiator);
59void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba);
60int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
61 struct mwifiex_ds_rx_reorder_tbl *buf);
62int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
63 struct mwifiex_ds_tx_ba_stream_tbl *buf);
64int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
65 void *data_buf);
66int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
67 struct host_cmd_ds_command *cmd,
68 int cmd_action, void *data_buf);
69int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
70 int cmd_action, void *data_buf);
71
72/*
73 * This function checks whether AMPDU is allowed or not for a particular TID.
74 */
75static inline u8
76mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid)
77{
78 return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
79 ? true : false);
80}
81
82/*
83 * This function checks whether AMSDU is allowed or not for a particular TID.
84 */
85static inline u8
86mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid)
87{
88 return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
89 && ((priv->is_data_rate_auto)
90 || !((priv->bitmap_rates[2]) & 0x03)))
91 ? true : false);
92}
93
94/*
95 * This function checks whether a space is available for new BA stream or not.
96 */
97static inline u8 mwifiex_space_avail_for_new_ba_stream(
98 struct mwifiex_adapter *adapter)
99{
100 struct mwifiex_private *priv;
101 u8 i;
102 u32 ba_stream_num = 0;
103
104 for (i = 0; i < adapter->priv_num; i++) {
105 priv = adapter->priv[i];
106 if (priv)
107 ba_stream_num += mwifiex_wmm_list_len(
108 (struct list_head *)
109 &priv->tx_ba_stream_tbl_ptr);
110 }
111
112 return ((ba_stream_num <
113 MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false);
114}
115
116/*
117 * This function finds the correct Tx BA stream to delete.
118 *
119 * Upon successfully locating, both the TID and the RA are returned.
120 */
121static inline u8
122mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid,
123 int *ptid, u8 *ra)
124{
125 int tid;
126 u8 ret = false;
127 struct mwifiex_tx_ba_stream_tbl *tx_tbl;
128 unsigned long flags;
129
130 tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
131
132 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
133 list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
134 if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) {
135 tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user;
136 *ptid = tx_tbl->tid;
137 memcpy(ra, tx_tbl->ra, ETH_ALEN);
138 ret = true;
139 }
140 }
141 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
142
143 return ret;
144}
145
146/*
147 * This function checks whether BA stream is set up or not.
148 */
149static inline int
150mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
151 struct mwifiex_ra_list_tbl *ptr, int tid)
152{
153 struct mwifiex_tx_ba_stream_tbl *tx_tbl;
154
155 tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra);
156 if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl))
157 return true;
158
159 return false;
160}
161#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..f807447e4d99
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -0,0 +1,302 @@
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 sk_buff *skb_aggr,
48 struct sk_buff *skb_src, int *pad)
49
50{
51 int dt_offset;
52 struct rfc_1042_hdr snap = {
53 0xaa, /* LLC DSAP */
54 0xaa, /* LLC SSAP */
55 0x03, /* LLC CTRL */
56 {0x00, 0x00, 0x00}, /* SNAP OUI */
57 0x0000 /* SNAP type */
58 /*
59 * This field will be overwritten
60 * later with ethertype
61 */
62 };
63 struct tx_packet_hdr *tx_header;
64
65 skb_put(skb_aggr, sizeof(*tx_header));
66
67 tx_header = (struct tx_packet_hdr *) skb_aggr->data;
68
69 /* Copy DA and SA */
70 dt_offset = 2 * ETH_ALEN;
71 memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset);
72
73 /* Copy SNAP header */
74 snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset);
75 dt_offset += sizeof(u16);
76
77 memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr));
78
79 skb_pull(skb_src, dt_offset);
80
81 /* Update Length field */
82 tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
83
84 /* Add payload */
85 skb_put(skb_aggr, skb_src->len);
86 memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
87 skb_src->len);
88 *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
89 LLC_SNAP_LEN)) & 3)) : 0;
90 skb_put(skb_aggr, *pad);
91
92 return skb_aggr->len + *pad;
93}
94
95/*
96 * Adds TxPD to AMSDU header.
97 *
98 * Each AMSDU packet will contain one TxPD at the beginning,
99 * followed by multiple AMSDU subframes.
100 */
101static void
102mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
103 struct sk_buff *skb)
104{
105 struct txpd *local_tx_pd;
106
107 skb_push(skb, sizeof(*local_tx_pd));
108
109 local_tx_pd = (struct txpd *) skb->data;
110 memset(local_tx_pd, 0, sizeof(struct txpd));
111
112 /* Original priority has been overwritten */
113 local_tx_pd->priority = (u8) skb->priority;
114 local_tx_pd->pkt_delay_2ms =
115 mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
116 local_tx_pd->bss_num = priv->bss_num;
117 local_tx_pd->bss_type = priv->bss_type;
118 /* Always zero as the data is followed by struct txpd */
119 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
120 local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
121 local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
122 sizeof(*local_tx_pd));
123
124 if (local_tx_pd->tx_control == 0)
125 /* TxCtrl set by user or default */
126 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
127
128 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
129 (priv->adapter->pps_uapsd_mode)) {
130 if (true == mwifiex_check_last_packet_indication(priv)) {
131 priv->adapter->tx_lock_flag = true;
132 local_tx_pd->flags =
133 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
134 }
135 }
136}
137
138/*
139 * Create aggregated packet.
140 *
141 * This function creates an aggregated MSDU packet, by combining buffers
142 * from the RA list. Each individual buffer is encapsulated as an AMSDU
143 * subframe and all such subframes are concatenated together to form the
144 * AMSDU packet.
145 *
146 * A TxPD is also added to the front of the resultant AMSDU packets for
147 * transmission. The resultant packets format is -
148 *
149 * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+
150 * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame|
151 * | | 1 | 2 | .. | n |
152 * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+
153 */
154int
155mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
156 struct mwifiex_ra_list_tbl *pra_list, int headroom,
157 int ptrindex, unsigned long ra_list_flags)
158 __releases(&priv->wmm.ra_list_spinlock)
159{
160 struct mwifiex_adapter *adapter = priv->adapter;
161 struct sk_buff *skb_aggr, *skb_src;
162 struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
163 int pad = 0, ret;
164 struct mwifiex_tx_param tx_param;
165 struct txpd *ptx_pd = NULL;
166
167 if (skb_queue_empty(&pra_list->skb_head)) {
168 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
169 ra_list_flags);
170 return 0;
171 }
172 skb_src = skb_peek(&pra_list->skb_head);
173 tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
174 skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
175 if (!skb_aggr) {
176 dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
177 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
178 ra_list_flags);
179 return -1;
180 }
181 skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
182 tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr);
183
184 tx_info_aggr->bss_index = tx_info_src->bss_index;
185 skb_aggr->priority = skb_src->priority;
186
187 while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len
188 + LLC_SNAP_LEN)
189 <= adapter->tx_buf_size)) {
190
191 if (!skb_queue_empty(&pra_list->skb_head))
192 skb_src = skb_dequeue(&pra_list->skb_head);
193 else
194 skb_src = NULL;
195
196 if (skb_src)
197 pra_list->total_pkts_size -= skb_src->len;
198
199 atomic_dec(&priv->wmm.tx_pkts_queued);
200
201 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
202 ra_list_flags);
203 mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
204
205 mwifiex_write_data_complete(adapter, skb_src, 0);
206
207 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
208
209 if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
210 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
211 ra_list_flags);
212 return -1;
213 }
214
215 if (!skb_queue_empty(&pra_list->skb_head))
216 skb_src = skb_peek(&pra_list->skb_head);
217 else
218 skb_src = NULL;
219 }
220
221 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
222
223 /* Last AMSDU packet does not need padding */
224 skb_trim(skb_aggr, skb_aggr->len - pad);
225
226 /* Form AMSDU */
227 mwifiex_11n_form_amsdu_txpd(priv, skb_aggr);
228 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
229 ptx_pd = (struct txpd *)skb_aggr->data;
230
231 skb_push(skb_aggr, headroom);
232
233 tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
234 (((pra_list->total_pkts_size) >
235 adapter->tx_buf_size) ? adapter->
236 tx_buf_size : pra_list->total_pkts_size +
237 LLC_SNAP_LEN + sizeof(struct txpd)) : 0);
238 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
239 skb_aggr->data,
240 skb_aggr->len, &tx_param);
241 switch (ret) {
242 case -EBUSY:
243 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
244 if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
245 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
246 ra_list_flags);
247 mwifiex_write_data_complete(adapter, skb_aggr, -1);
248 return -1;
249 }
250 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
251 (adapter->pps_uapsd_mode) &&
252 (adapter->tx_lock_flag)) {
253 priv->adapter->tx_lock_flag = false;
254 if (ptx_pd)
255 ptx_pd->flags = 0;
256 }
257
258 skb_queue_tail(&pra_list->skb_head, skb_aggr);
259
260 pra_list->total_pkts_size += skb_aggr->len;
261
262 atomic_inc(&priv->wmm.tx_pkts_queued);
263
264 tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
265 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
266 ra_list_flags);
267 dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
268 break;
269 case -1:
270 adapter->data_sent = false;
271 dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
272 __func__, ret);
273 adapter->dbg.num_tx_host_to_card_failure++;
274 mwifiex_write_data_complete(adapter, skb_aggr, ret);
275 return 0;
276 case -EINPROGRESS:
277 adapter->data_sent = false;
278 break;
279 case 0:
280 mwifiex_write_data_complete(adapter, skb_aggr, ret);
281 break;
282 default:
283 break;
284 }
285 if (ret != -EBUSY) {
286 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
287 if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
288 priv->wmm.packets_out[ptrindex]++;
289 priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
290 }
291 /* Now bss_prio_cur pointer points to next node */
292 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
293 list_first_entry(
294 &adapter->bss_prio_tbl[priv->bss_priority]
295 .bss_prio_cur->list,
296 struct mwifiex_bss_prio_node, list);
297 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
298 ra_list_flags);
299 }
300
301 return 0;
302}
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..e5dfdc39a921
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -0,0 +1,616 @@
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 dispatches all packets in the Rx reorder table.
31 *
32 * There could be holes in the buffer, which are skipped by the function.
33 * Since the buffer is linear, the function uses rotation to simulate
34 * circular buffer.
35 */
36static int
37mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
38 struct mwifiex_rx_reorder_tbl
39 *rx_reor_tbl_ptr, int start_win)
40{
41 int no_pkt_to_send, i;
42 void *rx_tmp_ptr;
43 unsigned long flags;
44
45 no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
46 min((start_win - rx_reor_tbl_ptr->start_win),
47 rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
48
49 for (i = 0; i < no_pkt_to_send; ++i) {
50 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
51 rx_tmp_ptr = NULL;
52 if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
53 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
54 rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
55 }
56 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
57 if (rx_tmp_ptr)
58 mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
59 }
60
61 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
62 /*
63 * We don't have a circular buffer, hence use rotation to simulate
64 * circular buffer
65 */
66 for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) {
67 rx_reor_tbl_ptr->rx_reorder_ptr[i] =
68 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
69 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
70 }
71
72 rx_reor_tbl_ptr->start_win = start_win;
73 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
74
75 return 0;
76}
77
78/*
79 * This function dispatches all packets in the Rx reorder table until
80 * a hole is found.
81 *
82 * The start window is adjusted automatically when a hole is located.
83 * Since the buffer is linear, the function uses rotation to simulate
84 * circular buffer.
85 */
86static int
87mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
88 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
89{
90 int i, j, xchg;
91 void *rx_tmp_ptr;
92 unsigned long flags;
93
94 for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
95 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
96 if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
97 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
98 break;
99 }
100 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
101 rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
102 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
103 mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
104 }
105
106 spin_lock_irqsave(&priv->rx_pkt_lock, flags);
107 /*
108 * We don't have a circular buffer, hence use rotation to simulate
109 * circular buffer
110 */
111 if (i > 0) {
112 xchg = rx_reor_tbl_ptr->win_size - i;
113 for (j = 0; j < xchg; ++j) {
114 rx_reor_tbl_ptr->rx_reorder_ptr[j] =
115 rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
116 rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
117 }
118 }
119 rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
120 &(MAX_TID_VALUE - 1);
121 spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
122 return 0;
123}
124
125/*
126 * This function deletes the Rx reorder table and frees the memory.
127 *
128 * The function stops the associated timer and dispatches all the
129 * pending packets in the Rx reorder table before deletion.
130 */
131static void
132mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
133 struct mwifiex_rx_reorder_tbl
134 *rx_reor_tbl_ptr)
135{
136 unsigned long flags;
137
138 if (!rx_reor_tbl_ptr)
139 return;
140
141 mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
142 (rx_reor_tbl_ptr->start_win +
143 rx_reor_tbl_ptr->win_size)
144 &(MAX_TID_VALUE - 1));
145
146 del_timer(&rx_reor_tbl_ptr->timer_context.timer);
147
148 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
149 list_del(&rx_reor_tbl_ptr->list);
150 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
151
152 kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
153 kfree(rx_reor_tbl_ptr);
154}
155
156/*
157 * This function returns the pointer to an entry in Rx reordering
158 * table which matches the given TA/TID pair.
159 */
160static struct mwifiex_rx_reorder_tbl *
161mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
162{
163 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
164 unsigned long flags;
165
166 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
167 list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
168 if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
169 && (rx_reor_tbl_ptr->tid == tid)) {
170 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
171 flags);
172 return rx_reor_tbl_ptr;
173 }
174 }
175 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
176
177 return NULL;
178}
179
180/*
181 * This function finds the last sequence number used in the packets
182 * buffered in Rx reordering table.
183 */
184static int
185mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
186{
187 int i;
188
189 for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
190 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
191 return i;
192
193 return -1;
194}
195
196/*
197 * This function flushes all the packets in Rx reordering table.
198 *
199 * The function checks if any packets are currently buffered in the
200 * table or not. In case there are packets available, it dispatches
201 * them and then dumps the Rx reordering table.
202 */
203static void
204mwifiex_flush_data(unsigned long context)
205{
206 struct reorder_tmr_cnxt *reorder_cnxt =
207 (struct reorder_tmr_cnxt *) context;
208 int start_win;
209
210 start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
211 if (start_win >= 0) {
212 dev_dbg(reorder_cnxt->priv->adapter->dev,
213 "info: flush data %d\n", start_win);
214 mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
215 reorder_cnxt->ptr,
216 ((reorder_cnxt->ptr->start_win +
217 start_win + 1) & (MAX_TID_VALUE - 1)));
218 }
219}
220
221/*
222 * This function creates an entry in Rx reordering table for the
223 * given TA/TID.
224 *
225 * The function also initializes the entry with sequence number, window
226 * size as well as initializes the timer.
227 *
228 * If the received TA/TID pair is already present, all the packets are
229 * dispatched and the window size is moved until the SSN.
230 */
231static void
232mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
233 int tid, int win_size, int seq_num)
234{
235 int i;
236 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
237 u16 last_seq = 0;
238 unsigned long flags;
239
240 /*
241 * If we get a TID, ta pair which is already present dispatch all the
242 * the packets and move the window size until the ssn
243 */
244 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
245 if (rx_reor_tbl_ptr) {
246 mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
247 seq_num);
248 return;
249 }
250 /* if !rx_reor_tbl_ptr then create one */
251 new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
252 if (!new_node) {
253 dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
254 __func__);
255 return;
256 }
257
258 INIT_LIST_HEAD(&new_node->list);
259 new_node->tid = tid;
260 memcpy(new_node->ta, ta, ETH_ALEN);
261 new_node->start_win = seq_num;
262 if (mwifiex_queuing_ra_based(priv))
263 /* TODO for adhoc */
264 dev_dbg(priv->adapter->dev,
265 "info: ADHOC:last_seq=%d start_win=%d\n",
266 last_seq, new_node->start_win);
267 else
268 last_seq = priv->rx_seq[tid];
269
270 if (last_seq >= new_node->start_win)
271 new_node->start_win = last_seq + 1;
272
273 new_node->win_size = win_size;
274
275 new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
276 GFP_KERNEL);
277 if (!new_node->rx_reorder_ptr) {
278 kfree((u8 *) new_node);
279 dev_err(priv->adapter->dev,
280 "%s: failed to alloc reorder_ptr\n", __func__);
281 return;
282 }
283
284 new_node->timer_context.ptr = new_node;
285 new_node->timer_context.priv = priv;
286
287 init_timer(&new_node->timer_context.timer);
288 new_node->timer_context.timer.function = mwifiex_flush_data;
289 new_node->timer_context.timer.data =
290 (unsigned long) &new_node->timer_context;
291
292 for (i = 0; i < win_size; ++i)
293 new_node->rx_reorder_ptr[i] = NULL;
294
295 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
296 list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
297 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
298}
299
300/*
301 * This function prepares command for adding a BA request.
302 *
303 * Preparation includes -
304 * - Setting command ID and proper size
305 * - Setting add BA request buffer
306 * - Ensuring correct endian-ness
307 */
308int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
309{
310 struct host_cmd_ds_11n_addba_req *add_ba_req =
311 (struct host_cmd_ds_11n_addba_req *)
312 &cmd->params.add_ba_req;
313
314 cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
315 cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
316 memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
317
318 return 0;
319}
320
321/*
322 * This function prepares command for adding a BA response.
323 *
324 * Preparation includes -
325 * - Setting command ID and proper size
326 * - Setting add BA response buffer
327 * - Ensuring correct endian-ness
328 */
329int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
330 struct host_cmd_ds_command *cmd,
331 void *data_buf)
332{
333 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
334 (struct host_cmd_ds_11n_addba_rsp *)
335 &cmd->params.add_ba_rsp;
336 struct host_cmd_ds_11n_addba_req *cmd_addba_req =
337 (struct host_cmd_ds_11n_addba_req *) data_buf;
338 u8 tid;
339 int win_size;
340 uint16_t block_ack_param_set;
341
342 cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
343 cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
344
345 memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
346 ETH_ALEN);
347 add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
348 add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
349 add_ba_rsp->ssn = cmd_addba_req->ssn;
350
351 block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
352 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
353 >> BLOCKACKPARAM_TID_POS;
354 add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
355 block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
356 /* We donot support AMSDU inside AMPDU, hence reset the bit */
357 block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
358 block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
359 BLOCKACKPARAM_WINSIZE_POS);
360 add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
361 win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
362 & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
363 >> BLOCKACKPARAM_WINSIZE_POS;
364 cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
365
366 mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
367 tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
368 return 0;
369}
370
371/*
372 * This function prepares command for deleting a BA request.
373 *
374 * Preparation includes -
375 * - Setting command ID and proper size
376 * - Setting del BA request buffer
377 * - Ensuring correct endian-ness
378 */
379int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
380{
381 struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
382 &cmd->params.del_ba;
383
384 cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
385 cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
386 memcpy(del_ba, data_buf, sizeof(*del_ba));
387
388 return 0;
389}
390
391/*
392 * This function identifies if Rx reordering is needed for a received packet.
393 *
394 * In case reordering is required, the function will do the reordering
395 * before sending it to kernel.
396 *
397 * The Rx reorder table is checked first with the received TID/TA pair. If
398 * not found, the received packet is dispatched immediately. But if found,
399 * the packet is reordered and all the packets in the updated Rx reordering
400 * table is dispatched until a hole is found.
401 *
402 * For sequence number less than the starting window, the packet is dropped.
403 */
404int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
405 u16 seq_num, u16 tid,
406 u8 *ta, u8 pkt_type, void *payload)
407{
408 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
409 int start_win, end_win, win_size, ret;
410 u16 pkt_index;
411
412 rx_reor_tbl_ptr =
413 mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
414 tid, ta);
415 if (!rx_reor_tbl_ptr) {
416 if (pkt_type != PKT_TYPE_BAR)
417 mwifiex_process_rx_packet(priv->adapter, payload);
418 return 0;
419 }
420 start_win = rx_reor_tbl_ptr->start_win;
421 win_size = rx_reor_tbl_ptr->win_size;
422 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
423 del_timer(&rx_reor_tbl_ptr->timer_context.timer);
424 mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
425 + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
426
427 /*
428 * If seq_num is less then starting win then ignore and drop the
429 * packet
430 */
431 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
432 if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
433 && (seq_num < start_win))
434 return -1;
435 } else if ((seq_num < start_win)
436 || (seq_num > (start_win + (TWOPOW11)))) {
437 return -1;
438 }
439
440 /*
441 * If this packet is a BAR we adjust seq_num as
442 * WinStart = seq_num
443 */
444 if (pkt_type == PKT_TYPE_BAR)
445 seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
446
447 if (((end_win < start_win)
448 && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
449 && (seq_num > end_win)) || ((end_win > start_win)
450 && ((seq_num > end_win) || (seq_num < start_win)))) {
451 end_win = seq_num;
452 if (((seq_num - win_size) + 1) >= 0)
453 start_win = (end_win - win_size) + 1;
454 else
455 start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
456 ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
457 rx_reor_tbl_ptr, start_win);
458
459 if (ret)
460 return ret;
461 }
462
463 if (pkt_type != PKT_TYPE_BAR) {
464 if (seq_num >= start_win)
465 pkt_index = seq_num - start_win;
466 else
467 pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
468
469 if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
470 return -1;
471
472 rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
473 }
474
475 /*
476 * Dispatch all packets sequentially from start_win until a
477 * hole is found and adjust the start_win appropriately
478 */
479 ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
480
481 return ret;
482}
483
484/*
485 * This function deletes an entry for a given TID/TA pair.
486 *
487 * The TID/TA are taken from del BA event body.
488 */
489void
490mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid,
491 u8 *peer_mac, u8 type, int initiator)
492{
493 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
494 struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
495 u8 cleanup_rx_reorder_tbl;
496 unsigned long flags;
497
498 if (type == TYPE_DELBA_RECEIVE)
499 cleanup_rx_reorder_tbl = (initiator) ? true : false;
500 else
501 cleanup_rx_reorder_tbl = (initiator) ? false : true;
502
503 dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
504 "initiator=%d\n", peer_mac, tid, initiator);
505
506 if (cleanup_rx_reorder_tbl) {
507 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
508 peer_mac);
509 if (!rx_reor_tbl_ptr) {
510 dev_dbg(priv->adapter->dev,
511 "event: TID, TA not found in table\n");
512 return;
513 }
514 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
515 } else {
516 ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac);
517 if (!ptx_tbl) {
518 dev_dbg(priv->adapter->dev,
519 "event: TID, RA not found in table\n");
520 return;
521 }
522
523 spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
524 mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
525 spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
526 }
527}
528
529/*
530 * This function handles the command response of an add BA response.
531 *
532 * Handling includes changing the header fields into CPU format and
533 * creating the stream, provided the add BA is accepted.
534 */
535int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
536 struct host_cmd_ds_command *resp)
537{
538 struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
539 (struct host_cmd_ds_11n_addba_rsp *)
540 &resp->params.add_ba_rsp;
541 int tid, win_size;
542 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
543 uint16_t block_ack_param_set;
544
545 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
546
547 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
548 >> BLOCKACKPARAM_TID_POS;
549 /*
550 * Check if we had rejected the ADDBA, if yes then do not create
551 * the stream
552 */
553 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
554 win_size = (block_ack_param_set &
555 IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
556 >> BLOCKACKPARAM_WINSIZE_POS;
557
558 dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM"
559 " tid=%d ssn=%d win_size=%d\n",
560 add_ba_rsp->peer_mac_addr,
561 tid, add_ba_rsp->ssn, win_size);
562 } else {
563 dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
564 add_ba_rsp->peer_mac_addr, tid);
565
566 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv,
567 tid, add_ba_rsp->peer_mac_addr);
568 if (rx_reor_tbl_ptr)
569 mwifiex_11n_delete_rx_reorder_tbl_entry(priv,
570 rx_reor_tbl_ptr);
571 }
572
573 return 0;
574}
575
576/*
577 * This function handles BA stream timeout event by preparing and sending
578 * a command to the firmware.
579 */
580void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
581 struct host_cmd_ds_11n_batimeout *event)
582{
583 struct host_cmd_ds_11n_delba delba;
584
585 memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
586 memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
587
588 delba.del_ba_param_set |=
589 cpu_to_le16((u16) event->tid << DELBA_TID_POS);
590 delba.del_ba_param_set |= cpu_to_le16(
591 (u16) event->origninator << DELBA_INITIATOR_POS);
592 delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
593 mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba);
594}
595
596/*
597 * This function cleans up the Rx reorder table by deleting all the entries
598 * and re-initializing.
599 */
600void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
601{
602 struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
603 unsigned long flags;
604
605 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
606 list_for_each_entry_safe(del_tbl_ptr, tmp_node,
607 &priv->rx_reorder_tbl_ptr, list) {
608 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
609 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr);
610 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
611 }
612 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
613
614 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
615 memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
616}
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
new file mode 100644
index 000000000000..f3ca8c8c18f9
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -0,0 +1,65 @@
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 host_cmd_ds_command *cmd,
53 void *data_buf);
54int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
55 struct host_cmd_ds_command
56 *cmd, void *data_buf);
57int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd,
58 void *data_buf);
59void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv);
60struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
61 mwifiex_private
62 *priv, int tid,
63 u8 *ta);
64
65#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..b55badef4660
--- /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 cmd_pending = <number of cmd 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..687c1f223497
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -0,0 +1,1419 @@
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 switch (channel_type) {
38 case NL80211_CHAN_NO_HT:
39 case NL80211_CHAN_HT20:
40 return NO_SEC_CHANNEL;
41 case NL80211_CHAN_HT40PLUS:
42 return SEC_CHANNEL_ABOVE;
43 case NL80211_CHAN_HT40MINUS:
44 return SEC_CHANNEL_BELOW;
45 default:
46 return NO_SEC_CHANNEL;
47 }
48}
49
50/*
51 * This function maps the driver channel type into nl802.11 channel type.
52 *
53 * The mapping is as follows -
54 * NO_SEC_CHANNEL -> NL80211_CHAN_HT20
55 * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS
56 * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS
57 * Others -> NL80211_CHAN_HT20
58 */
59static enum nl80211_channel_type
60mwifiex_channels_to_cfg80211_channel_type(int channel_type)
61{
62 switch (channel_type) {
63 case NO_SEC_CHANNEL:
64 return NL80211_CHAN_HT20;
65 case SEC_CHANNEL_ABOVE:
66 return NL80211_CHAN_HT40PLUS;
67 case SEC_CHANNEL_BELOW:
68 return NL80211_CHAN_HT40MINUS;
69 default:
70 return NL80211_CHAN_HT20;
71 }
72}
73
74/*
75 * This function checks whether WEP is set.
76 */
77static int
78mwifiex_is_alg_wep(u32 cipher)
79{
80 switch (cipher) {
81 case WLAN_CIPHER_SUITE_WEP40:
82 case WLAN_CIPHER_SUITE_WEP104:
83 return 1;
84 default:
85 break;
86 }
87
88 return 0;
89}
90
91/*
92 * This function retrieves the private structure from kernel wiphy structure.
93 */
94static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
95{
96 return (void *) (*(unsigned long *) wiphy_priv(wiphy));
97}
98
99/*
100 * CFG802.11 operation handler to delete a network key.
101 */
102static int
103mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
104 u8 key_index, bool pairwise, const u8 *mac_addr)
105{
106 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
107
108 if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) {
109 wiphy_err(wiphy, "deleting the crypto keys\n");
110 return -EFAULT;
111 }
112
113 wiphy_dbg(wiphy, "info: crypto keys deleted\n");
114 return 0;
115}
116
117/*
118 * CFG802.11 operation handler to set Tx power.
119 */
120static int
121mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
122 enum nl80211_tx_power_setting type,
123 int dbm)
124{
125 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
126 struct mwifiex_power_cfg power_cfg;
127
128 if (type == NL80211_TX_POWER_FIXED) {
129 power_cfg.is_power_auto = 0;
130 power_cfg.power_level = dbm;
131 } else {
132 power_cfg.is_power_auto = 1;
133 }
134
135 return mwifiex_set_tx_power(priv, &power_cfg);
136}
137
138/*
139 * CFG802.11 operation handler to set Power Save option.
140 *
141 * The timeout value, if provided, is currently ignored.
142 */
143static int
144mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
145 struct net_device *dev,
146 bool enabled, int timeout)
147{
148 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
149 u32 ps_mode;
150
151 if (timeout)
152 wiphy_dbg(wiphy,
153 "info: ignoring the timeout value"
154 " for IEEE power save\n");
155
156 ps_mode = enabled;
157
158 return mwifiex_drv_set_power(priv, &ps_mode);
159}
160
161/*
162 * CFG802.11 operation handler to set the default network key.
163 */
164static int
165mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
166 u8 key_index, bool unicast,
167 bool multicast)
168{
169 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
170
171 /* Return if WEP key not configured */
172 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED)
173 return 0;
174
175 if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
176 wiphy_err(wiphy, "set default Tx key index\n");
177 return -EFAULT;
178 }
179
180 return 0;
181}
182
183/*
184 * CFG802.11 operation handler to add a network key.
185 */
186static int
187mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
188 u8 key_index, bool pairwise, const u8 *mac_addr,
189 struct key_params *params)
190{
191 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
192
193 if (mwifiex_set_encode(priv, params->key, params->key_len,
194 key_index, 0)) {
195 wiphy_err(wiphy, "crypto keys added\n");
196 return -EFAULT;
197 }
198
199 return 0;
200}
201
202/*
203 * This function sends domain information to the firmware.
204 *
205 * The following information are passed to the firmware -
206 * - Country codes
207 * - Sub bands (first channel, number of channels, maximum Tx power)
208 */
209static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
210{
211 u8 no_of_triplet = 0;
212 struct ieee80211_country_ie_triplet *t;
213 u8 no_of_parsed_chan = 0;
214 u8 first_chan = 0, next_chan = 0, max_pwr = 0;
215 u8 i, flag = 0;
216 enum ieee80211_band band;
217 struct ieee80211_supported_band *sband;
218 struct ieee80211_channel *ch;
219 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
220 struct mwifiex_adapter *adapter = priv->adapter;
221 struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
222
223 /* Set country code */
224 domain_info->country_code[0] = priv->country_code[0];
225 domain_info->country_code[1] = priv->country_code[1];
226 domain_info->country_code[2] = ' ';
227
228 band = mwifiex_band_to_radio_type(adapter->config_bands);
229 if (!wiphy->bands[band]) {
230 wiphy_err(wiphy, "11D: setting domain info in FW\n");
231 return -1;
232 }
233
234 sband = wiphy->bands[band];
235
236 for (i = 0; i < sband->n_channels ; i++) {
237 ch = &sband->channels[i];
238 if (ch->flags & IEEE80211_CHAN_DISABLED)
239 continue;
240
241 if (!flag) {
242 flag = 1;
243 first_chan = (u32) ch->hw_value;
244 next_chan = first_chan;
245 max_pwr = ch->max_power;
246 no_of_parsed_chan = 1;
247 continue;
248 }
249
250 if (ch->hw_value == next_chan + 1 &&
251 ch->max_power == max_pwr) {
252 next_chan++;
253 no_of_parsed_chan++;
254 } else {
255 t = &domain_info->triplet[no_of_triplet];
256 t->chans.first_channel = first_chan;
257 t->chans.num_channels = no_of_parsed_chan;
258 t->chans.max_power = max_pwr;
259 no_of_triplet++;
260 first_chan = (u32) ch->hw_value;
261 next_chan = first_chan;
262 max_pwr = ch->max_power;
263 no_of_parsed_chan = 1;
264 }
265 }
266
267 if (flag) {
268 t = &domain_info->triplet[no_of_triplet];
269 t->chans.first_channel = first_chan;
270 t->chans.num_channels = no_of_parsed_chan;
271 t->chans.max_power = max_pwr;
272 no_of_triplet++;
273 }
274
275 domain_info->no_of_triplet = no_of_triplet;
276
277 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
278 HostCmd_ACT_GEN_SET, 0, NULL)) {
279 wiphy_err(wiphy, "11D: setting domain info in FW\n");
280 return -1;
281 }
282
283 return 0;
284}
285
286/*
287 * CFG802.11 regulatory domain callback function.
288 *
289 * This function is called when the regulatory domain is changed due to the
290 * following reasons -
291 * - Set by driver
292 * - Set by system core
293 * - Set by user
294 * - Set bt Country IE
295 */
296static int mwifiex_reg_notifier(struct wiphy *wiphy,
297 struct regulatory_request *request)
298{
299 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
300
301 wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
302 " %c%c\n", request->alpha2[0], request->alpha2[1]);
303
304 memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
305
306 switch (request->initiator) {
307 case NL80211_REGDOM_SET_BY_DRIVER:
308 case NL80211_REGDOM_SET_BY_CORE:
309 case NL80211_REGDOM_SET_BY_USER:
310 break;
311 /* Todo: apply driver specific changes in channel flags based
312 on the request initiator if necessary. */
313 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
314 break;
315 }
316 mwifiex_send_domain_info_cmd_fw(wiphy);
317
318 return 0;
319}
320
321/*
322 * This function sets the RF channel.
323 *
324 * This function creates multiple IOCTL requests, populates them accordingly
325 * and issues them to set the band/channel and frequency.
326 */
327static int
328mwifiex_set_rf_channel(struct mwifiex_private *priv,
329 struct ieee80211_channel *chan,
330 enum nl80211_channel_type channel_type)
331{
332 struct mwifiex_chan_freq_power cfp;
333 struct mwifiex_ds_band_cfg band_cfg;
334 u32 config_bands = 0;
335 struct wiphy *wiphy = priv->wdev->wiphy;
336
337 if (chan) {
338 memset(&band_cfg, 0, sizeof(band_cfg));
339 /* Set appropriate bands */
340 if (chan->band == IEEE80211_BAND_2GHZ)
341 config_bands = BAND_B | BAND_G | BAND_GN;
342 else
343 config_bands = BAND_AN | BAND_A;
344 if (priv->bss_mode == NL80211_IFTYPE_STATION
345 || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) {
346 band_cfg.config_bands = config_bands;
347 } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
348 band_cfg.config_bands = config_bands;
349 band_cfg.adhoc_start_band = config_bands;
350 }
351
352 band_cfg.sec_chan_offset =
353 mwifiex_cfg80211_channel_type_to_mwifiex_channels
354 (channel_type);
355
356 if (mwifiex_set_radio_band_cfg(priv, &band_cfg))
357 return -EFAULT;
358
359 mwifiex_send_domain_info_cmd_fw(wiphy);
360 }
361
362 wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and "
363 "mode %d\n", config_bands, band_cfg.sec_chan_offset,
364 priv->bss_mode);
365 if (!chan)
366 return 0;
367
368 memset(&cfp, 0, sizeof(cfp));
369 cfp.freq = chan->center_freq;
370 cfp.channel = ieee80211_frequency_to_channel(chan->center_freq);
371
372 if (mwifiex_bss_set_channel(priv, &cfp))
373 return -EFAULT;
374
375 return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
376}
377
378/*
379 * CFG802.11 operation handler to set channel.
380 *
381 * This function can only be used when station is not connected.
382 */
383static int
384mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
385 struct ieee80211_channel *chan,
386 enum nl80211_channel_type channel_type)
387{
388 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
389
390 if (priv->media_connected) {
391 wiphy_err(wiphy, "This setting is valid only when station "
392 "is not connected\n");
393 return -EINVAL;
394 }
395
396 return mwifiex_set_rf_channel(priv, chan, channel_type);
397}
398
399/*
400 * This function sets the fragmentation threshold.
401 *
402 * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE
403 * and MWIFIEX_FRAG_MAX_VALUE.
404 */
405static int
406mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
407{
408 int ret;
409
410 if (frag_thr < MWIFIEX_FRAG_MIN_VALUE
411 || frag_thr > MWIFIEX_FRAG_MAX_VALUE)
412 return -EINVAL;
413
414 /* Send request to firmware */
415 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
416 HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
417 &frag_thr);
418
419 return ret;
420}
421
422/*
423 * This function sets the RTS threshold.
424
425 * The rts value must lie between MWIFIEX_RTS_MIN_VALUE
426 * and MWIFIEX_RTS_MAX_VALUE.
427 */
428static int
429mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
430{
431 if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
432 rts_thr = MWIFIEX_RTS_MAX_VALUE;
433
434 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
435 HostCmd_ACT_GEN_SET, RTS_THRESH_I,
436 &rts_thr);
437}
438
439/*
440 * CFG802.11 operation handler to set wiphy parameters.
441 *
442 * This function can be used to set the RTS threshold and the
443 * Fragmentation threshold of the driver.
444 */
445static int
446mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
447{
448 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
449 int ret = 0;
450
451 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
452 ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
453 if (ret)
454 return ret;
455 }
456
457 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
458 ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
459
460 return ret;
461}
462
463/*
464 * CFG802.11 operation handler to change interface type.
465 */
466static int
467mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
468 struct net_device *dev,
469 enum nl80211_iftype type, u32 *flags,
470 struct vif_params *params)
471{
472 int ret;
473 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
474
475 if (priv->bss_mode == type) {
476 wiphy_warn(wiphy, "already set to required type\n");
477 return 0;
478 }
479
480 priv->bss_mode = type;
481
482 switch (type) {
483 case NL80211_IFTYPE_ADHOC:
484 dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
485 wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
486 break;
487 case NL80211_IFTYPE_STATION:
488 dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
489 wiphy_dbg(wiphy, "info: setting interface type to managed\n");
490 break;
491 case NL80211_IFTYPE_UNSPECIFIED:
492 dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
493 wiphy_dbg(wiphy, "info: setting interface type to auto\n");
494 return 0;
495 default:
496 wiphy_err(wiphy, "unknown interface type: %d\n", type);
497 return -EINVAL;
498 }
499
500 mwifiex_deauthenticate(priv, NULL);
501
502 priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
503
504 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
505 HostCmd_ACT_GEN_SET, 0, NULL);
506
507 return ret;
508}
509
510/*
511 * This function dumps the station information on a buffer.
512 *
513 * The following information are shown -
514 * - Total bytes transmitted
515 * - Total bytes received
516 * - Total packets transmitted
517 * - Total packets received
518 * - Signal quality level
519 * - Transmission rate
520 */
521static int
522mwifiex_dump_station_info(struct mwifiex_private *priv,
523 struct station_info *sinfo)
524{
525 struct mwifiex_ds_get_signal signal;
526 struct mwifiex_rate_cfg rate;
527 int ret = 0;
528
529 sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
530 STATION_INFO_RX_PACKETS |
531 STATION_INFO_TX_PACKETS
532 | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
533
534 /* Get signal information from the firmware */
535 memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal));
536 if (mwifiex_get_signal_info(priv, &signal)) {
537 dev_err(priv->adapter->dev, "getting signal information\n");
538 ret = -EFAULT;
539 }
540
541 if (mwifiex_drv_get_data_rate(priv, &rate)) {
542 dev_err(priv->adapter->dev, "getting data rate\n");
543 ret = -EFAULT;
544 }
545
546 sinfo->rx_bytes = priv->stats.rx_bytes;
547 sinfo->tx_bytes = priv->stats.tx_bytes;
548 sinfo->rx_packets = priv->stats.rx_packets;
549 sinfo->tx_packets = priv->stats.tx_packets;
550 sinfo->signal = priv->w_stats.qual.level;
551 sinfo->txrate.legacy = rate.rate;
552
553 return ret;
554}
555
556/*
557 * CFG802.11 operation handler to get station information.
558 *
559 * This function only works in connected mode, and dumps the
560 * requested station information, if available.
561 */
562static int
563mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
564 u8 *mac, struct station_info *sinfo)
565{
566 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
567
568 mwifiex_dump_station_info(priv, sinfo);
569
570 if (!priv->media_connected)
571 return -ENOENT;
572 if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
573 return -ENOENT;
574
575 return mwifiex_dump_station_info(priv, sinfo);
576}
577
578/* Supported rates to be advertised to the cfg80211 */
579
580static struct ieee80211_rate mwifiex_rates[] = {
581 {.bitrate = 10, .hw_value = 2, },
582 {.bitrate = 20, .hw_value = 4, },
583 {.bitrate = 55, .hw_value = 11, },
584 {.bitrate = 110, .hw_value = 22, },
585 {.bitrate = 220, .hw_value = 44, },
586 {.bitrate = 60, .hw_value = 12, },
587 {.bitrate = 90, .hw_value = 18, },
588 {.bitrate = 120, .hw_value = 24, },
589 {.bitrate = 180, .hw_value = 36, },
590 {.bitrate = 240, .hw_value = 48, },
591 {.bitrate = 360, .hw_value = 72, },
592 {.bitrate = 480, .hw_value = 96, },
593 {.bitrate = 540, .hw_value = 108, },
594 {.bitrate = 720, .hw_value = 144, },
595};
596
597/* Channel definitions to be advertised to cfg80211 */
598
599static struct ieee80211_channel mwifiex_channels_2ghz[] = {
600 {.center_freq = 2412, .hw_value = 1, },
601 {.center_freq = 2417, .hw_value = 2, },
602 {.center_freq = 2422, .hw_value = 3, },
603 {.center_freq = 2427, .hw_value = 4, },
604 {.center_freq = 2432, .hw_value = 5, },
605 {.center_freq = 2437, .hw_value = 6, },
606 {.center_freq = 2442, .hw_value = 7, },
607 {.center_freq = 2447, .hw_value = 8, },
608 {.center_freq = 2452, .hw_value = 9, },
609 {.center_freq = 2457, .hw_value = 10, },
610 {.center_freq = 2462, .hw_value = 11, },
611 {.center_freq = 2467, .hw_value = 12, },
612 {.center_freq = 2472, .hw_value = 13, },
613 {.center_freq = 2484, .hw_value = 14, },
614};
615
616static struct ieee80211_supported_band mwifiex_band_2ghz = {
617 .channels = mwifiex_channels_2ghz,
618 .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz),
619 .bitrates = mwifiex_rates,
620 .n_bitrates = 14,
621};
622
623static struct ieee80211_channel mwifiex_channels_5ghz[] = {
624 {.center_freq = 5040, .hw_value = 8, },
625 {.center_freq = 5060, .hw_value = 12, },
626 {.center_freq = 5080, .hw_value = 16, },
627 {.center_freq = 5170, .hw_value = 34, },
628 {.center_freq = 5190, .hw_value = 38, },
629 {.center_freq = 5210, .hw_value = 42, },
630 {.center_freq = 5230, .hw_value = 46, },
631 {.center_freq = 5180, .hw_value = 36, },
632 {.center_freq = 5200, .hw_value = 40, },
633 {.center_freq = 5220, .hw_value = 44, },
634 {.center_freq = 5240, .hw_value = 48, },
635 {.center_freq = 5260, .hw_value = 52, },
636 {.center_freq = 5280, .hw_value = 56, },
637 {.center_freq = 5300, .hw_value = 60, },
638 {.center_freq = 5320, .hw_value = 64, },
639 {.center_freq = 5500, .hw_value = 100, },
640 {.center_freq = 5520, .hw_value = 104, },
641 {.center_freq = 5540, .hw_value = 108, },
642 {.center_freq = 5560, .hw_value = 112, },
643 {.center_freq = 5580, .hw_value = 116, },
644 {.center_freq = 5600, .hw_value = 120, },
645 {.center_freq = 5620, .hw_value = 124, },
646 {.center_freq = 5640, .hw_value = 128, },
647 {.center_freq = 5660, .hw_value = 132, },
648 {.center_freq = 5680, .hw_value = 136, },
649 {.center_freq = 5700, .hw_value = 140, },
650 {.center_freq = 5745, .hw_value = 149, },
651 {.center_freq = 5765, .hw_value = 153, },
652 {.center_freq = 5785, .hw_value = 157, },
653 {.center_freq = 5805, .hw_value = 161, },
654 {.center_freq = 5825, .hw_value = 165, },
655};
656
657static struct ieee80211_supported_band mwifiex_band_5ghz = {
658 .channels = mwifiex_channels_5ghz,
659 .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz),
660 .bitrates = mwifiex_rates - 4,
661 .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4,
662};
663
664
665/* Supported crypto cipher suits to be advertised to cfg80211 */
666
667static const u32 mwifiex_cipher_suites[] = {
668 WLAN_CIPHER_SUITE_WEP40,
669 WLAN_CIPHER_SUITE_WEP104,
670 WLAN_CIPHER_SUITE_TKIP,
671 WLAN_CIPHER_SUITE_CCMP,
672};
673
674/*
675 * CFG802.11 operation handler for disconnection request.
676 *
677 * This function does not work when there is already a disconnection
678 * procedure going on.
679 */
680static int
681mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
682 u16 reason_code)
683{
684 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
685
686 if (priv->disconnect)
687 return -EBUSY;
688
689 priv->disconnect = 1;
690 if (mwifiex_deauthenticate(priv, NULL))
691 return -EFAULT;
692
693 wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
694 " reason code %d\n", priv->cfg_bssid, reason_code);
695
696 queue_work(priv->workqueue, &priv->cfg_workqueue);
697
698 return 0;
699}
700
701/*
702 * This function informs the CFG802.11 subsystem of a new IBSS.
703 *
704 * The following information are sent to the CFG802.11 subsystem
705 * to register the new IBSS. If we do not register the new IBSS,
706 * a kernel panic will result.
707 * - SSID
708 * - SSID length
709 * - BSSID
710 * - Channel
711 */
712static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
713{
714 struct ieee80211_channel *chan;
715 struct mwifiex_bss_info bss_info;
716 int ie_len;
717 u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
718
719 if (mwifiex_get_bss_info(priv, &bss_info))
720 return -1;
721
722 ie_buf[0] = WLAN_EID_SSID;
723 ie_buf[1] = bss_info.ssid.ssid_len;
724
725 memcpy(&ie_buf[sizeof(struct ieee_types_header)],
726 &bss_info.ssid.ssid,
727 bss_info.ssid.ssid_len);
728 ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
729
730 chan = __ieee80211_get_channel(priv->wdev->wiphy,
731 ieee80211_channel_to_frequency(bss_info.bss_chan,
732 priv->curr_bss_params.band));
733
734 cfg80211_inform_bss(priv->wdev->wiphy, chan,
735 bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
736 0, ie_buf, ie_len, 0, GFP_KERNEL);
737 memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
738
739 return 0;
740}
741
742/*
743 * This function informs the CFG802.11 subsystem of a new BSS connection.
744 *
745 * The following information are sent to the CFG802.11 subsystem
746 * to register the new BSS connection. If we do not register the new BSS,
747 * a kernel panic will result.
748 * - MAC address
749 * - Capabilities
750 * - Beacon period
751 * - RSSI value
752 * - Channel
753 * - Supported rates IE
754 * - Extended capabilities IE
755 * - DS parameter set IE
756 * - HT Capability IE
757 * - Vendor Specific IE (221)
758 * - WPA IE
759 * - RSN IE
760 */
761static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
762 struct mwifiex_802_11_ssid *ssid)
763{
764 struct mwifiex_bssdescriptor *scan_table;
765 int i, j;
766 struct ieee80211_channel *chan;
767 u8 *ie, *ie_buf;
768 u32 ie_len;
769 u8 *beacon;
770 int beacon_size;
771 u8 element_id, element_len;
772
773#define MAX_IE_BUF 2048
774 ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
775 if (!ie_buf) {
776 dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n",
777 __func__);
778 return -ENOMEM;
779 }
780
781 scan_table = priv->adapter->scan_table;
782 for (i = 0; i < priv->adapter->num_in_scan_table; i++) {
783 if (ssid) {
784 /* Inform specific BSS only */
785 if (memcmp(ssid->ssid, scan_table[i].ssid.ssid,
786 ssid->ssid_len))
787 continue;
788 }
789 memset(ie_buf, 0, MAX_IE_BUF);
790 ie_buf[0] = WLAN_EID_SSID;
791 ie_buf[1] = scan_table[i].ssid.ssid_len;
792 memcpy(&ie_buf[sizeof(struct ieee_types_header)],
793 scan_table[i].ssid.ssid, ie_buf[1]);
794
795 ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header);
796 ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
797
798 ie[0] = WLAN_EID_SUPP_RATES;
799
800 for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
801 if (!scan_table[i].supported_rates[j])
802 break;
803 else
804 ie[j + sizeof(struct ieee_types_header)] =
805 scan_table[i].supported_rates[j];
806 }
807
808 ie[1] = j;
809 ie_len += ie[1] + sizeof(struct ieee_types_header);
810
811 beacon = scan_table[i].beacon_buf;
812 beacon_size = scan_table[i].beacon_buf_size;
813
814 /* Skip time stamp, beacon interval and capability */
815
816 if (beacon) {
817 beacon += sizeof(scan_table[i].beacon_period)
818 + sizeof(scan_table[i].time_stamp) +
819 +sizeof(scan_table[i].cap_info_bitmap);
820
821 beacon_size -= sizeof(scan_table[i].beacon_period)
822 + sizeof(scan_table[i].time_stamp)
823 + sizeof(scan_table[i].cap_info_bitmap);
824 }
825
826 while (beacon_size >= sizeof(struct ieee_types_header)) {
827 ie = ie_buf + ie_len;
828 element_id = *beacon;
829 element_len = *(beacon + 1);
830 if (beacon_size < (int) element_len +
831 sizeof(struct ieee_types_header)) {
832 dev_err(priv->adapter->dev, "%s: in processing"
833 " IE, bytes left < IE length\n",
834 __func__);
835 break;
836 }
837 switch (element_id) {
838 case WLAN_EID_EXT_CAPABILITY:
839 case WLAN_EID_DS_PARAMS:
840 case WLAN_EID_HT_CAPABILITY:
841 case WLAN_EID_VENDOR_SPECIFIC:
842 case WLAN_EID_RSN:
843 case WLAN_EID_BSS_AC_ACCESS_DELAY:
844 ie[0] = element_id;
845 ie[1] = element_len;
846 memcpy(&ie[sizeof(struct ieee_types_header)],
847 (u8 *) beacon
848 + sizeof(struct ieee_types_header),
849 element_len);
850 ie_len += ie[1] +
851 sizeof(struct ieee_types_header);
852 break;
853 default:
854 break;
855 }
856 beacon += element_len +
857 sizeof(struct ieee_types_header);
858 beacon_size -= element_len +
859 sizeof(struct ieee_types_header);
860 }
861 chan = ieee80211_get_channel(priv->wdev->wiphy,
862 scan_table[i].freq);
863 cfg80211_inform_bss(priv->wdev->wiphy, chan,
864 scan_table[i].mac_address,
865 0, scan_table[i].cap_info_bitmap,
866 scan_table[i].beacon_period,
867 ie_buf, ie_len,
868 scan_table[i].rssi, GFP_KERNEL);
869 }
870
871 kfree(ie_buf);
872 return 0;
873}
874
875/*
876 * This function connects with a BSS.
877 *
878 * This function handles both Infra and Ad-Hoc modes. It also performs
879 * validity checking on the provided parameters, disconnects from the
880 * current BSS (if any), sets up the association/scan parameters,
881 * including security settings, and performs specific SSID scan before
882 * trying to connect.
883 *
884 * For Infra mode, the function returns failure if the specified SSID
885 * is not found in scan table. However, for Ad-Hoc mode, it can create
886 * the IBSS if it does not exist. On successful completion in either case,
887 * the function notifies the CFG802.11 subsystem of the new BSS connection,
888 * otherwise the kernel will panic.
889 */
890static int
891mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
892 u8 *bssid, int mode, struct ieee80211_channel *channel,
893 struct cfg80211_connect_params *sme, bool privacy)
894{
895 struct mwifiex_802_11_ssid req_ssid;
896 struct mwifiex_ssid_bssid ssid_bssid;
897 int ret, auth_type = 0;
898
899 memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
900 memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
901
902 req_ssid.ssid_len = ssid_len;
903 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
904 dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
905 return -EINVAL;
906 }
907
908 memcpy(req_ssid.ssid, ssid, ssid_len);
909 if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
910 dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
911 return -EINVAL;
912 }
913
914 /* disconnect before try to associate */
915 mwifiex_deauthenticate(priv, NULL);
916
917 if (channel)
918 ret = mwifiex_set_rf_channel(priv, channel,
919 mwifiex_channels_to_cfg80211_channel_type
920 (priv->adapter->chan_offset));
921
922 ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */
923
924 if (mode == NL80211_IFTYPE_ADHOC) {
925 /* "privacy" is set only for ad-hoc mode */
926 if (privacy) {
927 /*
928 * Keep WLAN_CIPHER_SUITE_WEP104 for now so that
929 * the firmware can find a matching network from the
930 * scan. The cfg80211 does not give us the encryption
931 * mode at this stage so just setting it to WEP here.
932 */
933 priv->sec_info.encryption_mode =
934 WLAN_CIPHER_SUITE_WEP104;
935 priv->sec_info.authentication_mode =
936 NL80211_AUTHTYPE_OPEN_SYSTEM;
937 }
938
939 goto done;
940 }
941
942 /* Now handle infra mode. "sme" is valid for infra mode only */
943 if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC
944 || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
945 auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
946 else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
947 auth_type = NL80211_AUTHTYPE_SHARED_KEY;
948
949 if (sme->crypto.n_ciphers_pairwise) {
950 priv->sec_info.encryption_mode =
951 sme->crypto.ciphers_pairwise[0];
952 priv->sec_info.authentication_mode = auth_type;
953 }
954
955 if (sme->crypto.cipher_group) {
956 priv->sec_info.encryption_mode = sme->crypto.cipher_group;
957 priv->sec_info.authentication_mode = auth_type;
958 }
959 if (sme->ie)
960 ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);
961
962 if (sme->key) {
963 if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) {
964 dev_dbg(priv->adapter->dev,
965 "info: setting wep encryption"
966 " with key len %d\n", sme->key_len);
967 ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
968 sme->key_idx, 0);
969 }
970 }
971done:
972 /* Do specific SSID scanning */
973 if (mwifiex_request_scan(priv, &req_ssid)) {
974 dev_err(priv->adapter->dev, "scan error\n");
975 return -EFAULT;
976 }
977
978
979 memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid));
980
981 if (mode != NL80211_IFTYPE_ADHOC) {
982 if (mwifiex_find_best_bss(priv, &ssid_bssid))
983 return -EFAULT;
984 /* Inform the BSS information to kernel, otherwise
985 * kernel will give a panic after successful assoc */
986 if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid))
987 return -EFAULT;
988 }
989
990 dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
991 (char *) req_ssid.ssid, ssid_bssid.bssid);
992
993 memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6);
994
995 /* Connect to BSS by ESSID */
996 memset(&ssid_bssid.bssid, 0, ETH_ALEN);
997
998 if (!netif_queue_stopped(priv->netdev))
999 netif_stop_queue(priv->netdev);
1000
1001 if (mwifiex_bss_start(priv, &ssid_bssid))
1002 return -EFAULT;
1003
1004 if (mode == NL80211_IFTYPE_ADHOC) {
1005 /* Inform the BSS information to kernel, otherwise
1006 * kernel will give a panic after successful assoc */
1007 if (mwifiex_cfg80211_inform_ibss_bss(priv))
1008 return -EFAULT;
1009 }
1010
1011 return ret;
1012}
1013
1014/*
1015 * CFG802.11 operation handler for association request.
1016 *
1017 * This function does not work when the current mode is set to Ad-Hoc, or
1018 * when there is already an association procedure going on. The given BSS
1019 * information is used to associate.
1020 */
1021static int
1022mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
1023 struct cfg80211_connect_params *sme)
1024{
1025 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
1026 int ret = 0;
1027
1028 if (priv->assoc_request)
1029 return -EBUSY;
1030
1031 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
1032 wiphy_err(wiphy, "received infra assoc request "
1033 "when station is in ibss mode\n");
1034 goto done;
1035 }
1036
1037 priv->assoc_request = -EINPROGRESS;
1038
1039 wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
1040 (char *) sme->ssid, sme->bssid);
1041
1042 ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
1043 priv->bss_mode, sme->channel, sme, 0);
1044
1045 priv->assoc_request = 1;
1046done:
1047 priv->assoc_result = ret;
1048 queue_work(priv->workqueue, &priv->cfg_workqueue);
1049 return ret;
1050}
1051
1052/*
1053 * CFG802.11 operation handler to join an IBSS.
1054 *
1055 * This function does not work in any mode other than Ad-Hoc, or if
1056 * a join operation is already in progress.
1057 */
1058static int
1059mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1060 struct cfg80211_ibss_params *params)
1061{
1062 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
1063 int ret = 0;
1064
1065 if (priv->ibss_join_request)
1066 return -EBUSY;
1067
1068 if (priv->bss_mode != NL80211_IFTYPE_ADHOC) {
1069 wiphy_err(wiphy, "request to join ibss received "
1070 "when station is not in ibss mode\n");
1071 goto done;
1072 }
1073
1074 priv->ibss_join_request = -EINPROGRESS;
1075
1076 wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
1077 (char *) params->ssid, params->bssid);
1078
1079 ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
1080 params->bssid, priv->bss_mode,
1081 params->channel, NULL, params->privacy);
1082
1083 priv->ibss_join_request = 1;
1084done:
1085 priv->ibss_join_result = ret;
1086 queue_work(priv->workqueue, &priv->cfg_workqueue);
1087 return ret;
1088}
1089
1090/*
1091 * CFG802.11 operation handler to leave an IBSS.
1092 *
1093 * This function does not work if a leave operation is
1094 * already in progress.
1095 */
1096static int
1097mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
1098{
1099 struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
1100
1101 if (priv->disconnect)
1102 return -EBUSY;
1103
1104 priv->disconnect = 1;
1105
1106 wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
1107 priv->cfg_bssid);
1108 if (mwifiex_deauthenticate(priv, NULL))
1109 return -EFAULT;
1110
1111 queue_work(priv->workqueue, &priv->cfg_workqueue);
1112
1113 return 0;
1114}
1115
1116/*
1117 * CFG802.11 operation handler for scan request.
1118 *
1119 * This function issues a scan request to the firmware based upon
1120 * the user specified scan configuration. On successfull completion,
1121 * it also informs the results.
1122 */
1123static int
1124mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
1125 struct cfg80211_scan_request *request)
1126{
1127 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
1128
1129 wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
1130
1131 if (priv->scan_request && priv->scan_request != request)
1132 return -EBUSY;
1133
1134 priv->scan_request = request;
1135
1136 queue_work(priv->workqueue, &priv->cfg_workqueue);
1137 return 0;
1138}
1139
1140/*
1141 * This function sets up the CFG802.11 specific HT capability fields
1142 * with default values.
1143 *
1144 * The following default values are set -
1145 * - HT Supported = True
1146 * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K
1147 * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE
1148 * - HT Capabilities supported by firmware
1149 * - MCS information, Rx mask = 0xff
1150 * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01)
1151 */
1152static void
1153mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
1154 struct mwifiex_private *priv)
1155{
1156 int rx_mcs_supp;
1157 struct ieee80211_mcs_info mcs_set;
1158 u8 *mcs = (u8 *)&mcs_set;
1159 struct mwifiex_adapter *adapter = priv->adapter;
1160
1161 ht_info->ht_supported = true;
1162 ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
1163 ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
1164
1165 memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
1166
1167 /* Fill HT capability information */
1168 if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
1169 ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
1170 else
1171 ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
1172
1173 if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
1174 ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
1175 else
1176 ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20;
1177
1178 if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
1179 ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
1180 else
1181 ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40;
1182
1183 if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
1184 ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
1185 else
1186 ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
1187
1188 if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
1189 ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
1190 else
1191 ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC;
1192
1193 ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
1194 ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
1195
1196 rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
1197 /* Set MCS for 1x1 */
1198 memset(mcs, 0xff, rx_mcs_supp);
1199 /* Clear all the other values */
1200 memset(&mcs[rx_mcs_supp], 0,
1201 sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
1202 if (priv->bss_mode == NL80211_IFTYPE_STATION ||
1203 ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
1204 /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
1205 SETHT_MCS32(mcs_set.rx_mask);
1206
1207 memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info));
1208
1209 ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
1210}
1211
1212/* station cfg80211 operations */
1213static struct cfg80211_ops mwifiex_cfg80211_ops = {
1214 .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
1215 .scan = mwifiex_cfg80211_scan,
1216 .connect = mwifiex_cfg80211_connect,
1217 .disconnect = mwifiex_cfg80211_disconnect,
1218 .get_station = mwifiex_cfg80211_get_station,
1219 .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
1220 .set_channel = mwifiex_cfg80211_set_channel,
1221 .join_ibss = mwifiex_cfg80211_join_ibss,
1222 .leave_ibss = mwifiex_cfg80211_leave_ibss,
1223 .add_key = mwifiex_cfg80211_add_key,
1224 .del_key = mwifiex_cfg80211_del_key,
1225 .set_default_key = mwifiex_cfg80211_set_default_key,
1226 .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
1227 .set_tx_power = mwifiex_cfg80211_set_tx_power,
1228};
1229
1230/*
1231 * This function registers the device with CFG802.11 subsystem.
1232 *
1233 * The function creates the wireless device/wiphy, populates it with
1234 * default parameters and handler function pointers, and finally
1235 * registers the device.
1236 */
1237int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
1238 struct mwifiex_private *priv)
1239{
1240 int ret;
1241 void *wdev_priv;
1242 struct wireless_dev *wdev;
1243
1244 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1245 if (!wdev) {
1246 dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
1247 __func__);
1248 return -ENOMEM;
1249 }
1250 wdev->wiphy =
1251 wiphy_new(&mwifiex_cfg80211_ops,
1252 sizeof(struct mwifiex_private *));
1253 if (!wdev->wiphy) {
1254 kfree(wdev);
1255 return -ENOMEM;
1256 }
1257 wdev->iftype = NL80211_IFTYPE_STATION;
1258 wdev->wiphy->max_scan_ssids = 10;
1259 wdev->wiphy->interface_modes =
1260 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
1261
1262 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
1263 mwifiex_setup_ht_caps(
1264 &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
1265
1266 if (priv->adapter->config_bands & BAND_A) {
1267 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
1268 mwifiex_setup_ht_caps(
1269 &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
1270 } else {
1271 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
1272 }
1273
1274 /* Initialize cipher suits */
1275 wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
1276 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
1277
1278 memcpy(wdev->wiphy->perm_addr, mac, 6);
1279 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
1280
1281 /* We are using custom domains */
1282 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
1283
1284 wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
1285
1286 /* Set struct mwifiex_private pointer in wiphy_priv */
1287 wdev_priv = wiphy_priv(wdev->wiphy);
1288
1289 *(unsigned long *) wdev_priv = (unsigned long) priv;
1290
1291 set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev);
1292
1293 ret = wiphy_register(wdev->wiphy);
1294 if (ret < 0) {
1295 dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
1296 __func__);
1297 wiphy_free(wdev->wiphy);
1298 kfree(wdev);
1299 return ret;
1300 } else {
1301 dev_dbg(priv->adapter->dev,
1302 "info: successfully registered wiphy device\n");
1303 }
1304
1305 dev_net_set(dev, wiphy_net(wdev->wiphy));
1306 dev->ieee80211_ptr = wdev;
1307 memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
1308 memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
1309 SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
1310 priv->wdev = wdev;
1311
1312 dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1313 dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
1314 dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
1315
1316 return ret;
1317}
1318
1319/*
1320 * This function handles the result of different pending network operations.
1321 *
1322 * The following operations are handled and CFG802.11 subsystem is
1323 * notified accordingly -
1324 * - Scan request completion
1325 * - Association request completion
1326 * - IBSS join request completion
1327 * - Disconnect request completion
1328 */
1329void
1330mwifiex_cfg80211_results(struct work_struct *work)
1331{
1332 struct mwifiex_private *priv =
1333 container_of(work, struct mwifiex_private, cfg_workqueue);
1334 struct mwifiex_user_scan_cfg *scan_req;
1335 int ret = 0, i;
1336 struct ieee80211_channel *chan;
1337
1338 if (priv->scan_request) {
1339 scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
1340 GFP_KERNEL);
1341 if (!scan_req) {
1342 dev_err(priv->adapter->dev, "failed to alloc "
1343 "scan_req\n");
1344 return;
1345 }
1346 for (i = 0; i < priv->scan_request->n_ssids; i++) {
1347 memcpy(scan_req->ssid_list[i].ssid,
1348 priv->scan_request->ssids[i].ssid,
1349 priv->scan_request->ssids[i].ssid_len);
1350 scan_req->ssid_list[i].max_len =
1351 priv->scan_request->ssids[i].ssid_len;
1352 }
1353 for (i = 0; i < priv->scan_request->n_channels; i++) {
1354 chan = priv->scan_request->channels[i];
1355 scan_req->chan_list[i].chan_number = chan->hw_value;
1356 scan_req->chan_list[i].radio_type = chan->band;
1357 if (chan->flags & IEEE80211_CHAN_DISABLED)
1358 scan_req->chan_list[i].scan_type =
1359 MWIFIEX_SCAN_TYPE_PASSIVE;
1360 else
1361 scan_req->chan_list[i].scan_type =
1362 MWIFIEX_SCAN_TYPE_ACTIVE;
1363 scan_req->chan_list[i].scan_time = 0;
1364 }
1365 if (mwifiex_set_user_scan_ioctl(priv, scan_req)) {
1366 ret = -EFAULT;
1367 goto done;
1368 }
1369 if (mwifiex_inform_bss_from_scan_result(priv, NULL))
1370 ret = -EFAULT;
1371done:
1372 priv->scan_result_status = ret;
1373 dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n",
1374 __func__);
1375 cfg80211_scan_done(priv->scan_request,
1376 (priv->scan_result_status < 0));
1377 priv->scan_request = NULL;
1378 kfree(scan_req);
1379 }
1380
1381 if (priv->assoc_request == 1) {
1382 if (!priv->assoc_result) {
1383 cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
1384 NULL, 0, NULL, 0,
1385 WLAN_STATUS_SUCCESS,
1386 GFP_KERNEL);
1387 dev_dbg(priv->adapter->dev,
1388 "info: associated to bssid %pM successfully\n",
1389 priv->cfg_bssid);
1390 } else {
1391 dev_dbg(priv->adapter->dev,
1392 "info: association to bssid %pM failed\n",
1393 priv->cfg_bssid);
1394 memset(priv->cfg_bssid, 0, ETH_ALEN);
1395 }
1396 priv->assoc_request = 0;
1397 priv->assoc_result = 0;
1398 }
1399
1400 if (priv->ibss_join_request == 1) {
1401 if (!priv->ibss_join_result) {
1402 cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
1403 GFP_KERNEL);
1404 dev_dbg(priv->adapter->dev,
1405 "info: joined/created adhoc network with bssid"
1406 " %pM successfully\n", priv->cfg_bssid);
1407 } else {
1408 dev_dbg(priv->adapter->dev,
1409 "info: failed creating/joining adhoc network\n");
1410 }
1411 priv->ibss_join_request = 0;
1412 priv->ibss_join_result = 0;
1413 }
1414
1415 if (priv->disconnect) {
1416 memset(priv->cfg_bssid, 0, ETH_ALEN);
1417 priv->disconnect = 0;
1418 }
1419}
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..d0cada5a29a0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -0,0 +1,360 @@
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(u8 index, u8 ht_info)
79{
80 u16 mcs_rate[4][8] = {
81 {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
82 , /* LG 40M */
83 {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c}
84 , /* SG 40M */
85 {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82}
86 , /* LG 20M */
87 {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90}
88 }; /* SG 20M */
89
90 u32 rate;
91
92 if (ht_info & BIT(0)) {
93 if (index == MWIFIEX_RATE_BITMAP_MCS0) {
94 if (ht_info & BIT(2))
95 rate = 0x0D; /* MCS 32 SGI rate */
96 else
97 rate = 0x0C; /* MCS 32 LGI rate */
98 } else if (index < 8) {
99 if (ht_info & BIT(1)) {
100 if (ht_info & BIT(2))
101 /* SGI, 40M */
102 rate = mcs_rate[1][index];
103 else
104 /* LGI, 40M */
105 rate = mcs_rate[0][index];
106 } else {
107 if (ht_info & BIT(2))
108 /* SGI, 20M */
109 rate = mcs_rate[3][index];
110 else
111 /* LGI, 20M */
112 rate = mcs_rate[2][index];
113 }
114 } else
115 rate = mwifiex_data_rates[0];
116 } else {
117 if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
118 index = 0;
119 rate = mwifiex_data_rates[index];
120 }
121 return rate;
122}
123
124/*
125 * This function maps a data rate value into corresponding index in supported
126 * rates table.
127 */
128u8 mwifiex_data_rate_to_index(u32 rate)
129{
130 u16 *ptr;
131
132 if (rate) {
133 ptr = memchr(mwifiex_data_rates, rate,
134 sizeof(mwifiex_data_rates));
135 if (ptr)
136 return (u8) (ptr - mwifiex_data_rates);
137 }
138 return 0;
139}
140
141/*
142 * This function returns the current active data rates.
143 *
144 * The result may vary depending upon connection status.
145 */
146u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
147{
148 if (!priv->media_connected)
149 return mwifiex_get_supported_rates(priv, rates);
150 else
151 return mwifiex_copy_rates(rates, 0,
152 priv->curr_bss_params.data_rates,
153 priv->curr_bss_params.num_of_rates);
154}
155
156/*
157 * This function locates the Channel-Frequency-Power triplet based upon
158 * band and channel parameters.
159 */
160struct mwifiex_chan_freq_power *
161mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private
162 *priv, u8 band, u16 channel)
163{
164 struct mwifiex_chan_freq_power *cfp = NULL;
165 struct ieee80211_supported_band *sband;
166 struct ieee80211_channel *ch;
167 int i;
168
169 if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
170 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
171 else
172 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
173
174 if (!sband) {
175 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
176 " & channel %d\n", __func__, band, channel);
177 return cfp;
178 }
179
180 for (i = 0; i < sband->n_channels; i++) {
181 ch = &sband->channels[i];
182 if (((ch->hw_value == channel) ||
183 (channel == FIRST_VALID_CHANNEL))
184 && !(ch->flags & IEEE80211_CHAN_DISABLED)) {
185 priv->cfp.channel = channel;
186 priv->cfp.freq = ch->center_freq;
187 priv->cfp.max_tx_power = ch->max_power;
188 cfp = &priv->cfp;
189 break;
190 }
191 }
192 if (i == sband->n_channels)
193 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
194 " & channel %d\n", __func__, band, channel);
195
196 return cfp;
197}
198
199/*
200 * This function locates the Channel-Frequency-Power triplet based upon
201 * band and frequency parameters.
202 */
203struct mwifiex_chan_freq_power *
204mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv,
205 u8 band, u32 freq)
206{
207 struct mwifiex_chan_freq_power *cfp = NULL;
208 struct ieee80211_supported_band *sband;
209 struct ieee80211_channel *ch;
210 int i;
211
212 if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
213 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
214 else
215 sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
216
217 if (!sband) {
218 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
219 " & freq %d\n", __func__, band, freq);
220 return cfp;
221 }
222
223 for (i = 0; i < sband->n_channels; i++) {
224 ch = &sband->channels[i];
225 if ((ch->center_freq == freq) &&
226 !(ch->flags & IEEE80211_CHAN_DISABLED)) {
227 priv->cfp.channel = ch->hw_value;
228 priv->cfp.freq = freq;
229 priv->cfp.max_tx_power = ch->max_power;
230 cfp = &priv->cfp;
231 break;
232 }
233 }
234 if (i == sband->n_channels)
235 dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
236 " & freq %d\n", __func__, band, freq);
237
238 return cfp;
239}
240
241/*
242 * This function checks if the data rate is set to auto.
243 */
244u8
245mwifiex_is_rate_auto(struct mwifiex_private *priv)
246{
247 u32 i;
248 int rate_num = 0;
249
250 for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
251 if (priv->bitmap_rates[i])
252 rate_num++;
253
254 if (rate_num > 1)
255 return true;
256 else
257 return false;
258}
259
260/*
261 * This function converts rate bitmap into rate index.
262 */
263int mwifiex_get_rate_index(u16 *rate_bitmap, int size)
264{
265 int i;
266
267 for (i = 0; i < size * 8; i++)
268 if (rate_bitmap[i / 16] & (1 << (i % 16)))
269 return i;
270
271 return 0;
272}
273
274/*
275 * This function gets the supported data rates.
276 *
277 * The function works in both Ad-Hoc and infra mode by printing the
278 * band and returning the data rates.
279 */
280u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
281{
282 u32 k = 0;
283 struct mwifiex_adapter *adapter = priv->adapter;
284 if (priv->bss_mode == NL80211_IFTYPE_STATION) {
285 switch (adapter->config_bands) {
286 case BAND_B:
287 dev_dbg(adapter->dev, "info: infra band=%d "
288 "supported_rates_b\n", adapter->config_bands);
289 k = mwifiex_copy_rates(rates, k, supported_rates_b,
290 sizeof(supported_rates_b));
291 break;
292 case BAND_G:
293 case BAND_G | BAND_GN:
294 dev_dbg(adapter->dev, "info: infra band=%d "
295 "supported_rates_g\n", adapter->config_bands);
296 k = mwifiex_copy_rates(rates, k, supported_rates_g,
297 sizeof(supported_rates_g));
298 break;
299 case BAND_B | BAND_G:
300 case BAND_A | BAND_B | BAND_G:
301 case BAND_A | BAND_B:
302 case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
303 case BAND_B | BAND_G | BAND_GN:
304 dev_dbg(adapter->dev, "info: infra band=%d "
305 "supported_rates_bg\n", adapter->config_bands);
306 k = mwifiex_copy_rates(rates, k, supported_rates_bg,
307 sizeof(supported_rates_bg));
308 break;
309 case BAND_A:
310 case BAND_A | BAND_G:
311 dev_dbg(adapter->dev, "info: infra band=%d "
312 "supported_rates_a\n", adapter->config_bands);
313 k = mwifiex_copy_rates(rates, k, supported_rates_a,
314 sizeof(supported_rates_a));
315 break;
316 case BAND_A | BAND_AN:
317 case BAND_A | BAND_G | BAND_AN | BAND_GN:
318 dev_dbg(adapter->dev, "info: infra band=%d "
319 "supported_rates_a\n", adapter->config_bands);
320 k = mwifiex_copy_rates(rates, k, supported_rates_a,
321 sizeof(supported_rates_a));
322 break;
323 case BAND_GN:
324 dev_dbg(adapter->dev, "info: infra band=%d "
325 "supported_rates_n\n", adapter->config_bands);
326 k = mwifiex_copy_rates(rates, k, supported_rates_n,
327 sizeof(supported_rates_n));
328 break;
329 }
330 } else {
331 /* Ad-hoc mode */
332 switch (adapter->adhoc_start_band) {
333 case BAND_B:
334 dev_dbg(adapter->dev, "info: adhoc B\n");
335 k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
336 sizeof(adhoc_rates_b));
337 break;
338 case BAND_G:
339 case BAND_G | BAND_GN:
340 dev_dbg(adapter->dev, "info: adhoc G only\n");
341 k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
342 sizeof(adhoc_rates_g));
343 break;
344 case BAND_B | BAND_G:
345 case BAND_B | BAND_G | BAND_GN:
346 dev_dbg(adapter->dev, "info: adhoc BG\n");
347 k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
348 sizeof(adhoc_rates_bg));
349 break;
350 case BAND_A:
351 case BAND_A | BAND_AN:
352 dev_dbg(adapter->dev, "info: adhoc A\n");
353 k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
354 sizeof(adhoc_rates_a));
355 break;
356 }
357 }
358
359 return k;
360}
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
new file mode 100644
index 000000000000..cd89fed206ae
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -0,0 +1,1414 @@
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 *data_buf)
40{
41 cmd_node->priv = priv;
42 cmd_node->cmd_oid = cmd_oid;
43 cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
44 priv->adapter->cmd_wait_q_required = false;
45 cmd_node->data_buf = data_buf;
46 cmd_node->cmd_skb = cmd_node->skb;
47}
48
49/*
50 * This function returns a command node from the free queue depending upon
51 * availability.
52 */
53static struct cmd_ctrl_node *
54mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
55{
56 struct cmd_ctrl_node *cmd_node;
57 unsigned long flags;
58
59 spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
60 if (list_empty(&adapter->cmd_free_q)) {
61 dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n");
62 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
63 return NULL;
64 }
65 cmd_node = list_first_entry(&adapter->cmd_free_q,
66 struct cmd_ctrl_node, list);
67 list_del(&cmd_node->list);
68 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
69
70 return cmd_node;
71}
72
73/*
74 * This function cleans up a command node.
75 *
76 * The function resets the fields including the buffer pointers.
77 * This function does not try to free the buffers. They must be
78 * freed before calling this function.
79 *
80 * This function will however call the receive completion callback
81 * in case a response buffer is still available before resetting
82 * the pointer.
83 */
84static void
85mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
86 struct cmd_ctrl_node *cmd_node)
87{
88 cmd_node->cmd_oid = 0;
89 cmd_node->cmd_flag = 0;
90 cmd_node->data_buf = NULL;
91 cmd_node->wait_q_enabled = false;
92
93 if (cmd_node->resp_skb) {
94 dev_kfree_skb_any(cmd_node->resp_skb);
95 cmd_node->resp_skb = NULL;
96 }
97}
98
99/*
100 * This function sends a host command to the firmware.
101 *
102 * The function copies the host command into the driver command
103 * buffer, which will be transferred to the firmware later by the
104 * main thread.
105 */
106static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv,
107 struct host_cmd_ds_command *cmd, void *data_buf)
108{
109 struct mwifiex_ds_misc_cmd *pcmd_ptr =
110 (struct mwifiex_ds_misc_cmd *) data_buf;
111
112 /* Copy the HOST command to command buffer */
113 memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
114 dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len);
115 return 0;
116}
117
118/*
119 * This function downloads a command to the firmware.
120 *
121 * The function performs sanity tests, sets the command sequence
122 * number and size, converts the header fields to CPU format before
123 * sending. Afterwards, it logs the command ID and action for debugging
124 * and sets up the command timeout timer.
125 */
126static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
127 struct cmd_ctrl_node *cmd_node)
128{
129
130 struct mwifiex_adapter *adapter = priv->adapter;
131 int ret;
132 struct host_cmd_ds_command *host_cmd;
133 uint16_t cmd_code;
134 uint16_t cmd_size;
135 struct timeval tstamp;
136 unsigned long flags;
137
138 if (!adapter || !cmd_node)
139 return -1;
140
141 host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
142
143 /* Sanity test */
144 if (host_cmd == NULL || host_cmd->size == 0) {
145 dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
146 " or cmd size is 0, not sending\n");
147 if (cmd_node->wait_q_enabled)
148 adapter->cmd_wait_q.status = -1;
149 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
150 return -1;
151 }
152
153 /* Set command sequence number */
154 adapter->seq_num++;
155 host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
156 (adapter->seq_num, cmd_node->priv->bss_num,
157 cmd_node->priv->bss_type));
158
159 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
160 adapter->curr_cmd = cmd_node;
161 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
162
163 cmd_code = le16_to_cpu(host_cmd->command);
164 cmd_size = le16_to_cpu(host_cmd->size);
165
166 skb_trim(cmd_node->cmd_skb, cmd_size);
167
168 do_gettimeofday(&tstamp);
169 dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
170 " seqno %#x\n",
171 tstamp.tv_sec, tstamp.tv_usec, cmd_code,
172 le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
173 le16_to_cpu(host_cmd->seq_num));
174
175 skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
176
177 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
178 cmd_node->cmd_skb->data,
179 cmd_node->cmd_skb->len, NULL);
180
181 skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
182
183 if (ret == -1) {
184 dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
185 if (cmd_node->wait_q_enabled)
186 adapter->cmd_wait_q.status = -1;
187 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
188
189 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
190 adapter->curr_cmd = NULL;
191 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
192
193 adapter->dbg.num_cmd_host_to_card_failure++;
194 return -1;
195 }
196
197 /* Save the last command id and action to debug log */
198 adapter->dbg.last_cmd_index =
199 (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
200 adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code;
201 adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] =
202 le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN));
203
204 /* Clear BSS_NO_BITS from HostCmd */
205 cmd_code &= HostCmd_CMD_ID_MASK;
206
207 /* Setup the timer after transmit command */
208 mod_timer(&adapter->cmd_timer,
209 jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000);
210
211 return 0;
212}
213
214/*
215 * This function downloads a sleep confirm command to the firmware.
216 *
217 * The function performs sanity tests, sets the command sequence
218 * number and size, converts the header fields to CPU format before
219 * sending.
220 *
221 * No responses are needed for sleep confirm command.
222 */
223static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
224{
225 int ret;
226 struct mwifiex_private *priv;
227 struct mwifiex_opt_sleep_confirm *sleep_cfm_buf =
228 (struct mwifiex_opt_sleep_confirm *)
229 adapter->sleep_cfm->data;
230 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
231
232 sleep_cfm_buf->seq_num =
233 cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
234 (adapter->seq_num, priv->bss_num,
235 priv->bss_type)));
236 adapter->seq_num++;
237
238 skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
239 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
240 adapter->sleep_cfm->data,
241 adapter->sleep_cfm->len, NULL);
242 skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
243
244 if (ret == -1) {
245 dev_err(adapter->dev, "SLEEP_CFM: failed\n");
246 adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
247 return -1;
248 }
249 if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
250 == MWIFIEX_BSS_ROLE_STA) {
251 if (!sleep_cfm_buf->resp_ctrl)
252 /* Response is not needed for sleep
253 confirm command */
254 adapter->ps_state = PS_STATE_SLEEP;
255 else
256 adapter->ps_state = PS_STATE_SLEEP_CFM;
257
258 if (!sleep_cfm_buf->resp_ctrl
259 && (adapter->is_hs_configured
260 && !adapter->sleep_period.period)) {
261 adapter->pm_wakeup_card_req = true;
262 mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
263 MWIFIEX_BSS_ROLE_STA), true);
264 }
265 }
266
267 return ret;
268}
269
270/*
271 * This function allocates the command buffers and links them to
272 * the command free queue.
273 *
274 * The driver uses a pre allocated number of command buffers, which
275 * are created at driver initializations and freed at driver cleanup.
276 * Every command needs to obtain a command buffer from this pool before
277 * it can be issued. The command free queue lists the command buffers
278 * currently free to use, while the command pending queue lists the
279 * command buffers already in use and awaiting handling. Command buffers
280 * are returned to the free queue after use.
281 */
282int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
283{
284 struct cmd_ctrl_node *cmd_array;
285 u32 buf_size;
286 u32 i;
287
288 /* Allocate and initialize struct cmd_ctrl_node */
289 buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER;
290 cmd_array = kzalloc(buf_size, GFP_KERNEL);
291 if (!cmd_array) {
292 dev_err(adapter->dev, "%s: failed to alloc cmd_array\n",
293 __func__);
294 return -ENOMEM;
295 }
296
297 adapter->cmd_pool = cmd_array;
298 memset(adapter->cmd_pool, 0, buf_size);
299
300 /* Allocate and initialize command buffers */
301 for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
302 cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
303 if (!cmd_array[i].skb) {
304 dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
305 return -1;
306 }
307 }
308
309 for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++)
310 mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]);
311
312 return 0;
313}
314
315/*
316 * This function frees the command buffers.
317 *
318 * The function calls the completion callback for all the command
319 * buffers that still have response buffers associated with them.
320 */
321int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
322{
323 struct cmd_ctrl_node *cmd_array;
324 u32 i;
325
326 /* Need to check if cmd pool is allocated or not */
327 if (!adapter->cmd_pool) {
328 dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n");
329 return 0;
330 }
331
332 cmd_array = adapter->cmd_pool;
333
334 /* Release shared memory buffers */
335 for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
336 if (cmd_array[i].skb) {
337 dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i);
338 dev_kfree_skb_any(cmd_array[i].skb);
339 }
340 if (!cmd_array[i].resp_skb)
341 continue;
342 dev_kfree_skb_any(cmd_array[i].resp_skb);
343 }
344 /* Release struct cmd_ctrl_node */
345 if (adapter->cmd_pool) {
346 dev_dbg(adapter->dev, "cmd: free cmd pool\n");
347 kfree(adapter->cmd_pool);
348 adapter->cmd_pool = NULL;
349 }
350
351 return 0;
352}
353
354/*
355 * This function handles events generated by firmware.
356 *
357 * Event body of events received from firmware are not used (though they are
358 * saved), only the event ID is used. Some events are re-invoked by
359 * the driver, with a new event body.
360 *
361 * After processing, the function calls the completion callback
362 * for cleanup.
363 */
364int mwifiex_process_event(struct mwifiex_adapter *adapter)
365{
366 int ret;
367 struct mwifiex_private *priv =
368 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
369 struct sk_buff *skb = adapter->event_skb;
370 u32 eventcause = adapter->event_cause;
371 struct timeval tstamp;
372 struct mwifiex_rxinfo *rx_info;
373
374 /* Save the last event to debug log */
375 adapter->dbg.last_event_index =
376 (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
377 adapter->dbg.last_event[adapter->dbg.last_event_index] =
378 (u16) eventcause;
379
380 /* Get BSS number and corresponding priv */
381 priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause),
382 EVENT_GET_BSS_TYPE(eventcause));
383 if (!priv)
384 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
385 /* Clear BSS_NO_BITS from event */
386 eventcause &= EVENT_ID_MASK;
387 adapter->event_cause = eventcause;
388
389 if (skb) {
390 rx_info = MWIFIEX_SKB_RXCB(skb);
391 rx_info->bss_index = priv->bss_index;
392 }
393
394 if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
395 do_gettimeofday(&tstamp);
396 dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
397 tstamp.tv_sec, tstamp.tv_usec, eventcause);
398 }
399
400 ret = mwifiex_process_sta_event(priv);
401
402 adapter->event_cause = 0;
403 adapter->event_skb = NULL;
404
405 dev_kfree_skb_any(skb);
406
407 return ret;
408}
409
410/*
411 * This function is used to send synchronous command to the firmware.
412 *
413 * it allocates a wait queue for the command and wait for the command
414 * response.
415 */
416int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
417 u16 cmd_action, u32 cmd_oid, void *data_buf)
418{
419 int ret = 0;
420 struct mwifiex_adapter *adapter = priv->adapter;
421
422 adapter->cmd_wait_q_required = true;
423 adapter->cmd_wait_q.condition = false;
424
425 ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
426 data_buf);
427 if (!ret)
428 ret = mwifiex_wait_queue_complete(adapter);
429
430 return ret;
431}
432
433
434/*
435 * This function prepares a command and asynchronously send it to the firmware.
436 *
437 * Preparation includes -
438 * - Sanity tests to make sure the card is still present or the FW
439 * is not reset
440 * - Getting a new command node from the command free queue
441 * - Initializing the command node for default parameters
442 * - Fill up the non-default parameters and buffer pointers
443 * - Add the command to pending queue
444 */
445int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
446 u16 cmd_action, u32 cmd_oid, void *data_buf)
447{
448 int ret;
449 struct mwifiex_adapter *adapter = priv->adapter;
450 struct cmd_ctrl_node *cmd_node;
451 struct host_cmd_ds_command *cmd_ptr;
452
453 if (!adapter) {
454 pr_err("PREP_CMD: adapter is NULL\n");
455 return -1;
456 }
457
458 if (adapter->is_suspended) {
459 dev_err(adapter->dev, "PREP_CMD: device in suspended state\n");
460 return -1;
461 }
462
463 if (adapter->surprise_removed) {
464 dev_err(adapter->dev, "PREP_CMD: card is removed\n");
465 return -1;
466 }
467
468 if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
469 if (cmd_no != HostCmd_CMD_FUNC_INIT) {
470 dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
471 return -1;
472 }
473 }
474
475 /* Get a new command node */
476 cmd_node = mwifiex_get_cmd_node(adapter);
477
478 if (!cmd_node) {
479 dev_err(adapter->dev, "PREP_CMD: no free cmd node\n");
480 return -1;
481 }
482
483 /* Initialize the command node */
484 mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf);
485
486 if (!cmd_node->cmd_skb) {
487 dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
488 return -1;
489 }
490
491 memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)),
492 0, sizeof(struct host_cmd_ds_command));
493
494 cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
495 cmd_ptr->command = cpu_to_le16(cmd_no);
496 cmd_ptr->result = 0;
497
498 /* Prepare command */
499 if (cmd_no) {
500 ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
501 cmd_oid, data_buf, cmd_ptr);
502 } else {
503 ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
504 cmd_node->cmd_flag |= CMD_F_HOSTCMD;
505 }
506
507 /* Return error, since the command preparation failed */
508 if (ret) {
509 dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n",
510 cmd_no);
511 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
512 return -1;
513 }
514
515 /* Send command */
516 if (cmd_no == HostCmd_CMD_802_11_SCAN)
517 mwifiex_queue_scan_cmd(priv, cmd_node);
518 else
519 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
520
521 return ret;
522}
523
524/*
525 * This function returns a command to the command free queue.
526 *
527 * The function also calls the completion callback if required, before
528 * cleaning the command node and re-inserting it into the free queue.
529 */
530void
531mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
532 struct cmd_ctrl_node *cmd_node)
533{
534 unsigned long flags;
535
536 if (!cmd_node)
537 return;
538
539 if (cmd_node->wait_q_enabled)
540 mwifiex_complete_cmd(adapter);
541 /* Clean the node */
542 mwifiex_clean_cmd_node(adapter, cmd_node);
543
544 /* Insert node into cmd_free_q */
545 spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
546 list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
547 spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
548}
549
550/*
551 * This function queues a command to the command pending queue.
552 *
553 * This in effect adds the command to the command list to be executed.
554 * Exit PS command is handled specially, by placing it always to the
555 * front of the command queue.
556 */
557void
558mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
559 struct cmd_ctrl_node *cmd_node, u32 add_tail)
560{
561 struct host_cmd_ds_command *host_cmd = NULL;
562 u16 command;
563 unsigned long flags;
564
565 host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
566 if (!host_cmd) {
567 dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n");
568 return;
569 }
570
571 command = le16_to_cpu(host_cmd->command);
572
573 /* Exit_PS command needs to be queued in the header always. */
574 if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
575 struct host_cmd_ds_802_11_ps_mode_enh *pm =
576 &host_cmd->params.psmode_enh;
577 if ((le16_to_cpu(pm->action) == DIS_PS)
578 || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) {
579 if (adapter->ps_state != PS_STATE_AWAKE)
580 add_tail = false;
581 }
582 }
583
584 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
585 if (add_tail)
586 list_add_tail(&cmd_node->list, &adapter->cmd_pending_q);
587 else
588 list_add(&cmd_node->list, &adapter->cmd_pending_q);
589 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
590
591 dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
592}
593
594/*
595 * This function executes the next command in command pending queue.
596 *
597 * This function will fail if a command is already in processing stage,
598 * otherwise it will dequeue the first command from the command pending
599 * queue and send to the firmware.
600 *
601 * If the device is currently in host sleep mode, any commands, except the
602 * host sleep configuration command will de-activate the host sleep. For PS
603 * mode, the function will put the firmware back to sleep if applicable.
604 */
605int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
606{
607 struct mwifiex_private *priv;
608 struct cmd_ctrl_node *cmd_node;
609 int ret = 0;
610 struct host_cmd_ds_command *host_cmd;
611 unsigned long cmd_flags;
612 unsigned long cmd_pending_q_flags;
613
614 /* Check if already in processing */
615 if (adapter->curr_cmd) {
616 dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n");
617 return -1;
618 }
619
620 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
621 /* Check if any command is pending */
622 spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
623 if (list_empty(&adapter->cmd_pending_q)) {
624 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
625 cmd_pending_q_flags);
626 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
627 return 0;
628 }
629 cmd_node = list_first_entry(&adapter->cmd_pending_q,
630 struct cmd_ctrl_node, list);
631 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
632 cmd_pending_q_flags);
633
634 host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
635 priv = cmd_node->priv;
636
637 if (adapter->ps_state != PS_STATE_AWAKE) {
638 dev_err(adapter->dev, "%s: cannot send cmd in sleep state,"
639 " this should not happen\n", __func__);
640 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
641 return ret;
642 }
643
644 spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
645 list_del(&cmd_node->list);
646 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
647 cmd_pending_q_flags);
648
649 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
650 ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node);
651 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
652 /* Any command sent to the firmware when host is in sleep
653 * mode should de-configure host sleep. We should skip the
654 * host sleep configuration command itself though
655 */
656 if (priv && (host_cmd->command !=
657 cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
658 if (adapter->hs_activated) {
659 adapter->is_hs_configured = false;
660 mwifiex_hs_activated_event(priv, false);
661 }
662 }
663
664 return ret;
665}
666
667/*
668 * This function handles the command response.
669 *
670 * After processing, the function cleans the command node and puts
671 * it back to the command free queue.
672 */
673int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
674{
675 struct host_cmd_ds_command *resp;
676 struct mwifiex_private *priv =
677 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
678 int ret = 0;
679 uint16_t orig_cmdresp_no;
680 uint16_t cmdresp_no;
681 uint16_t cmdresp_result;
682 struct timeval tstamp;
683 unsigned long flags;
684
685 /* Now we got response from FW, cancel the command timer */
686 del_timer(&adapter->cmd_timer);
687
688 if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
689 resp = (struct host_cmd_ds_command *) adapter->upld_buf;
690 dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n",
691 le16_to_cpu(resp->command));
692 return -1;
693 }
694
695 adapter->num_cmd_timeout = 0;
696
697 resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
698 if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
699 dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
700 le16_to_cpu(resp->command));
701 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
702 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
703 adapter->curr_cmd = NULL;
704 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
705 return -1;
706 }
707
708 if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
709 /* Copy original response back to response buffer */
710 struct mwifiex_ds_misc_cmd *hostcmd = NULL;
711 uint16_t size = le16_to_cpu(resp->size);
712 dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size);
713 size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER);
714 if (adapter->curr_cmd->data_buf) {
715 hostcmd = (struct mwifiex_ds_misc_cmd *)
716 adapter->curr_cmd->data_buf;
717 hostcmd->len = size;
718 memcpy(hostcmd->cmd, (void *) resp, size);
719 }
720 }
721 orig_cmdresp_no = le16_to_cpu(resp->command);
722
723 /* Get BSS number and corresponding priv */
724 priv = mwifiex_get_priv_by_id(adapter,
725 HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)),
726 HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num)));
727 if (!priv)
728 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
729 /* Clear RET_BIT from HostCmd */
730 resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK);
731
732 cmdresp_no = le16_to_cpu(resp->command);
733 cmdresp_result = le16_to_cpu(resp->result);
734
735 /* Save the last command response to debug log */
736 adapter->dbg.last_cmd_resp_index =
737 (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
738 adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
739 orig_cmdresp_no;
740
741 do_gettimeofday(&tstamp);
742 dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d,"
743 " len %d, seqno 0x%x\n",
744 tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result,
745 le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
746
747 if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
748 dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
749 if (adapter->curr_cmd->wait_q_enabled)
750 adapter->cmd_wait_q.status = -1;
751
752 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
753 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
754 adapter->curr_cmd = NULL;
755 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
756 return -1;
757 }
758
759 if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
760 adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
761 if ((cmdresp_result == HostCmd_RESULT_OK)
762 && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
763 ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
764 } else {
765 /* handle response */
766 ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp);
767 }
768
769 /* Check init command response */
770 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
771 if (ret == -1) {
772 dev_err(adapter->dev, "%s: cmd %#x failed during "
773 "initialization\n", __func__, cmdresp_no);
774 mwifiex_init_fw_complete(adapter);
775 return -1;
776 } else if (adapter->last_init_cmd == cmdresp_no)
777 adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE;
778 }
779
780 if (adapter->curr_cmd) {
781 if (adapter->curr_cmd->wait_q_enabled && (!ret))
782 adapter->cmd_wait_q.status = 0;
783 else if (adapter->curr_cmd->wait_q_enabled && (ret == -1))
784 adapter->cmd_wait_q.status = -1;
785
786 /* Clean up and put current command back to cmd_free_q */
787 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
788
789 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
790 adapter->curr_cmd = NULL;
791 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
792 }
793
794 return ret;
795}
796
797/*
798 * This function handles the timeout of command sending.
799 *
800 * It will re-send the same command again.
801 */
802void
803mwifiex_cmd_timeout_func(unsigned long function_context)
804{
805 struct mwifiex_adapter *adapter =
806 (struct mwifiex_adapter *) function_context;
807 struct cmd_ctrl_node *cmd_node;
808 struct timeval tstamp;
809
810 adapter->num_cmd_timeout++;
811 adapter->dbg.num_cmd_timeout++;
812 if (!adapter->curr_cmd) {
813 dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
814 return;
815 }
816 cmd_node = adapter->curr_cmd;
817 if (cmd_node->wait_q_enabled)
818 adapter->cmd_wait_q.status = -ETIMEDOUT;
819
820 if (cmd_node) {
821 adapter->dbg.timeout_cmd_id =
822 adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
823 adapter->dbg.timeout_cmd_act =
824 adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
825 do_gettimeofday(&tstamp);
826 dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x,"
827 " act = %#x\n", __func__,
828 tstamp.tv_sec, tstamp.tv_usec,
829 adapter->dbg.timeout_cmd_id,
830 adapter->dbg.timeout_cmd_act);
831
832 dev_err(adapter->dev, "num_data_h2c_failure = %d\n",
833 adapter->dbg.num_tx_host_to_card_failure);
834 dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
835 adapter->dbg.num_cmd_host_to_card_failure);
836
837 dev_err(adapter->dev, "num_cmd_timeout = %d\n",
838 adapter->dbg.num_cmd_timeout);
839 dev_err(adapter->dev, "num_tx_timeout = %d\n",
840 adapter->dbg.num_tx_timeout);
841
842 dev_err(adapter->dev, "last_cmd_index = %d\n",
843 adapter->dbg.last_cmd_index);
844 print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET,
845 adapter->dbg.last_cmd_id, DBG_CMD_NUM);
846 print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET,
847 adapter->dbg.last_cmd_act, DBG_CMD_NUM);
848
849 dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
850 adapter->dbg.last_cmd_resp_index);
851 print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET,
852 adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM);
853
854 dev_err(adapter->dev, "last_event_index = %d\n",
855 adapter->dbg.last_event_index);
856 print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET,
857 adapter->dbg.last_event, DBG_CMD_NUM);
858
859 dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
860 adapter->data_sent, adapter->cmd_sent);
861
862 dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
863 adapter->ps_mode, adapter->ps_state);
864 }
865 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
866 mwifiex_init_fw_complete(adapter);
867}
868
869/*
870 * This function cancels all the pending commands.
871 *
872 * The current command, all commands in command pending queue and all scan
873 * commands in scan pending queue are cancelled. All the completion callbacks
874 * are called with failure status to ensure cleanup.
875 */
876void
877mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
878{
879 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
880 unsigned long flags;
881
882 /* Cancel current cmd */
883 if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
884 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
885 adapter->curr_cmd->wait_q_enabled = false;
886 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
887 adapter->cmd_wait_q.status = -1;
888 mwifiex_complete_cmd(adapter);
889 }
890 /* Cancel all pending command */
891 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
892 list_for_each_entry_safe(cmd_node, tmp_node,
893 &adapter->cmd_pending_q, list) {
894 list_del(&cmd_node->list);
895 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
896
897 if (cmd_node->wait_q_enabled) {
898 adapter->cmd_wait_q.status = -1;
899 mwifiex_complete_cmd(adapter);
900 cmd_node->wait_q_enabled = false;
901 }
902 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
903 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
904 }
905 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
906
907 /* Cancel all pending scan command */
908 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
909 list_for_each_entry_safe(cmd_node, tmp_node,
910 &adapter->scan_pending_q, list) {
911 list_del(&cmd_node->list);
912 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
913
914 cmd_node->wait_q_enabled = false;
915 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
916 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
917 }
918 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
919
920 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
921 adapter->scan_processing = false;
922 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
923}
924
925/*
926 * This function cancels all pending commands that matches with
927 * the given IOCTL request.
928 *
929 * Both the current command buffer and the pending command queue are
930 * searched for matching IOCTL request. The completion callback of
931 * the matched command is called with failure status to ensure cleanup.
932 * In case of scan commands, all pending commands in scan pending queue
933 * are cancelled.
934 */
935void
936mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
937{
938 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
939 unsigned long cmd_flags;
940 unsigned long cmd_pending_q_flags;
941 unsigned long scan_pending_q_flags;
942 uint16_t cancel_scan_cmd = false;
943
944 if ((adapter->curr_cmd) &&
945 (adapter->curr_cmd->wait_q_enabled)) {
946 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
947 cmd_node = adapter->curr_cmd;
948 cmd_node->wait_q_enabled = false;
949 cmd_node->cmd_flag |= CMD_F_CANCELED;
950 spin_lock_irqsave(&adapter->cmd_pending_q_lock,
951 cmd_pending_q_flags);
952 list_del(&cmd_node->list);
953 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
954 cmd_pending_q_flags);
955 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
956 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
957 }
958
959 /* Cancel all pending scan command */
960 spin_lock_irqsave(&adapter->scan_pending_q_lock,
961 scan_pending_q_flags);
962 list_for_each_entry_safe(cmd_node, tmp_node,
963 &adapter->scan_pending_q, list) {
964 list_del(&cmd_node->list);
965 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
966 scan_pending_q_flags);
967 cmd_node->wait_q_enabled = false;
968 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
969 spin_lock_irqsave(&adapter->scan_pending_q_lock,
970 scan_pending_q_flags);
971 cancel_scan_cmd = true;
972 }
973 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
974 scan_pending_q_flags);
975
976 if (cancel_scan_cmd) {
977 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
978 adapter->scan_processing = false;
979 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
980 }
981 adapter->cmd_wait_q.status = -1;
982 mwifiex_complete_cmd(adapter);
983}
984
985/*
986 * This function sends the sleep confirm command to firmware, if
987 * possible.
988 *
989 * The sleep confirm command cannot be issued if command response,
990 * data response or event response is awaiting handling, or if we
991 * are in the middle of sending a command, or expecting a command
992 * response.
993 */
994void
995mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
996{
997 if (!adapter->cmd_sent &&
998 !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
999 mwifiex_dnld_sleep_confirm_cmd(adapter);
1000 else
1001 dev_dbg(adapter->dev,
1002 "cmd: Delay Sleep Confirm (%s%s%s)\n",
1003 (adapter->cmd_sent) ? "D" : "",
1004 (adapter->curr_cmd) ? "C" : "",
1005 (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
1006}
1007
1008/*
1009 * This function sends a Host Sleep activated event to applications.
1010 *
1011 * This event is generated by the driver, with a blank event body.
1012 */
1013void
1014mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
1015{
1016 if (activated) {
1017 if (priv->adapter->is_hs_configured) {
1018 priv->adapter->hs_activated = true;
1019 dev_dbg(priv->adapter->dev, "event: hs_activated\n");
1020 priv->adapter->hs_activate_wait_q_woken = true;
1021 wake_up_interruptible(
1022 &priv->adapter->hs_activate_wait_q);
1023 } else {
1024 dev_dbg(priv->adapter->dev, "event: HS not configured\n");
1025 }
1026 } else {
1027 dev_dbg(priv->adapter->dev, "event: hs_deactivated\n");
1028 priv->adapter->hs_activated = false;
1029 }
1030}
1031
1032/*
1033 * This function handles the command response of a Host Sleep configuration
1034 * command.
1035 *
1036 * Handling includes changing the header fields into CPU format
1037 * and setting the current host sleep activation status in driver.
1038 *
1039 * In case host sleep status change, the function generates an event to
1040 * notify the applications.
1041 */
1042int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
1043 struct host_cmd_ds_command *resp)
1044{
1045 struct mwifiex_adapter *adapter = priv->adapter;
1046 struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg =
1047 &resp->params.opt_hs_cfg;
1048 uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
1049
1050 if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
1051 mwifiex_hs_activated_event(priv, true);
1052 return 0;
1053 } else {
1054 dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply"
1055 " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
1056 resp->result, conditions,
1057 phs_cfg->params.hs_config.gpio,
1058 phs_cfg->params.hs_config.gap);
1059 }
1060 if (conditions != HOST_SLEEP_CFG_CANCEL) {
1061 adapter->is_hs_configured = true;
1062 } else {
1063 adapter->is_hs_configured = false;
1064 if (adapter->hs_activated)
1065 mwifiex_hs_activated_event(priv, false);
1066 }
1067
1068 return 0;
1069}
1070
1071/*
1072 * This function wakes up the adapter and generates a Host Sleep
1073 * cancel event on receiving the power up interrupt.
1074 */
1075void
1076mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
1077{
1078 dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep"
1079 " since there is interrupt from the firmware\n", __func__);
1080
1081 adapter->if_ops.wakeup(adapter);
1082 adapter->hs_activated = false;
1083 adapter->is_hs_configured = false;
1084 mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
1085 MWIFIEX_BSS_ROLE_ANY), false);
1086}
1087
1088/*
1089 * This function handles the command response of a sleep confirm command.
1090 *
1091 * The function sets the card state to SLEEP if the response indicates success.
1092 */
1093void
1094mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
1095 u8 *pbuf, u32 upld_len)
1096{
1097 struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf;
1098 struct mwifiex_private *priv =
1099 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
1100 uint16_t result = le16_to_cpu(cmd->result);
1101 uint16_t command = le16_to_cpu(cmd->command);
1102 uint16_t seq_num = le16_to_cpu(cmd->seq_num);
1103
1104 if (!upld_len) {
1105 dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
1106 return;
1107 }
1108
1109 /* Get BSS number and corresponding priv */
1110 priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
1111 HostCmd_GET_BSS_TYPE(seq_num));
1112 if (!priv)
1113 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
1114
1115 /* Update sequence number */
1116 seq_num = HostCmd_GET_SEQ_NO(seq_num);
1117 /* Clear RET_BIT from HostCmd */
1118 command &= HostCmd_CMD_ID_MASK;
1119
1120 if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
1121 dev_err(adapter->dev, "%s: received unexpected response for"
1122 " cmd %x, result = %x\n", __func__, command, result);
1123 return;
1124 }
1125
1126 if (result) {
1127 dev_err(adapter->dev, "%s: sleep confirm cmd failed\n",
1128 __func__);
1129 adapter->pm_wakeup_card_req = false;
1130 adapter->ps_state = PS_STATE_AWAKE;
1131 return;
1132 }
1133 adapter->pm_wakeup_card_req = true;
1134 if (adapter->is_hs_configured)
1135 mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
1136 MWIFIEX_BSS_ROLE_ANY), true);
1137 adapter->ps_state = PS_STATE_SLEEP;
1138 cmd->command = cpu_to_le16(command);
1139 cmd->seq_num = cpu_to_le16(seq_num);
1140}
1141EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp);
1142
1143/*
1144 * This function prepares an enhanced power mode command.
1145 *
1146 * This function can be used to disable power save or to configure
1147 * power save with auto PS or STA PS or auto deep sleep.
1148 *
1149 * Preparation includes -
1150 * - Setting command ID, action and proper size
1151 * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV,
1152 * auto deep sleep TLV (as required)
1153 * - Ensuring correct endian-ness
1154 */
1155int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
1156 struct host_cmd_ds_command *cmd,
1157 u16 cmd_action, uint16_t ps_bitmap,
1158 void *data_buf)
1159{
1160 struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh =
1161 &cmd->params.psmode_enh;
1162 u8 *tlv;
1163 u16 cmd_size = 0;
1164
1165 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
1166 if (cmd_action == DIS_AUTO_PS) {
1167 psmode_enh->action = cpu_to_le16(DIS_AUTO_PS);
1168 psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
1169 cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) +
1170 sizeof(psmode_enh->params.ps_bitmap));
1171 } else if (cmd_action == GET_PS) {
1172 psmode_enh->action = cpu_to_le16(GET_PS);
1173 psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
1174 cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) +
1175 sizeof(psmode_enh->params.ps_bitmap));
1176 } else if (cmd_action == EN_AUTO_PS) {
1177 psmode_enh->action = cpu_to_le16(EN_AUTO_PS);
1178 psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
1179 cmd_size = S_DS_GEN + sizeof(psmode_enh->action) +
1180 sizeof(psmode_enh->params.ps_bitmap);
1181 tlv = (u8 *) cmd + cmd_size;
1182 if (ps_bitmap & BITMAP_STA_PS) {
1183 struct mwifiex_adapter *adapter = priv->adapter;
1184 struct mwifiex_ie_types_ps_param *ps_tlv =
1185 (struct mwifiex_ie_types_ps_param *) tlv;
1186 struct mwifiex_ps_param *ps_mode = &ps_tlv->param;
1187 ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM);
1188 ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) -
1189 sizeof(struct mwifiex_ie_types_header));
1190 cmd_size += sizeof(*ps_tlv);
1191 tlv += sizeof(*ps_tlv);
1192 dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n");
1193 ps_mode->null_pkt_interval =
1194 cpu_to_le16(adapter->null_pkt_interval);
1195 ps_mode->multiple_dtims =
1196 cpu_to_le16(adapter->multiple_dtim);
1197 ps_mode->bcn_miss_timeout =
1198 cpu_to_le16(adapter->bcn_miss_time_out);
1199 ps_mode->local_listen_interval =
1200 cpu_to_le16(adapter->local_listen_interval);
1201 ps_mode->adhoc_wake_period =
1202 cpu_to_le16(adapter->adhoc_awake_period);
1203 ps_mode->delay_to_ps =
1204 cpu_to_le16(adapter->delay_to_ps);
1205 ps_mode->mode =
1206 cpu_to_le16(adapter->enhanced_ps_mode);
1207
1208 }
1209 if (ps_bitmap & BITMAP_AUTO_DS) {
1210 struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv =
1211 (struct mwifiex_ie_types_auto_ds_param *) tlv;
1212 u16 idletime = 0;
1213
1214 auto_ds_tlv->header.type =
1215 cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
1216 auto_ds_tlv->header.len =
1217 cpu_to_le16(sizeof(*auto_ds_tlv) -
1218 sizeof(struct mwifiex_ie_types_header));
1219 cmd_size += sizeof(*auto_ds_tlv);
1220 tlv += sizeof(*auto_ds_tlv);
1221 if (data_buf)
1222 idletime = ((struct mwifiex_ds_auto_ds *)
1223 data_buf)->idle_time;
1224 dev_dbg(priv->adapter->dev,
1225 "cmd: PS Command: Enter Auto Deep Sleep\n");
1226 auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime);
1227 }
1228 cmd->size = cpu_to_le16(cmd_size);
1229 }
1230 return 0;
1231}
1232
1233/*
1234 * This function handles the command response of an enhanced power mode
1235 * command.
1236 *
1237 * Handling includes changing the header fields into CPU format
1238 * and setting the current enhanced power mode in driver.
1239 */
1240int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
1241 struct host_cmd_ds_command *resp,
1242 void *data_buf)
1243{
1244 struct mwifiex_adapter *adapter = priv->adapter;
1245 struct host_cmd_ds_802_11_ps_mode_enh *ps_mode =
1246 &resp->params.psmode_enh;
1247 uint16_t action = le16_to_cpu(ps_mode->action);
1248 uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap);
1249 uint16_t auto_ps_bitmap =
1250 le16_to_cpu(ps_mode->params.ps_bitmap);
1251
1252 dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
1253 __func__, resp->result, action);
1254 if (action == EN_AUTO_PS) {
1255 if (auto_ps_bitmap & BITMAP_AUTO_DS) {
1256 dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n");
1257 priv->adapter->is_deep_sleep = true;
1258 }
1259 if (auto_ps_bitmap & BITMAP_STA_PS) {
1260 dev_dbg(adapter->dev, "cmd: Enabled STA power save\n");
1261 if (adapter->sleep_period.period)
1262 dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n");
1263 }
1264 } else if (action == DIS_AUTO_PS) {
1265 if (ps_bitmap & BITMAP_AUTO_DS) {
1266 priv->adapter->is_deep_sleep = false;
1267 dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n");
1268 }
1269 if (ps_bitmap & BITMAP_STA_PS) {
1270 dev_dbg(adapter->dev, "cmd: Disabled STA power save\n");
1271 if (adapter->sleep_period.period) {
1272 adapter->delay_null_pkt = false;
1273 adapter->tx_lock_flag = false;
1274 adapter->pps_uapsd_mode = false;
1275 }
1276 }
1277 } else if (action == GET_PS) {
1278 if (ps_bitmap & BITMAP_STA_PS)
1279 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1280 else
1281 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
1282
1283 dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap);
1284
1285 if (data_buf) {
1286 /* This section is for get power save mode */
1287 struct mwifiex_ds_pm_cfg *pm_cfg =
1288 (struct mwifiex_ds_pm_cfg *)data_buf;
1289 if (ps_bitmap & BITMAP_STA_PS)
1290 pm_cfg->param.ps_mode = 1;
1291 else
1292 pm_cfg->param.ps_mode = 0;
1293 }
1294 }
1295 return 0;
1296}
1297
1298/*
1299 * This function prepares command to get hardware specifications.
1300 *
1301 * Preparation includes -
1302 * - Setting command ID, action and proper size
1303 * - Setting permanent address parameter
1304 * - Ensuring correct endian-ness
1305 */
1306int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
1307 struct host_cmd_ds_command *cmd)
1308{
1309 struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec;
1310
1311 cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
1312 cmd->size =
1313 cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN);
1314 memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN);
1315
1316 return 0;
1317}
1318
1319/*
1320 * This function handles the command response of get hardware
1321 * specifications.
1322 *
1323 * Handling includes changing the header fields into CPU format
1324 * and saving/updating the following parameters in driver -
1325 * - Firmware capability information
1326 * - Firmware band settings
1327 * - Ad-hoc start band and channel
1328 * - Ad-hoc 11n activation status
1329 * - Firmware release number
1330 * - Number of antennas
1331 * - Hardware address
1332 * - Hardware interface version
1333 * - Firmware version
1334 * - Region code
1335 * - 11n capabilities
1336 * - MCS support fields
1337 * - MP end port
1338 */
1339int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
1340 struct host_cmd_ds_command *resp)
1341{
1342 struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
1343 struct mwifiex_adapter *adapter = priv->adapter;
1344 int i;
1345
1346 adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info);
1347
1348 if (IS_SUPPORT_MULTI_BANDS(adapter))
1349 adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter);
1350 else
1351 adapter->fw_bands = BAND_B;
1352
1353 adapter->config_bands = adapter->fw_bands;
1354
1355 if (adapter->fw_bands & BAND_A) {
1356 if (adapter->fw_bands & BAND_GN) {
1357 adapter->config_bands |= BAND_AN;
1358 adapter->fw_bands |= BAND_AN;
1359 }
1360 if (adapter->fw_bands & BAND_AN) {
1361 adapter->adhoc_start_band = BAND_A | BAND_AN;
1362 adapter->adhoc_11n_enabled = true;
1363 } else {
1364 adapter->adhoc_start_band = BAND_A;
1365 }
1366 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
1367 } else if (adapter->fw_bands & BAND_GN) {
1368 adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
1369 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
1370 adapter->adhoc_11n_enabled = true;
1371 } else if (adapter->fw_bands & BAND_G) {
1372 adapter->adhoc_start_band = BAND_G | BAND_B;
1373 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
1374 } else if (adapter->fw_bands & BAND_B) {
1375 adapter->adhoc_start_band = BAND_B;
1376 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
1377 }
1378
1379 adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
1380 adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
1381
1382 dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
1383 adapter->fw_release_number);
1384 dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
1385 hw_spec->permanent_addr);
1386 dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
1387 le16_to_cpu(hw_spec->hw_if_version),
1388 le16_to_cpu(hw_spec->version));
1389
1390 if (priv->curr_addr[0] == 0xff)
1391 memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN);
1392
1393 adapter->region_code = le16_to_cpu(hw_spec->region_code);
1394
1395 for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++)
1396 /* Use the region code to search for the index */
1397 if (adapter->region_code == region_code_index[i])
1398 break;
1399
1400 /* If it's unidentified region code, use the default (USA) */
1401 if (i >= MWIFIEX_MAX_REGION_CODE) {
1402 adapter->region_code = 0x10;
1403 dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n");
1404 }
1405
1406 adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
1407 adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
1408
1409 if (adapter->if_ops.update_mp_end_port)
1410 adapter->if_ops.update_mp_end_port(adapter,
1411 le16_to_cpu(hw_spec->mp_end_port));
1412
1413 return 0;
1414}
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
new file mode 100644
index 000000000000..46d65e02c7ba
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -0,0 +1,770 @@
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 {"cmd_pending", adapter_item_size(cmd_pending),
133 adapter_item_addr(cmd_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;
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;
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;
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;
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;
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
740/*
741 * This function removes the debug FS directory structure and the files.
742 */
743void
744mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
745{
746 if (!priv)
747 return;
748
749 debugfs_remove_recursive(priv->dfs_dev_dir);
750}
751
752/*
753 * This function creates the top level proc directory.
754 */
755void
756mwifiex_debugfs_init(void)
757{
758 if (!mwifiex_dfs_dir)
759 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
760}
761
762/*
763 * This function removes the top level proc directory.
764 */
765void
766mwifiex_debugfs_remove(void)
767{
768 if (mwifiex_dfs_dir)
769 debugfs_remove(mwifiex_dfs_dir);
770}
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
new file mode 100644
index 000000000000..0e90b0986ed8
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -0,0 +1,129 @@
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
55#define MWIFIEX_RTS_MIN_VALUE (0)
56#define MWIFIEX_RTS_MAX_VALUE (2347)
57#define MWIFIEX_FRAG_MIN_VALUE (256)
58#define MWIFIEX_FRAG_MAX_VALUE (2346)
59
60#define MWIFIEX_SDIO_BLOCK_SIZE 256
61
62#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
63
64enum mwifiex_bss_type {
65 MWIFIEX_BSS_TYPE_STA = 0,
66 MWIFIEX_BSS_TYPE_UAP = 1,
67 MWIFIEX_BSS_TYPE_ANY = 0xff,
68};
69
70enum mwifiex_bss_role {
71 MWIFIEX_BSS_ROLE_STA = 0,
72 MWIFIEX_BSS_ROLE_UAP = 1,
73 MWIFIEX_BSS_ROLE_ANY = 0xff,
74};
75
76#define BSS_ROLE_BIT_MASK BIT(0)
77
78#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
79
80enum mwifiex_data_frame_type {
81 MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0,
82 MWIFIEX_DATA_FRAME_TYPE_802_11,
83};
84
85struct mwifiex_fw_image {
86 u8 *helper_buf;
87 u32 helper_len;
88 u8 *fw_buf;
89 u32 fw_len;
90};
91
92struct mwifiex_802_11_ssid {
93 u32 ssid_len;
94 u8 ssid[IEEE80211_MAX_SSID_LEN];
95};
96
97struct mwifiex_wait_queue {
98 wait_queue_head_t wait;
99 u16 condition;
100 int status;
101};
102
103struct mwifiex_rxinfo {
104 u8 bss_index;
105 struct sk_buff *parent;
106 u8 use_count;
107};
108
109struct mwifiex_txinfo {
110 u32 status_code;
111 u8 flags;
112 u8 bss_index;
113};
114
115struct mwifiex_bss_attr {
116 u8 bss_type;
117 u8 frame_type;
118 u8 active;
119 u8 bss_priority;
120 u8 bss_num;
121};
122
123enum mwifiex_wmm_ac_e {
124 WMM_AC_BK,
125 WMM_AC_BE,
126 WMM_AC_VI,
127 WMM_AC_VO
128} __packed;
129#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..afdd145dff0b
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -0,0 +1,1187 @@
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
60extern u8 supported_rates_b[B_SUPPORTED_RATES];
61extern u8 supported_rates_g[G_SUPPORTED_RATES];
62extern u8 supported_rates_bg[BG_SUPPORTED_RATES];
63extern u8 supported_rates_a[A_SUPPORTED_RATES];
64extern u8 supported_rates_n[N_SUPPORTED_RATES];
65
66#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
67
68#define KEY_INFO_ENABLED 0x01
69enum KEY_TYPE_ID {
70 KEY_TYPE_ID_WEP = 0,
71 KEY_TYPE_ID_TKIP,
72 KEY_TYPE_ID_AES,
73 KEY_TYPE_ID_WAPI,
74};
75#define KEY_MCAST BIT(0)
76#define KEY_UNICAST BIT(1)
77#define KEY_ENABLED BIT(2)
78
79#define WAPI_KEY_LEN 50
80
81#define MAX_POLL_TRIES 100
82
83#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
84
85#define MAX_FIRMWARE_POLL_TRIES 100
86
87#define FIRMWARE_READY 0xfedc
88
89enum MWIFIEX_802_11_PRIVACY_FILTER {
90 MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
91 MWIFIEX_802_11_PRIV_FILTER_8021X_WEP
92};
93
94enum MWIFIEX_802_11_WEP_STATUS {
95 MWIFIEX_802_11_WEP_ENABLED,
96 MWIFIEX_802_11_WEP_DISABLED,
97};
98
99#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
100
101#define PROPRIETARY_TLV_BASE_ID 0x0100
102#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
103#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
104#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
105#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
106#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
107#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
108#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
109#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
110#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
111#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
112#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
113#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
114#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
115#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
116#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
117
118#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
119
120#define SSN_MASK 0xfff0
121
122#define BA_RESULT_SUCCESS 0x0
123#define BA_RESULT_TIMEOUT 0x2
124
125#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
126
127#define BA_STREAM_NOT_ALLOWED 0xff
128
129#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \
130 priv->adapter->config_bands & BAND_AN) \
131 && priv->curr_bss_params.bss_descriptor.bcn_ht_cap)
132#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\
133 BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
134
135#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096
136#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192
137
138#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
139
140/* dev_cap bitmap
141 * BIT
142 * 0-16 reserved
143 * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40
144 * 18-22 reserved
145 * 23 IEEE80211_HT_CAP_SGI_20
146 * 24 IEEE80211_HT_CAP_SGI_40
147 * 25 IEEE80211_HT_CAP_TX_STBC
148 * 26 IEEE80211_HT_CAP_RX_STBC
149 * 27-28 reserved
150 * 29 IEEE80211_HT_CAP_GRN_FLD
151 * 30-31 reserved
152 */
153#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17))
154#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23))
155#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24))
156#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25))
157#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26))
158#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29))
159
160#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
161#define SETHT_MCS32(x) (x[4] |= 1)
162
163#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
164
165#define LLC_SNAP_LEN 8
166
167#define MOD_CLASS_HR_DSSS 0x03
168#define MOD_CLASS_OFDM 0x07
169#define MOD_CLASS_HT 0x08
170#define HT_BW_20 0
171#define HT_BW_40 1
172
173#define HostCmd_CMD_GET_HW_SPEC 0x0003
174#define HostCmd_CMD_802_11_SCAN 0x0006
175#define HostCmd_CMD_802_11_GET_LOG 0x000b
176#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
177#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
178#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
179#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
180#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
181#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
182#define HostCmd_CMD_RF_REG_ACCESS 0x001b
183#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad
184#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
185#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
186#define HostCmd_CMD_MAC_CONTROL 0x0028
187#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
188#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
189#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
190#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
191#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
192#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
193#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
194#define HostCmd_CMD_WMM_GET_STATUS 0x0071
195#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
196#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
197#define HostCmd_CMD_VERSION_EXT 0x0097
198#define HostCmd_CMD_RSSI_INFO 0x00a4
199#define HostCmd_CMD_FUNC_INIT 0x00a9
200#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
201#define HostCmd_CMD_11N_CFG 0x00cd
202#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
203#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
204#define HostCmd_CMD_11N_DELBA 0x00d0
205#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
206#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
207#define HostCmd_CMD_TXPWR_CFG 0x00d1
208#define HostCmd_CMD_TX_RATE_CFG 0x00d6
209#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
210#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
211#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
212#define HostCmd_CMD_SET_BSS_MODE 0x00f7
213
214
215enum ENH_PS_MODES {
216 EN_PS = 1,
217 DIS_PS = 2,
218 EN_AUTO_DS = 3,
219 DIS_AUTO_DS = 4,
220 SLEEP_CONFIRM = 5,
221 GET_PS = 0,
222 EN_AUTO_PS = 0xff,
223 DIS_AUTO_PS = 0xfe,
224};
225
226#define HostCmd_RET_BIT 0x8000
227#define HostCmd_ACT_GEN_GET 0x0000
228#define HostCmd_ACT_GEN_SET 0x0001
229#define HostCmd_RESULT_OK 0x0000
230
231#define HostCmd_ACT_MAC_RX_ON 0x0001
232#define HostCmd_ACT_MAC_TX_ON 0x0002
233#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
234#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
235#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
236#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
237#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
238
239#define HostCmd_BSS_MODE_IBSS 0x0002
240#define HostCmd_BSS_MODE_ANY 0x0003
241
242#define HostCmd_SCAN_RADIO_TYPE_BG 0
243#define HostCmd_SCAN_RADIO_TYPE_A 1
244
245#define HOST_SLEEP_CFG_CANCEL 0xffffffff
246#define HOST_SLEEP_CFG_COND_DEF 0x0000000f
247#define HOST_SLEEP_CFG_GPIO_DEF 0xff
248#define HOST_SLEEP_CFG_GAP_DEF 0
249
250#define CMD_F_HOSTCMD (1 << 0)
251#define CMD_F_CANCELED (1 << 1)
252
253#define HostCmd_CMD_ID_MASK 0x0fff
254
255#define HostCmd_SEQ_NUM_MASK 0x00ff
256
257#define HostCmd_BSS_NUM_MASK 0x0f00
258
259#define HostCmd_BSS_TYPE_MASK 0xf000
260
261#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \
262 (((seq) & 0x00ff) | \
263 (((num) & 0x000f) << 8)) | \
264 (((type) & 0x000f) << 12); }
265
266#define HostCmd_GET_SEQ_NO(seq) \
267 ((seq) & HostCmd_SEQ_NUM_MASK)
268
269#define HostCmd_GET_BSS_NO(seq) \
270 (((seq) & HostCmd_BSS_NUM_MASK) >> 8)
271
272#define HostCmd_GET_BSS_TYPE(seq) \
273 (((seq) & HostCmd_BSS_TYPE_MASK) >> 12)
274
275#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
276#define EVENT_LINK_LOST 0x00000003
277#define EVENT_LINK_SENSED 0x00000004
278#define EVENT_MIB_CHANGED 0x00000006
279#define EVENT_INIT_DONE 0x00000007
280#define EVENT_DEAUTHENTICATED 0x00000008
281#define EVENT_DISASSOCIATED 0x00000009
282#define EVENT_PS_AWAKE 0x0000000a
283#define EVENT_PS_SLEEP 0x0000000b
284#define EVENT_MIC_ERR_MULTICAST 0x0000000d
285#define EVENT_MIC_ERR_UNICAST 0x0000000e
286#define EVENT_DEEP_SLEEP_AWAKE 0x00000010
287#define EVENT_ADHOC_BCN_LOST 0x00000011
288
289#define EVENT_WMM_STATUS_CHANGE 0x00000017
290#define EVENT_BG_SCAN_REPORT 0x00000018
291#define EVENT_RSSI_LOW 0x00000019
292#define EVENT_SNR_LOW 0x0000001a
293#define EVENT_MAX_FAIL 0x0000001b
294#define EVENT_RSSI_HIGH 0x0000001c
295#define EVENT_SNR_HIGH 0x0000001d
296#define EVENT_IBSS_COALESCED 0x0000001e
297#define EVENT_DATA_RSSI_LOW 0x00000024
298#define EVENT_DATA_SNR_LOW 0x00000025
299#define EVENT_DATA_RSSI_HIGH 0x00000026
300#define EVENT_DATA_SNR_HIGH 0x00000027
301#define EVENT_LINK_QUALITY 0x00000028
302#define EVENT_PORT_RELEASE 0x0000002b
303#define EVENT_PRE_BEACON_LOST 0x00000031
304#define EVENT_ADDBA 0x00000033
305#define EVENT_DELBA 0x00000034
306#define EVENT_BA_STREAM_TIEMOUT 0x00000037
307#define EVENT_AMSDU_AGGR_CTRL 0x00000042
308#define EVENT_WEP_ICV_ERR 0x00000046
309#define EVENT_HS_ACT_REQ 0x00000047
310#define EVENT_BW_CHANGE 0x00000048
311
312#define EVENT_HOSTWAKE_STAIE 0x0000004d
313
314#define EVENT_ID_MASK 0xffff
315#define BSS_NUM_MASK 0xf
316
317#define EVENT_GET_BSS_NUM(event_cause) \
318 (((event_cause) >> 16) & BSS_NUM_MASK)
319
320#define EVENT_GET_BSS_TYPE(event_cause) \
321 (((event_cause) >> 24) & 0x00ff)
322
323struct mwifiex_ie_types_header {
324 __le16 type;
325 __le16 len;
326} __packed;
327
328struct mwifiex_ie_types_data {
329 struct mwifiex_ie_types_header header;
330 u8 data[1];
331} __packed;
332
333#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01
334#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08
335
336struct txpd {
337 u8 bss_type;
338 u8 bss_num;
339 __le16 tx_pkt_length;
340 __le16 tx_pkt_offset;
341 __le16 tx_pkt_type;
342 __le32 tx_control;
343 u8 priority;
344 u8 flags;
345 u8 pkt_delay_2ms;
346 u8 reserved1;
347} __packed;
348
349struct rxpd {
350 u8 bss_type;
351 u8 bss_num;
352 u16 rx_pkt_length;
353 u16 rx_pkt_offset;
354 u16 rx_pkt_type;
355 u16 seq_num;
356 u8 priority;
357 u8 rx_rate;
358 s8 snr;
359 s8 nf;
360 /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
361 * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
362 * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
363 u8 ht_info;
364 u8 reserved;
365} __packed;
366
367enum mwifiex_chan_scan_mode_bitmasks {
368 MWIFIEX_PASSIVE_SCAN = BIT(0),
369 MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
370};
371
372#define SECOND_CHANNEL_BELOW 0x30
373#define SECOND_CHANNEL_ABOVE 0x10
374struct mwifiex_chan_scan_param_set {
375 u8 radio_type;
376 u8 chan_number;
377 u8 chan_scan_mode_bitmap;
378 __le16 min_scan_time;
379 __le16 max_scan_time;
380} __packed;
381
382struct mwifiex_ie_types_chan_list_param_set {
383 struct mwifiex_ie_types_header header;
384 struct mwifiex_chan_scan_param_set chan_scan_param[1];
385} __packed;
386
387struct chan_band_param_set {
388 u8 radio_type;
389 u8 chan_number;
390};
391
392struct mwifiex_ie_types_chan_band_list_param_set {
393 struct mwifiex_ie_types_header header;
394 struct chan_band_param_set chan_band_param[1];
395} __packed;
396
397struct mwifiex_ie_types_rates_param_set {
398 struct mwifiex_ie_types_header header;
399 u8 rates[1];
400} __packed;
401
402struct mwifiex_ie_types_ssid_param_set {
403 struct mwifiex_ie_types_header header;
404 u8 ssid[1];
405} __packed;
406
407struct mwifiex_ie_types_num_probes {
408 struct mwifiex_ie_types_header header;
409 __le16 num_probes;
410} __packed;
411
412struct mwifiex_ie_types_wildcard_ssid_params {
413 struct mwifiex_ie_types_header header;
414 u8 max_ssid_length;
415 u8 ssid[1];
416} __packed;
417
418#define TSF_DATA_SIZE 8
419struct mwifiex_ie_types_tsf_timestamp {
420 struct mwifiex_ie_types_header header;
421 u8 tsf_data[1];
422} __packed;
423
424struct mwifiex_cf_param_set {
425 u8 cfp_cnt;
426 u8 cfp_period;
427 u16 cfp_max_duration;
428 u16 cfp_duration_remaining;
429} __packed;
430
431struct mwifiex_ibss_param_set {
432 u16 atim_window;
433} __packed;
434
435struct mwifiex_ie_types_ss_param_set {
436 struct mwifiex_ie_types_header header;
437 union {
438 struct mwifiex_cf_param_set cf_param_set[1];
439 struct mwifiex_ibss_param_set ibss_param_set[1];
440 } cf_ibss;
441} __packed;
442
443struct mwifiex_fh_param_set {
444 u16 dwell_time;
445 u8 hop_set;
446 u8 hop_pattern;
447 u8 hop_index;
448} __packed;
449
450struct mwifiex_ds_param_set {
451 u8 current_chan;
452} __packed;
453
454struct mwifiex_ie_types_phy_param_set {
455 struct mwifiex_ie_types_header header;
456 union {
457 struct mwifiex_fh_param_set fh_param_set[1];
458 struct mwifiex_ds_param_set ds_param_set[1];
459 } fh_ds;
460} __packed;
461
462struct mwifiex_ie_types_auth_type {
463 struct mwifiex_ie_types_header header;
464 __le16 auth_type;
465} __packed;
466
467struct mwifiex_ie_types_vendor_param_set {
468 struct mwifiex_ie_types_header header;
469 u8 ie[MWIFIEX_MAX_VSIE_LEN];
470};
471
472struct mwifiex_ie_types_rsn_param_set {
473 struct mwifiex_ie_types_header header;
474 u8 rsn_ie[1];
475} __packed;
476
477#define KEYPARAMSET_FIXED_LEN 6
478
479struct mwifiex_ie_type_key_param_set {
480 __le16 type;
481 __le16 length;
482 __le16 key_type_id;
483 __le16 key_info;
484 __le16 key_len;
485 u8 key[50];
486} __packed;
487
488struct host_cmd_ds_802_11_key_material {
489 __le16 action;
490 struct mwifiex_ie_type_key_param_set key_param_set;
491} __packed;
492
493struct host_cmd_ds_gen {
494 u16 command;
495 u16 size;
496 u16 seq_num;
497 u16 result;
498};
499
500#define S_DS_GEN sizeof(struct host_cmd_ds_gen)
501
502enum sleep_resp_ctrl {
503 RESP_NOT_NEEDED = 0,
504 RESP_NEEDED,
505};
506
507struct mwifiex_ps_param {
508 __le16 null_pkt_interval;
509 __le16 multiple_dtims;
510 __le16 bcn_miss_timeout;
511 __le16 local_listen_interval;
512 __le16 adhoc_wake_period;
513 __le16 mode;
514 __le16 delay_to_ps;
515};
516
517#define BITMAP_AUTO_DS 0x01
518#define BITMAP_STA_PS 0x10
519
520struct mwifiex_ie_types_auto_ds_param {
521 struct mwifiex_ie_types_header header;
522 __le16 deep_sleep_timeout;
523} __packed;
524
525struct mwifiex_ie_types_ps_param {
526 struct mwifiex_ie_types_header header;
527 struct mwifiex_ps_param param;
528} __packed;
529
530struct host_cmd_ds_802_11_ps_mode_enh {
531 __le16 action;
532
533 union {
534 struct mwifiex_ps_param opt_ps;
535 __le16 ps_bitmap;
536 } params;
537} __packed;
538
539struct host_cmd_ds_get_hw_spec {
540 __le16 hw_if_version;
541 __le16 version;
542 __le16 reserved;
543 __le16 num_of_mcast_adr;
544 u8 permanent_addr[ETH_ALEN];
545 __le16 region_code;
546 __le16 number_of_antenna;
547 __le32 fw_release_number;
548 __le32 reserved_1;
549 __le32 reserved_2;
550 __le32 reserved_3;
551 __le32 fw_cap_info;
552 __le32 dot_11n_dev_cap;
553 u8 dev_mcs_support;
554 __le16 mp_end_port; /* SDIO only, reserved for other interfacces */
555 __le16 reserved_4;
556} __packed;
557
558struct host_cmd_ds_802_11_rssi_info {
559 __le16 action;
560 __le16 ndata;
561 __le16 nbcn;
562 __le16 reserved[9];
563 long long reserved_1;
564};
565
566struct host_cmd_ds_802_11_rssi_info_rsp {
567 __le16 action;
568 __le16 ndata;
569 __le16 nbcn;
570 __le16 data_rssi_last;
571 __le16 data_nf_last;
572 __le16 data_rssi_avg;
573 __le16 data_nf_avg;
574 __le16 bcn_rssi_last;
575 __le16 bcn_nf_last;
576 __le16 bcn_rssi_avg;
577 __le16 bcn_nf_avg;
578 long long tsf_bcn;
579};
580
581struct host_cmd_ds_802_11_mac_address {
582 __le16 action;
583 u8 mac_addr[ETH_ALEN];
584};
585
586struct host_cmd_ds_mac_control {
587 __le16 action;
588 __le16 reserved;
589};
590
591struct host_cmd_ds_mac_multicast_adr {
592 __le16 action;
593 __le16 num_of_adrs;
594 u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
595} __packed;
596
597struct host_cmd_ds_802_11_deauthenticate {
598 u8 mac_addr[ETH_ALEN];
599 __le16 reason_code;
600} __packed;
601
602struct host_cmd_ds_802_11_associate {
603 u8 peer_sta_addr[ETH_ALEN];
604 __le16 cap_info_bitmap;
605 __le16 listen_interval;
606 __le16 beacon_period;
607 u8 dtim_period;
608} __packed;
609
610struct ieee_types_assoc_rsp {
611 __le16 cap_info_bitmap;
612 __le16 status_code;
613 __le16 a_id;
614 u8 ie_buffer[1];
615} __packed;
616
617struct host_cmd_ds_802_11_associate_rsp {
618 struct ieee_types_assoc_rsp assoc_rsp;
619} __packed;
620
621struct ieee_types_cf_param_set {
622 u8 element_id;
623 u8 len;
624 u8 cfp_cnt;
625 u8 cfp_period;
626 u16 cfp_max_duration;
627 u16 cfp_duration_remaining;
628} __packed;
629
630struct ieee_types_ibss_param_set {
631 u8 element_id;
632 u8 len;
633 __le16 atim_window;
634} __packed;
635
636union ieee_types_ss_param_set {
637 struct ieee_types_cf_param_set cf_param_set;
638 struct ieee_types_ibss_param_set ibss_param_set;
639} __packed;
640
641struct ieee_types_fh_param_set {
642 u8 element_id;
643 u8 len;
644 __le16 dwell_time;
645 u8 hop_set;
646 u8 hop_pattern;
647 u8 hop_index;
648} __packed;
649
650struct ieee_types_ds_param_set {
651 u8 element_id;
652 u8 len;
653 u8 current_chan;
654} __packed;
655
656union ieee_types_phy_param_set {
657 struct ieee_types_fh_param_set fh_param_set;
658 struct ieee_types_ds_param_set ds_param_set;
659} __packed;
660
661struct host_cmd_ds_802_11_ad_hoc_start {
662 u8 ssid[IEEE80211_MAX_SSID_LEN];
663 u8 bss_mode;
664 __le16 beacon_period;
665 u8 dtim_period;
666 union ieee_types_ss_param_set ss_param_set;
667 union ieee_types_phy_param_set phy_param_set;
668 u16 reserved1;
669 __le16 cap_info_bitmap;
670 u8 DataRate[HOSTCMD_SUPPORTED_RATES];
671} __packed;
672
673struct host_cmd_ds_802_11_ad_hoc_result {
674 u8 pad[3];
675 u8 bssid[ETH_ALEN];
676} __packed;
677
678struct adhoc_bss_desc {
679 u8 bssid[ETH_ALEN];
680 u8 ssid[IEEE80211_MAX_SSID_LEN];
681 u8 bss_mode;
682 __le16 beacon_period;
683 u8 dtim_period;
684 u8 time_stamp[8];
685 u8 local_time[8];
686 union ieee_types_phy_param_set phy_param_set;
687 union ieee_types_ss_param_set ss_param_set;
688 __le16 cap_info_bitmap;
689 u8 data_rates[HOSTCMD_SUPPORTED_RATES];
690
691 /*
692 * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
693 * It is used in the Adhoc join command and will cause a
694 * binary layout mismatch with the firmware
695 */
696} __packed;
697
698struct host_cmd_ds_802_11_ad_hoc_join {
699 struct adhoc_bss_desc bss_descriptor;
700 u16 reserved1;
701 u16 reserved2;
702} __packed;
703
704struct host_cmd_ds_802_11_get_log {
705 __le32 mcast_tx_frame;
706 __le32 failed;
707 __le32 retry;
708 __le32 multi_retry;
709 __le32 frame_dup;
710 __le32 rts_success;
711 __le32 rts_failure;
712 __le32 ack_failure;
713 __le32 rx_frag;
714 __le32 mcast_rx_frame;
715 __le32 fcs_error;
716 __le32 tx_frame;
717 __le32 reserved;
718 __le32 wep_icv_err_cnt[4];
719};
720
721struct host_cmd_ds_tx_rate_query {
722 u8 tx_rate;
723 /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
724 * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
725 * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
726 u8 ht_info;
727} __packed;
728
729enum Host_Sleep_Action {
730 HS_CONFIGURE = 0x0001,
731 HS_ACTIVATE = 0x0002,
732};
733
734struct mwifiex_hs_config_param {
735 __le32 conditions;
736 u8 gpio;
737 u8 gap;
738} __packed;
739
740struct hs_activate_param {
741 u16 resp_ctrl;
742} __packed;
743
744struct host_cmd_ds_802_11_hs_cfg_enh {
745 __le16 action;
746
747 union {
748 struct mwifiex_hs_config_param hs_config;
749 struct hs_activate_param hs_activate;
750 } params;
751} __packed;
752
753enum SNMP_MIB_INDEX {
754 OP_RATE_SET_I = 1,
755 DTIM_PERIOD_I = 3,
756 RTS_THRESH_I = 5,
757 SHORT_RETRY_LIM_I = 6,
758 LONG_RETRY_LIM_I = 7,
759 FRAG_THRESH_I = 8,
760 DOT11D_I = 9,
761};
762
763#define MAX_SNMP_BUF_SIZE 128
764
765struct host_cmd_ds_802_11_snmp_mib {
766 __le16 query_type;
767 __le16 oid;
768 __le16 buf_size;
769 u8 value[1];
770} __packed;
771
772struct mwifiex_rate_scope {
773 __le16 type;
774 __le16 length;
775 __le16 hr_dsss_rate_bitmap;
776 __le16 ofdm_rate_bitmap;
777 __le16 ht_mcs_rate_bitmap[8];
778} __packed;
779
780struct mwifiex_rate_drop_pattern {
781 __le16 type;
782 __le16 length;
783 __le32 rate_drop_mode;
784} __packed;
785
786struct host_cmd_ds_tx_rate_cfg {
787 __le16 action;
788 __le16 cfg_index;
789} __packed;
790
791struct mwifiex_power_group {
792 u8 modulation_class;
793 u8 first_rate_code;
794 u8 last_rate_code;
795 s8 power_step;
796 s8 power_min;
797 s8 power_max;
798 u8 ht_bandwidth;
799 u8 reserved;
800} __packed;
801
802struct mwifiex_types_power_group {
803 u16 type;
804 u16 length;
805} __packed;
806
807struct host_cmd_ds_txpwr_cfg {
808 __le16 action;
809 __le16 cfg_index;
810 __le32 mode;
811} __packed;
812
813#define MWIFIEX_USER_SCAN_CHAN_MAX 50
814
815#define MWIFIEX_MAX_SSID_LIST_LENGTH 10
816
817struct mwifiex_scan_cmd_config {
818 /*
819 * BSS mode to be sent in the firmware command
820 */
821 u8 bss_mode;
822
823 /* Specific BSSID used to filter scan results in the firmware */
824 u8 specific_bssid[ETH_ALEN];
825
826 /* Length of TLVs sent in command starting at tlvBuffer */
827 u32 tlv_buf_len;
828
829 /*
830 * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
831 *
832 * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set
833 * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set
834 */
835 u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
836 here */
837} __packed;
838
839struct mwifiex_user_scan_chan {
840 u8 chan_number;
841 u8 radio_type;
842 u8 scan_type;
843 u8 reserved;
844 u32 scan_time;
845} __packed;
846
847struct mwifiex_user_scan_ssid {
848 u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
849 u8 max_len;
850} __packed;
851
852struct mwifiex_user_scan_cfg {
853 /*
854 * Flag set to keep the previous scan table intact
855 *
856 * If set, the scan results will accumulate, replacing any previous
857 * matched entries for a BSS with the new scan data
858 */
859 u8 keep_previous_scan;
860 /*
861 * BSS mode to be sent in the firmware command
862 */
863 u8 bss_mode;
864 /* Configure the number of probe requests for active chan scans */
865 u8 num_probes;
866 u8 reserved;
867 /* BSSID filter sent in the firmware command to limit the results */
868 u8 specific_bssid[ETH_ALEN];
869 /* SSID filter list used in the to limit the scan results */
870 struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH];
871 /* Variable number (fixed maximum) of channels to scan up */
872 struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
873} __packed;
874
875struct ie_body {
876 u8 grp_key_oui[4];
877 u8 ptk_cnt[2];
878 u8 ptk_body[4];
879} __packed;
880
881struct host_cmd_ds_802_11_scan {
882 u8 bss_mode;
883 u8 bssid[ETH_ALEN];
884 u8 tlv_buffer[1];
885} __packed;
886
887struct host_cmd_ds_802_11_scan_rsp {
888 __le16 bss_descript_size;
889 u8 number_of_sets;
890 u8 bss_desc_and_tlv_buffer[1];
891} __packed;
892
893struct host_cmd_ds_802_11_bg_scan_query {
894 u8 flush;
895} __packed;
896
897struct host_cmd_ds_802_11_bg_scan_query_rsp {
898 u32 report_condition;
899 struct host_cmd_ds_802_11_scan_rsp scan_resp;
900} __packed;
901
902struct mwifiex_ietypes_domain_param_set {
903 struct mwifiex_ie_types_header header;
904 u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
905 struct ieee80211_country_ie_triplet triplet[1];
906} __packed;
907
908struct host_cmd_ds_802_11d_domain_info {
909 __le16 action;
910 struct mwifiex_ietypes_domain_param_set domain;
911} __packed;
912
913struct host_cmd_ds_802_11d_domain_info_rsp {
914 __le16 action;
915 struct mwifiex_ietypes_domain_param_set domain;
916} __packed;
917
918struct host_cmd_ds_11n_addba_req {
919 u8 add_req_result;
920 u8 peer_mac_addr[ETH_ALEN];
921 u8 dialog_token;
922 __le16 block_ack_param_set;
923 __le16 block_ack_tmo;
924 __le16 ssn;
925} __packed;
926
927struct host_cmd_ds_11n_addba_rsp {
928 u8 add_rsp_result;
929 u8 peer_mac_addr[ETH_ALEN];
930 u8 dialog_token;
931 __le16 status_code;
932 __le16 block_ack_param_set;
933 __le16 block_ack_tmo;
934 __le16 ssn;
935} __packed;
936
937struct host_cmd_ds_11n_delba {
938 u8 del_result;
939 u8 peer_mac_addr[ETH_ALEN];
940 __le16 del_ba_param_set;
941 __le16 reason_code;
942 u8 reserved;
943} __packed;
944
945struct host_cmd_ds_11n_batimeout {
946 u8 tid;
947 u8 peer_mac_addr[ETH_ALEN];
948 u8 origninator;
949} __packed;
950
951struct host_cmd_ds_11n_cfg {
952 __le16 action;
953 __le16 ht_tx_cap;
954 __le16 ht_tx_info;
955} __packed;
956
957struct host_cmd_ds_txbuf_cfg {
958 __le16 action;
959 __le16 buff_size;
960 __le16 mp_end_port; /* SDIO only, reserved for other interfacces */
961 __le16 reserved3;
962} __packed;
963
964struct host_cmd_ds_amsdu_aggr_ctrl {
965 __le16 action;
966 __le16 enable;
967 __le16 curr_buf_size;
968} __packed;
969
970struct mwifiex_ie_types_wmm_param_set {
971 struct mwifiex_ie_types_header header;
972 u8 wmm_ie[1];
973};
974
975struct mwifiex_ie_types_wmm_queue_status {
976 struct mwifiex_ie_types_header header;
977 u8 queue_index;
978 u8 disabled;
979 u16 medium_time;
980 u8 flow_required;
981 u8 flow_created;
982 u32 reserved;
983};
984
985struct ieee_types_vendor_header {
986 u8 element_id;
987 u8 len;
988 u8 oui[3];
989 u8 oui_type;
990 u8 oui_subtype;
991 u8 version;
992} __packed;
993
994struct ieee_types_wmm_ac_parameters {
995 u8 aci_aifsn_bitmap;
996 u8 ecw_bitmap;
997 __le16 tx_op_limit;
998} __packed;
999
1000struct ieee_types_wmm_parameter {
1001 /*
1002 * WMM Parameter IE - Vendor Specific Header:
1003 * element_id [221/0xdd]
1004 * Len [24]
1005 * Oui [00:50:f2]
1006 * OuiType [2]
1007 * OuiSubType [1]
1008 * Version [1]
1009 */
1010 struct ieee_types_vendor_header vend_hdr;
1011 u8 qos_info_bitmap;
1012 u8 reserved;
1013 struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES];
1014} __packed;
1015
1016struct ieee_types_wmm_info {
1017
1018 /*
1019 * WMM Info IE - Vendor Specific Header:
1020 * element_id [221/0xdd]
1021 * Len [7]
1022 * Oui [00:50:f2]
1023 * OuiType [2]
1024 * OuiSubType [0]
1025 * Version [1]
1026 */
1027 struct ieee_types_vendor_header vend_hdr;
1028
1029 u8 qos_info_bitmap;
1030} __packed;
1031
1032struct host_cmd_ds_wmm_get_status {
1033 u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) *
1034 IEEE80211_MAX_QUEUES];
1035 u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2];
1036} __packed;
1037
1038struct mwifiex_wmm_ac_status {
1039 u8 disabled;
1040 u8 flow_required;
1041 u8 flow_created;
1042};
1043
1044struct mwifiex_ie_types_htcap {
1045 struct mwifiex_ie_types_header header;
1046 struct ieee80211_ht_cap ht_cap;
1047} __packed;
1048
1049struct mwifiex_ie_types_htinfo {
1050 struct mwifiex_ie_types_header header;
1051 struct ieee80211_ht_info ht_info;
1052} __packed;
1053
1054struct mwifiex_ie_types_2040bssco {
1055 struct mwifiex_ie_types_header header;
1056 u8 bss_co_2040;
1057} __packed;
1058
1059struct mwifiex_ie_types_extcap {
1060 struct mwifiex_ie_types_header header;
1061 u8 ext_cap;
1062} __packed;
1063
1064struct host_cmd_ds_mac_reg_access {
1065 __le16 action;
1066 __le16 offset;
1067 __le32 value;
1068} __packed;
1069
1070struct host_cmd_ds_bbp_reg_access {
1071 __le16 action;
1072 __le16 offset;
1073 u8 value;
1074 u8 reserved[3];
1075} __packed;
1076
1077struct host_cmd_ds_rf_reg_access {
1078 __le16 action;
1079 __le16 offset;
1080 u8 value;
1081 u8 reserved[3];
1082} __packed;
1083
1084struct host_cmd_ds_pmic_reg_access {
1085 __le16 action;
1086 __le16 offset;
1087 u8 value;
1088 u8 reserved[3];
1089} __packed;
1090
1091struct host_cmd_ds_802_11_eeprom_access {
1092 __le16 action;
1093
1094 __le16 offset;
1095 __le16 byte_count;
1096 u8 value;
1097} __packed;
1098
1099struct host_cmd_ds_802_11_rf_channel {
1100 __le16 action;
1101 __le16 current_channel;
1102 __le16 rf_type;
1103 __le16 reserved;
1104 u8 reserved_1[32];
1105} __packed;
1106
1107struct host_cmd_ds_version_ext {
1108 u8 version_str_sel;
1109 char version_str[128];
1110} __packed;
1111
1112struct host_cmd_ds_802_11_ibss_status {
1113 __le16 action;
1114 __le16 enable;
1115 u8 bssid[ETH_ALEN];
1116 __le16 beacon_interval;
1117 __le16 atim_window;
1118 __le16 use_g_rate_protect;
1119} __packed;
1120
1121#define CONNECTION_TYPE_INFRA 0
1122#define CONNECTION_TYPE_ADHOC 1
1123
1124struct host_cmd_ds_set_bss_mode {
1125 u8 con_type;
1126} __packed;
1127
1128struct host_cmd_ds_command {
1129 __le16 command;
1130 __le16 size;
1131 __le16 seq_num;
1132 __le16 result;
1133 union {
1134 struct host_cmd_ds_get_hw_spec hw_spec;
1135 struct host_cmd_ds_mac_control mac_ctrl;
1136 struct host_cmd_ds_802_11_mac_address mac_addr;
1137 struct host_cmd_ds_mac_multicast_adr mc_addr;
1138 struct host_cmd_ds_802_11_get_log get_log;
1139 struct host_cmd_ds_802_11_rssi_info rssi_info;
1140 struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp;
1141 struct host_cmd_ds_802_11_snmp_mib smib;
1142 struct host_cmd_ds_802_11_rf_channel rf_channel;
1143 struct host_cmd_ds_tx_rate_query tx_rate;
1144 struct host_cmd_ds_tx_rate_cfg tx_rate_cfg;
1145 struct host_cmd_ds_txpwr_cfg txp_cfg;
1146 struct host_cmd_ds_802_11_ps_mode_enh psmode_enh;
1147 struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg;
1148 struct host_cmd_ds_802_11_scan scan;
1149 struct host_cmd_ds_802_11_scan_rsp scan_resp;
1150 struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
1151 struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
1152 struct host_cmd_ds_802_11_associate associate;
1153 struct host_cmd_ds_802_11_associate_rsp associate_rsp;
1154 struct host_cmd_ds_802_11_deauthenticate deauth;
1155 struct host_cmd_ds_802_11_ad_hoc_start adhoc_start;
1156 struct host_cmd_ds_802_11_ad_hoc_result adhoc_result;
1157 struct host_cmd_ds_802_11_ad_hoc_join adhoc_join;
1158 struct host_cmd_ds_802_11d_domain_info domain_info;
1159 struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp;
1160 struct host_cmd_ds_11n_addba_req add_ba_req;
1161 struct host_cmd_ds_11n_addba_rsp add_ba_rsp;
1162 struct host_cmd_ds_11n_delba del_ba;
1163 struct host_cmd_ds_txbuf_cfg tx_buf;
1164 struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl;
1165 struct host_cmd_ds_11n_cfg htcfg;
1166 struct host_cmd_ds_wmm_get_status get_wmm_status;
1167 struct host_cmd_ds_802_11_key_material key_material;
1168 struct host_cmd_ds_version_ext verext;
1169 struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
1170 struct host_cmd_ds_mac_reg_access mac_reg;
1171 struct host_cmd_ds_bbp_reg_access bbp_reg;
1172 struct host_cmd_ds_rf_reg_access rf_reg;
1173 struct host_cmd_ds_pmic_reg_access pmic_reg;
1174 struct host_cmd_ds_set_bss_mode bss_mode;
1175 struct host_cmd_ds_802_11_eeprom_access eeprom;
1176 } params;
1177} __packed;
1178
1179struct mwifiex_opt_sleep_confirm {
1180 __le16 command;
1181 __le16 size;
1182 __le16 seq_num;
1183 __le16 result;
1184 __le16 action;
1185 __le16 resp_ctrl;
1186} __packed;
1187#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..3f1559e61320
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -0,0 +1,645 @@
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 unsigned long flags;
39
40 bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
41 if (!bss_prio) {
42 dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
43 __func__);
44 return -ENOMEM;
45 }
46
47 bss_prio->priv = priv;
48 INIT_LIST_HEAD(&bss_prio->list);
49 if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur)
50 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
51 bss_prio;
52
53 spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority]
54 .bss_prio_lock, flags);
55 list_add_tail(&bss_prio->list,
56 &adapter->bss_prio_tbl[priv->bss_priority]
57 .bss_prio_head);
58 spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority]
59 .bss_prio_lock, flags);
60
61 return 0;
62}
63
64/*
65 * This function initializes the private structure and sets default
66 * values to the members.
67 *
68 * Additionally, it also initializes all the locks and sets up all the
69 * lists.
70 */
71static int mwifiex_init_priv(struct mwifiex_private *priv)
72{
73 u32 i;
74
75 priv->media_connected = false;
76 memset(priv->curr_addr, 0xff, ETH_ALEN);
77
78 priv->pkt_tx_ctrl = 0;
79 priv->bss_mode = NL80211_IFTYPE_STATION;
80 priv->data_rate = 0; /* Initially indicate the rate as auto */
81 priv->is_data_rate_auto = true;
82 priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
83 priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
84
85 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
86 priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
87 priv->sec_info.encryption_mode = 0;
88 for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
89 memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key));
90 priv->wep_key_curr_index = 0;
91 priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
92 HostCmd_ACT_MAC_ETHERNETII_ENABLE;
93
94 priv->beacon_period = 100; /* beacon interval */ ;
95 priv->attempted_bss_desc = NULL;
96 memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
97 priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL;
98
99 memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid));
100 memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid));
101 memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
102 priv->assoc_rsp_size = 0;
103 priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
104 priv->atim_window = 0;
105 priv->adhoc_state = ADHOC_IDLE;
106 priv->tx_power_level = 0;
107 priv->max_tx_power_level = 0;
108 priv->min_tx_power_level = 0;
109 priv->tx_rate = 0;
110 priv->rxpd_htinfo = 0;
111 priv->rxpd_rate = 0;
112 priv->rate_bitmap = 0;
113 priv->data_rssi_last = 0;
114 priv->data_rssi_avg = 0;
115 priv->data_nf_avg = 0;
116 priv->data_nf_last = 0;
117 priv->bcn_rssi_last = 0;
118 priv->bcn_rssi_avg = 0;
119 priv->bcn_nf_avg = 0;
120 priv->bcn_nf_last = 0;
121 memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie));
122 memset(&priv->aes_key, 0, sizeof(priv->aes_key));
123 priv->wpa_ie_len = 0;
124 priv->wpa_is_gtk_set = false;
125
126 memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf));
127 priv->assoc_tlv_buf_len = 0;
128 memset(&priv->wps, 0, sizeof(priv->wps));
129 memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
130 priv->gen_ie_buf_len = 0;
131 memset(priv->vs_ie, 0, sizeof(priv->vs_ie));
132
133 priv->wmm_required = true;
134 priv->wmm_enabled = false;
135 priv->wmm_qosinfo = 0;
136 priv->curr_bcn_buf = NULL;
137 priv->curr_bcn_size = 0;
138
139 priv->scan_block = false;
140
141 return mwifiex_add_bss_prio_tbl(priv);
142}
143
144/*
145 * This function allocates buffers for members of the adapter
146 * structure.
147 *
148 * The memory allocated includes scan table, command buffers, and
149 * sleep confirm command buffer. In addition, the queues are
150 * also initialized.
151 */
152static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
153{
154 int ret;
155 u32 buf_size;
156 struct mwifiex_bssdescriptor *temp_scan_table;
157
158 /* Allocate buffer to store the BSSID list */
159 buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP;
160 temp_scan_table = kzalloc(buf_size, GFP_KERNEL);
161 if (!temp_scan_table) {
162 dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
163 __func__);
164 return -ENOMEM;
165 }
166
167 adapter->scan_table = temp_scan_table;
168
169 /* Allocate command buffer */
170 ret = mwifiex_alloc_cmd_buffer(adapter);
171 if (ret) {
172 dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
173 __func__);
174 return -1;
175 }
176
177 adapter->sleep_cfm =
178 dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm)
179 + INTF_HEADER_LEN);
180
181 if (!adapter->sleep_cfm) {
182 dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
183 " cmd buffer\n", __func__);
184 return -1;
185 }
186 skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
187
188 return 0;
189}
190
191/*
192 * This function initializes the adapter structure and sets default
193 * values to the members of adapter.
194 *
195 * This also initializes the WMM related parameters in the driver private
196 * structures.
197 */
198static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
199{
200 struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL;
201
202 skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm));
203 sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
204 (adapter->sleep_cfm->data);
205
206 adapter->cmd_sent = false;
207 adapter->data_sent = true;
208 adapter->cmd_resp_received = false;
209 adapter->event_received = false;
210 adapter->data_received = false;
211
212 adapter->surprise_removed = false;
213
214 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
215
216 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
217 adapter->ps_state = PS_STATE_AWAKE;
218 adapter->need_to_wakeup = false;
219
220 adapter->scan_mode = HostCmd_BSS_MODE_ANY;
221 adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
222 adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
223 adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
224
225 adapter->num_in_scan_table = 0;
226 memset(adapter->scan_table, 0,
227 (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP));
228 adapter->scan_probes = 1;
229
230 memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf));
231 adapter->bcn_buf_end = adapter->bcn_buf;
232
233 adapter->multiple_dtim = 1;
234
235 adapter->local_listen_interval = 0; /* default value in firmware
236 will be used */
237
238 adapter->is_deep_sleep = false;
239
240 adapter->delay_null_pkt = false;
241 adapter->delay_to_ps = 1000;
242 adapter->enhanced_ps_mode = PS_MODE_AUTO;
243
244 adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by
245 default */
246 adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by
247 default */
248 adapter->pm_wakeup_card_req = false;
249
250 adapter->pm_wakeup_fw_try = false;
251
252 adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
253 adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
254 adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
255
256 adapter->is_hs_configured = false;
257 adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
258 adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
259 adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
260 adapter->hs_activated = false;
261
262 memset(adapter->event_body, 0, sizeof(adapter->event_body));
263 adapter->hw_dot_11n_dev_cap = 0;
264 adapter->hw_dev_mcs_support = 0;
265 adapter->chan_offset = 0;
266 adapter->adhoc_11n_enabled = false;
267
268 mwifiex_wmm_init(adapter);
269
270 if (adapter->sleep_cfm) {
271 memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len);
272 sleep_cfm_buf->command =
273 cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
274 sleep_cfm_buf->size =
275 cpu_to_le16(adapter->sleep_cfm->len);
276 sleep_cfm_buf->result = 0;
277 sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM);
278 sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED);
279 }
280 memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
281 memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
282 adapter->tx_lock_flag = false;
283 adapter->null_pkt_interval = 0;
284 adapter->fw_bands = 0;
285 adapter->config_bands = 0;
286 adapter->adhoc_start_band = 0;
287 adapter->scan_channels = NULL;
288 adapter->fw_release_number = 0;
289 adapter->fw_cap_info = 0;
290 memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf));
291 adapter->event_cause = 0;
292 adapter->region_code = 0;
293 adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
294 adapter->adhoc_awake_period = 0;
295 memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
296 adapter->arp_filter_size = 0;
297}
298
299/*
300 * This function frees the adapter structure.
301 *
302 * The freeing operation is done recursively, by canceling all
303 * pending commands, freeing the member buffers previously
304 * allocated (command buffers, scan table buffer, sleep confirm
305 * command buffer), stopping the timers and calling the cleanup
306 * routines for every interface, before the actual adapter
307 * structure is freed.
308 */
309static void
310mwifiex_free_adapter(struct mwifiex_adapter *adapter)
311{
312 if (!adapter) {
313 pr_err("%s: adapter is NULL\n", __func__);
314 return;
315 }
316
317 mwifiex_cancel_all_pending_cmd(adapter);
318
319 /* Free lock variables */
320 mwifiex_free_lock_list(adapter);
321
322 /* Free command buffer */
323 dev_dbg(adapter->dev, "info: free cmd buffer\n");
324 mwifiex_free_cmd_buffer(adapter);
325
326 del_timer(&adapter->cmd_timer);
327
328 dev_dbg(adapter->dev, "info: free scan table\n");
329 kfree(adapter->scan_table);
330 adapter->scan_table = NULL;
331
332 adapter->if_ops.cleanup_if(adapter);
333
334 dev_kfree_skb_any(adapter->sleep_cfm);
335}
336
337/*
338 * This function intializes the lock variables and
339 * the list heads.
340 */
341int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
342{
343 struct mwifiex_private *priv;
344 s32 i, j;
345
346 spin_lock_init(&adapter->mwifiex_lock);
347 spin_lock_init(&adapter->int_lock);
348 spin_lock_init(&adapter->main_proc_lock);
349 spin_lock_init(&adapter->mwifiex_cmd_lock);
350 for (i = 0; i < adapter->priv_num; i++) {
351 if (adapter->priv[i]) {
352 priv = adapter->priv[i];
353 spin_lock_init(&priv->rx_pkt_lock);
354 spin_lock_init(&priv->wmm.ra_list_spinlock);
355 spin_lock_init(&priv->curr_bcn_buf_lock);
356 }
357 }
358
359 /* Initialize cmd_free_q */
360 INIT_LIST_HEAD(&adapter->cmd_free_q);
361 /* Initialize cmd_pending_q */
362 INIT_LIST_HEAD(&adapter->cmd_pending_q);
363 /* Initialize scan_pending_q */
364 INIT_LIST_HEAD(&adapter->scan_pending_q);
365
366 spin_lock_init(&adapter->cmd_free_q_lock);
367 spin_lock_init(&adapter->cmd_pending_q_lock);
368 spin_lock_init(&adapter->scan_pending_q_lock);
369
370 for (i = 0; i < adapter->priv_num; ++i) {
371 INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
372 adapter->bss_prio_tbl[i].bss_prio_cur = NULL;
373 spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock);
374 }
375
376 for (i = 0; i < adapter->priv_num; i++) {
377 if (!adapter->priv[i])
378 continue;
379 priv = adapter->priv[i];
380 for (j = 0; j < MAX_NUM_TID; ++j) {
381 INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
382 spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
383 }
384 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
385 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
386
387 spin_lock_init(&priv->tx_ba_stream_tbl_lock);
388 spin_lock_init(&priv->rx_reorder_tbl_lock);
389 }
390
391 return 0;
392}
393
394/*
395 * This function releases the lock variables and frees the locks and
396 * associated locks.
397 */
398void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
399{
400 struct mwifiex_private *priv;
401 s32 i, j;
402
403 /* Free lists */
404 list_del(&adapter->cmd_free_q);
405 list_del(&adapter->cmd_pending_q);
406 list_del(&adapter->scan_pending_q);
407
408 for (i = 0; i < adapter->priv_num; i++)
409 list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
410
411 for (i = 0; i < adapter->priv_num; i++) {
412 if (adapter->priv[i]) {
413 priv = adapter->priv[i];
414 for (j = 0; j < MAX_NUM_TID; ++j)
415 list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
416 list_del(&priv->tx_ba_stream_tbl_ptr);
417 list_del(&priv->rx_reorder_tbl_ptr);
418 }
419 }
420}
421
422/*
423 * This function initializes the firmware.
424 *
425 * The following operations are performed sequentially -
426 * - Allocate adapter structure
427 * - Initialize the adapter structure
428 * - Initialize the private structure
429 * - Add BSS priority tables to the adapter structure
430 * - For each interface, send the init commands to firmware
431 * - Send the first command in command pending queue, if available
432 */
433int mwifiex_init_fw(struct mwifiex_adapter *adapter)
434{
435 int ret;
436 struct mwifiex_private *priv;
437 u8 i, first_sta = true;
438 int is_cmd_pend_q_empty;
439 unsigned long flags;
440
441 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
442
443 /* Allocate memory for member of adapter structure */
444 ret = mwifiex_allocate_adapter(adapter);
445 if (ret)
446 return -1;
447
448 /* Initialize adapter structure */
449 mwifiex_init_adapter(adapter);
450
451 for (i = 0; i < adapter->priv_num; i++) {
452 if (adapter->priv[i]) {
453 priv = adapter->priv[i];
454
455 /* Initialize private structure */
456 ret = mwifiex_init_priv(priv);
457 if (ret)
458 return -1;
459 }
460 }
461 for (i = 0; i < adapter->priv_num; i++) {
462 if (adapter->priv[i]) {
463 ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
464 if (ret == -1)
465 return -1;
466
467 first_sta = false;
468 }
469 }
470
471 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
472 is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
473 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
474 if (!is_cmd_pend_q_empty) {
475 /* Send the first command in queue and return */
476 if (mwifiex_main_process(adapter) != -1)
477 ret = -EINPROGRESS;
478 } else {
479 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
480 }
481
482 return ret;
483}
484
485/*
486 * This function deletes the BSS priority tables.
487 *
488 * The function traverses through all the allocated BSS priority nodes
489 * in every BSS priority table and frees them.
490 */
491static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
492{
493 int i;
494 struct mwifiex_adapter *adapter = priv->adapter;
495 struct mwifiex_bss_prio_node *bssprio_node, *tmp_node, **cur;
496 struct list_head *head;
497 spinlock_t *lock;
498 unsigned long flags;
499
500 for (i = 0; i < adapter->priv_num; ++i) {
501 head = &adapter->bss_prio_tbl[i].bss_prio_head;
502 cur = &adapter->bss_prio_tbl[i].bss_prio_cur;
503 lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
504 dev_dbg(adapter->dev, "info: delete BSS priority table,"
505 " index = %d, i = %d, head = %p, cur = %p\n",
506 priv->bss_index, i, head, *cur);
507 if (*cur) {
508 spin_lock_irqsave(lock, flags);
509 if (list_empty(head)) {
510 spin_unlock_irqrestore(lock, flags);
511 continue;
512 }
513 bssprio_node = list_first_entry(head,
514 struct mwifiex_bss_prio_node, list);
515 spin_unlock_irqrestore(lock, flags);
516
517 list_for_each_entry_safe(bssprio_node, tmp_node, head,
518 list) {
519 if (bssprio_node->priv == priv) {
520 dev_dbg(adapter->dev, "info: Delete "
521 "node %p, next = %p\n",
522 bssprio_node, tmp_node);
523 spin_lock_irqsave(lock, flags);
524 list_del(&bssprio_node->list);
525 spin_unlock_irqrestore(lock, flags);
526 kfree(bssprio_node);
527 }
528 }
529 *cur = (struct mwifiex_bss_prio_node *)head;
530 }
531 }
532}
533
534/*
535 * This function is used to shutdown the driver.
536 *
537 * The following operations are performed sequentially -
538 * - Check if already shut down
539 * - Make sure the main process has stopped
540 * - Clean up the Tx and Rx queues
541 * - Delete BSS priority tables
542 * - Free the adapter
543 * - Notify completion
544 */
545int
546mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
547{
548 int ret = -EINPROGRESS;
549 struct mwifiex_private *priv;
550 s32 i;
551 unsigned long flags;
552
553 /* mwifiex already shutdown */
554 if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)
555 return 0;
556
557 adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
558 /* wait for mwifiex_process to complete */
559 if (adapter->mwifiex_processing) {
560 dev_warn(adapter->dev, "main process is still running\n");
561 return ret;
562 }
563
564 /* shut down mwifiex */
565 dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
566
567 /* Clean up Tx/Rx queues and delete BSS priority table */
568 for (i = 0; i < adapter->priv_num; i++) {
569 if (adapter->priv[i]) {
570 priv = adapter->priv[i];
571
572 mwifiex_clean_txrx(priv);
573 mwifiex_delete_bss_prio_tbl(priv);
574 }
575 }
576
577 spin_lock_irqsave(&adapter->mwifiex_lock, flags);
578
579 /* Free adapter structure */
580 mwifiex_free_adapter(adapter);
581
582 spin_unlock_irqrestore(&adapter->mwifiex_lock, flags);
583
584 /* Notify completion */
585 ret = mwifiex_shutdown_fw_complete(adapter);
586
587 return ret;
588}
589
590/*
591 * This function downloads the firmware to the card.
592 *
593 * The actual download is preceded by two sanity checks -
594 * - Check if firmware is already running
595 * - Check if the interface is the winner to download the firmware
596 *
597 * ...and followed by another -
598 * - Check if the firmware is downloaded successfully
599 *
600 * After download is successfully completed, the host interrupts are enabled.
601 */
602int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
603 struct mwifiex_fw_image *pmfw)
604{
605 int ret, winner;
606 u32 poll_num = 1;
607
608 /* Check if firmware is already running */
609 ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
610 if (!ret) {
611 dev_notice(adapter->dev,
612 "WLAN FW already running! Skip FW download\n");
613 goto done;
614 }
615 poll_num = MAX_FIRMWARE_POLL_TRIES;
616
617 /* Check if we are the winner for downloading FW */
618 if (!winner) {
619 dev_notice(adapter->dev,
620 "Other interface already running!"
621 " Skip FW download\n");
622 poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
623 goto poll_fw;
624 }
625 if (pmfw) {
626 /* Download firmware with helper */
627 ret = adapter->if_ops.prog_fw(adapter, pmfw);
628 if (ret) {
629 dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
630 return ret;
631 }
632 }
633
634poll_fw:
635 /* Check if the firmware is downloaded successfully or not */
636 ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
637 if (ret) {
638 dev_err(adapter->dev, "FW failed to be active in time\n");
639 return -1;
640 }
641done:
642 /* re-enable host interrupt for mwifiex after fw dnld is successful */
643 adapter->if_ops.enable_int(adapter);
644 return ret;
645}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
new file mode 100644
index 000000000000..7c1c5ee40eb9
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -0,0 +1,331 @@
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_TYPE_UNCHANGED = 0,
27 MWIFIEX_SCAN_TYPE_ACTIVE,
28 MWIFIEX_SCAN_TYPE_PASSIVE
29};
30
31struct mwifiex_user_scan {
32 u32 scan_cfg_len;
33 u8 scan_cfg_buf[1];
34};
35
36#define MWIFIEX_PROMISC_MODE 1
37#define MWIFIEX_MULTICAST_MODE 2
38#define MWIFIEX_ALL_MULTI_MODE 4
39#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32
40
41struct mwifiex_multicast_list {
42 u32 mode;
43 u32 num_multicast_addr;
44 u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
45};
46
47struct mwifiex_chan_freq {
48 u32 channel;
49 u32 freq;
50};
51
52struct mwifiex_ssid_bssid {
53 struct mwifiex_802_11_ssid ssid;
54 u8 bssid[ETH_ALEN];
55};
56
57enum {
58 BAND_B = 1,
59 BAND_G = 2,
60 BAND_A = 4,
61 BAND_GN = 8,
62 BAND_AN = 16,
63};
64
65#define NO_SEC_CHANNEL 0
66#define SEC_CHANNEL_ABOVE 1
67#define SEC_CHANNEL_BELOW 3
68
69struct mwifiex_ds_band_cfg {
70 u32 config_bands;
71 u32 adhoc_start_band;
72 u32 adhoc_channel;
73 u32 sec_chan_offset;
74};
75
76enum {
77 ADHOC_IDLE,
78 ADHOC_STARTED,
79 ADHOC_JOINED,
80 ADHOC_COALESCED
81};
82
83struct mwifiex_ds_get_stats {
84 u32 mcast_tx_frame;
85 u32 failed;
86 u32 retry;
87 u32 multi_retry;
88 u32 frame_dup;
89 u32 rts_success;
90 u32 rts_failure;
91 u32 ack_failure;
92 u32 rx_frag;
93 u32 mcast_rx_frame;
94 u32 fcs_error;
95 u32 tx_frame;
96 u32 wep_icv_error[4];
97};
98
99#define BCN_RSSI_AVG_MASK 0x00000002
100#define BCN_NF_AVG_MASK 0x00000200
101#define ALL_RSSI_INFO_MASK 0x00000fff
102
103struct mwifiex_ds_get_signal {
104 /*
105 * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
106 * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
107 * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
108 * Bit6: Last Data SNR, Bit7: Average Data SNR,
109 * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
110 * Bit10: Last Data NF, Bit11: Average Data NF
111 */
112 u16 selector;
113 s16 bcn_rssi_last;
114 s16 bcn_rssi_avg;
115 s16 data_rssi_last;
116 s16 data_rssi_avg;
117 s16 bcn_snr_last;
118 s16 bcn_snr_avg;
119 s16 data_snr_last;
120 s16 data_snr_avg;
121 s16 bcn_nf_last;
122 s16 bcn_nf_avg;
123 s16 data_nf_last;
124 s16 data_nf_avg;
125};
126
127#define MWIFIEX_MAX_VER_STR_LEN 128
128
129struct mwifiex_ver_ext {
130 u32 version_str_sel;
131 char version_str[MWIFIEX_MAX_VER_STR_LEN];
132};
133
134struct mwifiex_bss_info {
135 u32 bss_mode;
136 struct mwifiex_802_11_ssid ssid;
137 u32 scan_table_idx;
138 u32 bss_chan;
139 u32 region_code;
140 u32 media_connected;
141 u32 max_power_level;
142 u32 min_power_level;
143 u32 adhoc_state;
144 signed int bcn_nf_last;
145 u32 wep_status;
146 u32 is_hs_configured;
147 u32 is_deep_sleep;
148 u8 bssid[ETH_ALEN];
149};
150
151#define MAX_NUM_TID 8
152
153#define MAX_RX_WINSIZE 64
154
155struct mwifiex_ds_rx_reorder_tbl {
156 u16 tid;
157 u8 ta[ETH_ALEN];
158 u32 start_win;
159 u32 win_size;
160 u32 buffer[MAX_RX_WINSIZE];
161};
162
163struct mwifiex_ds_tx_ba_stream_tbl {
164 u16 tid;
165 u8 ra[ETH_ALEN];
166};
167
168#define DBG_CMD_NUM 5
169
170struct mwifiex_debug_info {
171 u32 int_counter;
172 u32 packets_out[MAX_NUM_TID];
173 u32 max_tx_buf_size;
174 u32 tx_buf_size;
175 u32 curr_tx_buf_size;
176 u32 tx_tbl_num;
177 struct mwifiex_ds_tx_ba_stream_tbl
178 tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED];
179 u32 rx_tbl_num;
180 struct mwifiex_ds_rx_reorder_tbl rx_tbl
181 [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED];
182 u16 ps_mode;
183 u32 ps_state;
184 u8 is_deep_sleep;
185 u8 pm_wakeup_card_req;
186 u32 pm_wakeup_fw_try;
187 u8 is_hs_configured;
188 u8 hs_activated;
189 u32 num_cmd_host_to_card_failure;
190 u32 num_cmd_sleep_cfm_host_to_card_failure;
191 u32 num_tx_host_to_card_failure;
192 u32 num_event_deauth;
193 u32 num_event_disassoc;
194 u32 num_event_link_lost;
195 u32 num_cmd_deauth;
196 u32 num_cmd_assoc_success;
197 u32 num_cmd_assoc_failure;
198 u32 num_tx_timeout;
199 u32 num_cmd_timeout;
200 u16 timeout_cmd_id;
201 u16 timeout_cmd_act;
202 u16 last_cmd_id[DBG_CMD_NUM];
203 u16 last_cmd_act[DBG_CMD_NUM];
204 u16 last_cmd_index;
205 u16 last_cmd_resp_id[DBG_CMD_NUM];
206 u16 last_cmd_resp_index;
207 u16 last_event[DBG_CMD_NUM];
208 u16 last_event_index;
209 u8 data_sent;
210 u8 cmd_sent;
211 u8 cmd_resp_received;
212 u8 event_received;
213};
214
215#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000
216#define WAPI_RXPN_LEN 16
217
218struct mwifiex_ds_encrypt_key {
219 u32 key_disable;
220 u32 key_index;
221 u32 key_len;
222 u8 key_material[WLAN_MAX_KEY_LEN];
223 u8 mac_addr[ETH_ALEN];
224 u32 is_wapi_key;
225 u8 wapi_rxpn[WAPI_RXPN_LEN];
226};
227
228struct mwifiex_rate_cfg {
229 u32 action;
230 u32 is_rate_auto;
231 u32 rate;
232};
233
234struct mwifiex_power_cfg {
235 u32 is_power_auto;
236 u32 power_level;
237};
238
239struct mwifiex_ds_hs_cfg {
240 u32 is_invoke_hostcmd;
241 /* Bit0: non-unicast data
242 * Bit1: unicast data
243 * Bit2: mac events
244 * Bit3: magic packet
245 */
246 u32 conditions;
247 u32 gpio;
248 u32 gap;
249};
250
251#define DEEP_SLEEP_ON 1
252#define DEEP_SLEEP_IDLE_TIME 100
253#define PS_MODE_AUTO 1
254
255struct mwifiex_ds_auto_ds {
256 u16 auto_ds;
257 u16 idle_time;
258};
259
260struct mwifiex_ds_pm_cfg {
261 union {
262 u32 ps_mode;
263 struct mwifiex_ds_hs_cfg hs_cfg;
264 struct mwifiex_ds_auto_ds auto_deep_sleep;
265 u32 sleep_period;
266 } param;
267};
268
269struct mwifiex_ds_11n_tx_cfg {
270 u16 tx_htcap;
271 u16 tx_htinfo;
272};
273
274struct mwifiex_ds_11n_amsdu_aggr_ctrl {
275 u16 enable;
276 u16 curr_buf_size;
277};
278
279#define MWIFIEX_NUM_OF_CMD_BUFFER 20
280#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048
281
282enum {
283 MWIFIEX_IE_TYPE_GEN_IE = 0,
284 MWIFIEX_IE_TYPE_ARP_FILTER,
285};
286
287enum {
288 MWIFIEX_REG_MAC = 1,
289 MWIFIEX_REG_BBP,
290 MWIFIEX_REG_RF,
291 MWIFIEX_REG_PMIC,
292 MWIFIEX_REG_CAU,
293};
294
295struct mwifiex_ds_reg_rw {
296 __le32 type;
297 __le32 offset;
298 __le32 value;
299};
300
301#define MAX_EEPROM_DATA 256
302
303struct mwifiex_ds_read_eeprom {
304 __le16 offset;
305 __le16 byte_count;
306 u8 value[MAX_EEPROM_DATA];
307};
308
309struct mwifiex_ds_misc_gen_ie {
310 u32 type;
311 u32 len;
312 u8 ie_data[IW_CUSTOM_MAX];
313};
314
315struct mwifiex_ds_misc_cmd {
316 u32 len;
317 u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER];
318};
319
320#define MWIFIEX_MAX_VSIE_LEN (256)
321#define MWIFIEX_MAX_VSIE_NUM (8)
322#define MWIFIEX_VSIE_MASK_SCAN 0x01
323#define MWIFIEX_VSIE_MASK_ASSOC 0x02
324#define MWIFIEX_VSIE_MASK_ADHOC 0x04
325
326enum {
327 MWIFIEX_FUNC_INIT = 1,
328 MWIFIEX_FUNC_SHUTDOWN,
329};
330
331#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..5eab3dc29b1c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -0,0 +1,1423 @@
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 __le64 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 /* TSF at the time when beacon/probe_response was received */
120 tsf_val = cpu_to_le64(bss_desc->network_tsf);
121 memcpy(*buffer, &tsf_val, sizeof(tsf_val));
122 *buffer += sizeof(tsf_val);
123
124 memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val));
125
126 dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - "
127 "%016llx\n", __func__, tsf_val, bss_desc->network_tsf);
128
129 memcpy(*buffer, &tsf_val, sizeof(tsf_val));
130 *buffer += sizeof(tsf_val);
131
132 return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
133}
134
135/*
136 * This function finds out the common rates between rate1 and rate2.
137 *
138 * It will fill common rates in rate1 as output if found.
139 *
140 * NOTE: Setting the MSB of the basic rates needs to be taken
141 * care of, either before or after calling this function.
142 */
143static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
144 u32 rate1_size, u8 *rate2, u32 rate2_size)
145{
146 int ret;
147 u8 *ptr = rate1, *tmp;
148 u32 i, j;
149
150 tmp = kmalloc(rate1_size, GFP_KERNEL);
151 if (!tmp) {
152 dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
153 return -ENOMEM;
154 }
155
156 memcpy(tmp, rate1, rate1_size);
157 memset(rate1, 0, rate1_size);
158
159 for (i = 0; rate2[i] && i < rate2_size; i++) {
160 for (j = 0; tmp[j] && j < rate1_size; j++) {
161 /* Check common rate, excluding the bit for
162 basic rate */
163 if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
164 *rate1++ = tmp[j];
165 break;
166 }
167 }
168 }
169
170 dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n",
171 priv->data_rate);
172
173 if (!priv->is_data_rate_auto) {
174 while (*ptr) {
175 if ((*ptr & 0x7f) == priv->data_rate) {
176 ret = 0;
177 goto done;
178 }
179 ptr++;
180 }
181 dev_err(priv->adapter->dev, "previously set fixed data rate %#x"
182 " is not compatible with the network\n",
183 priv->data_rate);
184
185 ret = -1;
186 goto done;
187 }
188
189 ret = 0;
190done:
191 kfree(tmp);
192 return ret;
193}
194
195/*
196 * This function creates the intersection of the rates supported by a
197 * target BSS and our adapter settings for use in an assoc/join command.
198 */
199static int
200mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
201 struct mwifiex_bssdescriptor *bss_desc,
202 u8 *out_rates, u32 *out_rates_size)
203{
204 u8 card_rates[MWIFIEX_SUPPORTED_RATES];
205 u32 card_rates_size;
206
207 /* Copy AP supported rates */
208 memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
209 /* Get the STA supported rates */
210 card_rates_size = mwifiex_get_active_data_rates(priv, card_rates);
211 /* Get the common rates between AP and STA supported rates */
212 if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
213 card_rates, card_rates_size)) {
214 *out_rates_size = 0;
215 dev_err(priv->adapter->dev, "%s: cannot get common rates\n",
216 __func__);
217 return -1;
218 }
219
220 *out_rates_size =
221 min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES);
222
223 return 0;
224}
225
226/*
227 * This function updates the scan entry TSF timestamps to reflect
228 * a new association.
229 */
230static void
231mwifiex_update_tsf_timestamps(struct mwifiex_private *priv,
232 struct mwifiex_bssdescriptor *new_bss_desc)
233{
234 struct mwifiex_adapter *adapter = priv->adapter;
235 u32 table_idx;
236 long long new_tsf_base;
237 signed long long tsf_delta;
238
239 memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base));
240
241 tsf_delta = new_tsf_base - new_bss_desc->network_tsf;
242
243 dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, "
244 "0x%016llx -> 0x%016llx\n",
245 new_bss_desc->network_tsf, new_tsf_base);
246
247 for (table_idx = 0; table_idx < adapter->num_in_scan_table;
248 table_idx++)
249 adapter->scan_table[table_idx].network_tsf += tsf_delta;
250}
251
252/*
253 * This function appends a WAPI IE.
254 *
255 * This function is called from the network join command preparation routine.
256 *
257 * If the IE buffer has been setup by the application, this routine appends
258 * the buffer as a WAPI TLV type to the request.
259 */
260static int
261mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
262{
263 int retLen = 0;
264 struct mwifiex_ie_types_header ie_header;
265
266 /* Null Checks */
267 if (buffer == NULL)
268 return 0;
269 if (*buffer == NULL)
270 return 0;
271
272 /*
273 * If there is a wapi ie buffer setup, append it to the return
274 * parameter buffer pointer.
275 */
276 if (priv->wapi_ie_len) {
277 dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n",
278 priv->wapi_ie_len, *buffer);
279
280 /* Wrap the generic IE buffer with a pass through TLV type */
281 ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
282 ie_header.len = cpu_to_le16(priv->wapi_ie_len);
283 memcpy(*buffer, &ie_header, sizeof(ie_header));
284
285 /* Increment the return size and the return buffer pointer
286 param */
287 *buffer += sizeof(ie_header);
288 retLen += sizeof(ie_header);
289
290 /* Copy the wapi IE buffer to the output buffer, advance
291 pointer */
292 memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len);
293
294 /* Increment the return size and the return buffer pointer
295 param */
296 *buffer += priv->wapi_ie_len;
297 retLen += priv->wapi_ie_len;
298
299 }
300 /* return the length appended to the buffer */
301 return retLen;
302}
303
304/*
305 * This function appends rsn ie tlv for wpa/wpa2 security modes.
306 * It is called from the network join command preparation routine.
307 */
308static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv,
309 u8 **buffer)
310{
311 struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv;
312 int rsn_ie_len;
313
314 if (!buffer || !(*buffer))
315 return 0;
316
317 rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer);
318 rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]);
319 rsn_ie_tlv->header.type = cpu_to_le16(
320 le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF);
321 rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]);
322 rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len)
323 & 0x00FF);
324 if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2))
325 memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2],
326 le16_to_cpu(rsn_ie_tlv->header.len));
327 else
328 return -1;
329
330 rsn_ie_len = sizeof(rsn_ie_tlv->header) +
331 le16_to_cpu(rsn_ie_tlv->header.len);
332 *buffer += rsn_ie_len;
333
334 return rsn_ie_len;
335}
336
337/*
338 * This function prepares command for association.
339 *
340 * This sets the following parameters -
341 * - Peer MAC address
342 * - Listen interval
343 * - Beacon interval
344 * - Capability information
345 *
346 * ...and the following TLVs, as required -
347 * - SSID TLV
348 * - PHY TLV
349 * - SS TLV
350 * - Rates TLV
351 * - Authentication TLV
352 * - Channel TLV
353 * - WPA/WPA2 IE
354 * - 11n TLV
355 * - Vendor specific TLV
356 * - WMM TLV
357 * - WAPI IE
358 * - Generic IE
359 * - TSF TLV
360 *
361 * Preparation also includes -
362 * - Setting command ID and proper size
363 * - Ensuring correct endian-ness
364 */
365int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
366 struct host_cmd_ds_command *cmd,
367 void *data_buf)
368{
369 struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate;
370 struct mwifiex_bssdescriptor *bss_desc;
371 struct mwifiex_ie_types_ssid_param_set *ssid_tlv;
372 struct mwifiex_ie_types_phy_param_set *phy_tlv;
373 struct mwifiex_ie_types_ss_param_set *ss_tlv;
374 struct mwifiex_ie_types_rates_param_set *rates_tlv;
375 struct mwifiex_ie_types_auth_type *auth_tlv;
376 struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
377 u8 rates[MWIFIEX_SUPPORTED_RATES];
378 u32 rates_size;
379 u16 tmp_cap;
380 u8 *pos;
381 int rsn_ie_len = 0;
382
383 bss_desc = (struct mwifiex_bssdescriptor *) data_buf;
384 pos = (u8 *) assoc;
385
386 mwifiex_cfg_tx_buf(priv, bss_desc);
387
388 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
389
390 /* Save so we know which BSS Desc to use in the response handler */
391 priv->attempted_bss_desc = bss_desc;
392
393 memcpy(assoc->peer_sta_addr,
394 bss_desc->mac_address, sizeof(assoc->peer_sta_addr));
395 pos += sizeof(assoc->peer_sta_addr);
396
397 /* Set the listen interval */
398 assoc->listen_interval = cpu_to_le16(priv->listen_interval);
399 /* Set the beacon period */
400 assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period);
401
402 pos += sizeof(assoc->cap_info_bitmap);
403 pos += sizeof(assoc->listen_interval);
404 pos += sizeof(assoc->beacon_period);
405 pos += sizeof(assoc->dtim_period);
406
407 ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos;
408 ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID);
409 ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len);
410 memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid,
411 le16_to_cpu(ssid_tlv->header.len));
412 pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len);
413
414 phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
415 phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
416 phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
417 memcpy(&phy_tlv->fh_ds.ds_param_set,
418 &bss_desc->phy_param_set.ds_param_set.current_chan,
419 sizeof(phy_tlv->fh_ds.ds_param_set));
420 pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
421
422 ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
423 ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
424 ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
425 pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
426
427 /* Get the common rates supported between the driver and the BSS Desc */
428 if (mwifiex_setup_rates_from_bssdesc
429 (priv, bss_desc, rates, &rates_size))
430 return -1;
431
432 /* Save the data rates into Current BSS state structure */
433 priv->curr_bss_params.num_of_rates = rates_size;
434 memcpy(&priv->curr_bss_params.data_rates, rates, rates_size);
435
436 /* Setup the Rates TLV in the association command */
437 rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos;
438 rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
439 rates_tlv->header.len = cpu_to_le16((u16) rates_size);
440 memcpy(rates_tlv->rates, rates, rates_size);
441 pos += sizeof(rates_tlv->header) + rates_size;
442 dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n",
443 rates_size);
444
445 /* Add the Authentication type to be used for Auth frames */
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(
451 (u16) priv->sec_info.authentication_mode);
452 else
453 auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM);
454
455 pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len);
456
457 if (IS_SUPPORT_MULTI_BANDS(priv->adapter)
458 && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
459 && (!bss_desc->disable_11n)
460 && (priv->adapter->config_bands & BAND_GN
461 || priv->adapter->config_bands & BAND_AN)
462 && (bss_desc->bcn_ht_cap)
463 )
464 ) {
465 /* Append a channel TLV for the channel the attempted AP was
466 found on */
467 chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
468 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
469 chan_tlv->header.len =
470 cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
471
472 memset(chan_tlv->chan_scan_param, 0x00,
473 sizeof(struct mwifiex_chan_scan_param_set));
474 chan_tlv->chan_scan_param[0].chan_number =
475 (bss_desc->phy_param_set.ds_param_set.current_chan);
476 dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n",
477 chan_tlv->chan_scan_param[0].chan_number);
478
479 chan_tlv->chan_scan_param[0].radio_type =
480 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
481
482 dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n",
483 chan_tlv->chan_scan_param[0].radio_type);
484 pos += sizeof(chan_tlv->header) +
485 sizeof(struct mwifiex_chan_scan_param_set);
486 }
487
488 if (!priv->wps.session_enable) {
489 if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
490 rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
491
492 if (rsn_ie_len == -1)
493 return -1;
494 }
495
496 if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
497 && (!bss_desc->disable_11n)
498 && (priv->adapter->config_bands & BAND_GN
499 || priv->adapter->config_bands & BAND_AN))
500 mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
501
502 /* Append vendor specific IE TLV */
503 mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
504
505 mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie,
506 bss_desc->bcn_ht_cap);
507 if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
508 mwifiex_cmd_append_wapi_ie(priv, &pos);
509
510
511 mwifiex_cmd_append_generic_ie(priv, &pos);
512
513 mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
514
515 cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
516
517 /* Set the Capability info at last */
518 tmp_cap = bss_desc->cap_info_bitmap;
519
520 if (priv->adapter->config_bands == BAND_B)
521 tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
522
523 tmp_cap &= CAPINFO_MASK;
524 dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
525 tmp_cap, CAPINFO_MASK);
526 assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
527
528 return 0;
529}
530
531/*
532 * Association firmware command response handler
533 *
534 * The response buffer for the association command has the following
535 * memory layout.
536 *
537 * For cases where an association response was not received (indicated
538 * by the CapInfo and AId field):
539 *
540 * .------------------------------------------------------------.
541 * | Header(4 * sizeof(t_u16)): Standard command response hdr |
542 * .------------------------------------------------------------.
543 * | cap_info/Error Return(t_u16): |
544 * | 0xFFFF(-1): Internal error |
545 * | 0xFFFE(-2): Authentication unhandled message |
546 * | 0xFFFD(-3): Authentication refused |
547 * | 0xFFFC(-4): Timeout waiting for AP response |
548 * .------------------------------------------------------------.
549 * | status_code(t_u16): |
550 * | If cap_info is -1: |
551 * | An internal firmware failure prevented the |
552 * | command from being processed. The status_code |
553 * | will be set to 1. |
554 * | |
555 * | If cap_info is -2: |
556 * | An authentication frame was received but was |
557 * | not handled by the firmware. IEEE Status |
558 * | code for the failure is returned. |
559 * | |
560 * | If cap_info is -3: |
561 * | An authentication frame was received and the |
562 * | status_code is the IEEE Status reported in the |
563 * | response. |
564 * | |
565 * | If cap_info is -4: |
566 * | (1) Association response timeout |
567 * | (2) Authentication response timeout |
568 * .------------------------------------------------------------.
569 * | a_id(t_u16): 0xFFFF |
570 * .------------------------------------------------------------.
571 *
572 *
573 * For cases where an association response was received, the IEEE
574 * standard association response frame is returned:
575 *
576 * .------------------------------------------------------------.
577 * | Header(4 * sizeof(t_u16)): Standard command response hdr |
578 * .------------------------------------------------------------.
579 * | cap_info(t_u16): IEEE Capability |
580 * .------------------------------------------------------------.
581 * | status_code(t_u16): IEEE Status Code |
582 * .------------------------------------------------------------.
583 * | a_id(t_u16): IEEE Association ID |
584 * .------------------------------------------------------------.
585 * | IEEE IEs(variable): Any received IEs comprising the |
586 * | remaining portion of a received |
587 * | association response frame. |
588 * .------------------------------------------------------------.
589 *
590 * For simplistic handling, the status_code field can be used to determine
591 * an association success (0) or failure (non-zero).
592 */
593int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
594 struct host_cmd_ds_command *resp)
595{
596 struct mwifiex_adapter *adapter = priv->adapter;
597 int ret = 0;
598 struct ieee_types_assoc_rsp *assoc_rsp;
599 struct mwifiex_bssdescriptor *bss_desc;
600 u8 enable_data = true;
601
602 assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
603
604 priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
605 sizeof(priv->assoc_rsp_buf));
606
607 memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
608
609 if (le16_to_cpu(assoc_rsp->status_code)) {
610 priv->adapter->dbg.num_cmd_assoc_failure++;
611 dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, "
612 "status code = %d, error = 0x%x, a_id = 0x%x\n",
613 le16_to_cpu(assoc_rsp->status_code),
614 le16_to_cpu(assoc_rsp->cap_info_bitmap),
615 le16_to_cpu(assoc_rsp->a_id));
616
617 ret = -1;
618 goto done;
619 }
620
621 /* Send a Media Connected event, according to the Spec */
622 priv->media_connected = true;
623
624 priv->adapter->ps_state = PS_STATE_AWAKE;
625 priv->adapter->pps_uapsd_mode = false;
626 priv->adapter->tx_lock_flag = false;
627
628 /* Set the attempted BSSID Index to current */
629 bss_desc = priv->attempted_bss_desc;
630
631 dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n",
632 bss_desc->ssid.ssid);
633
634 /* Make a copy of current BSSID descriptor */
635 memcpy(&priv->curr_bss_params.bss_descriptor,
636 bss_desc, sizeof(struct mwifiex_bssdescriptor));
637
638 /* Update curr_bss_params */
639 priv->curr_bss_params.bss_descriptor.channel
640 = bss_desc->phy_param_set.ds_param_set.current_chan;
641
642 priv->curr_bss_params.band = (u8) bss_desc->bss_band;
643
644 /*
645 * Adjust the timestamps in the scan table to be relative to the newly
646 * associated AP's TSF
647 */
648 mwifiex_update_tsf_timestamps(priv, bss_desc);
649
650 if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
651 priv->curr_bss_params.wmm_enabled = true;
652 else
653 priv->curr_bss_params.wmm_enabled = false;
654
655 if ((priv->wmm_required || bss_desc->bcn_ht_cap)
656 && priv->curr_bss_params.wmm_enabled)
657 priv->wmm_enabled = true;
658 else
659 priv->wmm_enabled = false;
660
661 priv->curr_bss_params.wmm_uapsd_enabled = false;
662
663 if (priv->wmm_enabled)
664 priv->curr_bss_params.wmm_uapsd_enabled
665 = ((bss_desc->wmm_ie.qos_info_bitmap &
666 IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
667
668 dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
669 priv->curr_pkt_filter);
670 if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
671 priv->wpa_is_gtk_set = false;
672
673 if (priv->wmm_enabled) {
674 /* Don't re-enable carrier until we get the WMM_GET_STATUS
675 event */
676 enable_data = false;
677 } else {
678 /* Since WMM is not enabled, setup the queues with the
679 defaults */
680 mwifiex_wmm_setup_queue_priorities(priv, NULL);
681 mwifiex_wmm_setup_ac_downgrade(priv);
682 }
683
684 if (enable_data)
685 dev_dbg(priv->adapter->dev,
686 "info: post association, re-enabling data flow\n");
687
688 /* Reset SNR/NF/RSSI values */
689 priv->data_rssi_last = 0;
690 priv->data_nf_last = 0;
691 priv->data_rssi_avg = 0;
692 priv->data_nf_avg = 0;
693 priv->bcn_rssi_last = 0;
694 priv->bcn_nf_last = 0;
695 priv->bcn_rssi_avg = 0;
696 priv->bcn_nf_avg = 0;
697 priv->rxpd_rate = 0;
698 priv->rxpd_htinfo = 0;
699
700 mwifiex_save_curr_bcn(priv);
701
702 priv->adapter->dbg.num_cmd_assoc_success++;
703
704 dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n");
705
706 /* Add the ra_list here for infra mode as there will be only 1 ra
707 always */
708 mwifiex_ralist_add(priv,
709 priv->curr_bss_params.bss_descriptor.mac_address);
710
711 if (!netif_carrier_ok(priv->netdev))
712 netif_carrier_on(priv->netdev);
713 if (netif_queue_stopped(priv->netdev))
714 netif_wake_queue(priv->netdev);
715
716 if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
717 priv->scan_block = true;
718
719done:
720 /* Need to indicate IOCTL complete */
721 if (adapter->curr_cmd->wait_q_enabled) {
722 if (ret)
723 adapter->cmd_wait_q.status = -1;
724 else
725 adapter->cmd_wait_q.status = 0;
726 }
727
728 return ret;
729}
730
731/*
732 * This function prepares command for ad-hoc start.
733 *
734 * Driver will fill up SSID, BSS mode, IBSS parameters, physical
735 * parameters, probe delay, and capability information. Firmware
736 * will fill up beacon period, basic rates and operational rates.
737 *
738 * In addition, the following TLVs are added -
739 * - Channel TLV
740 * - Vendor specific IE
741 * - WPA/WPA2 IE
742 * - HT Capabilities IE
743 * - HT Information IE
744 *
745 * Preparation also includes -
746 * - Setting command ID and proper size
747 * - Ensuring correct endian-ness
748 */
749int
750mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
751 struct host_cmd_ds_command *cmd, void *data_buf)
752{
753 int rsn_ie_len = 0;
754 struct mwifiex_adapter *adapter = priv->adapter;
755 struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start =
756 &cmd->params.adhoc_start;
757 struct mwifiex_bssdescriptor *bss_desc;
758 u32 cmd_append_size = 0;
759 u32 i;
760 u16 tmp_cap;
761 uint16_t ht_cap_info;
762 struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
763
764 struct mwifiex_ie_types_htcap *ht_cap;
765 struct mwifiex_ie_types_htinfo *ht_info;
766 u8 *pos = (u8 *) adhoc_start +
767 sizeof(struct host_cmd_ds_802_11_ad_hoc_start);
768
769 if (!adapter)
770 return -1;
771
772 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
773
774 bss_desc = &priv->curr_bss_params.bss_descriptor;
775 priv->attempted_bss_desc = bss_desc;
776
777 /*
778 * Fill in the parameters for 2 data structures:
779 * 1. struct host_cmd_ds_802_11_ad_hoc_start command
780 * 2. bss_desc
781 * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
782 * probe delay, and Cap info.
783 * Firmware will fill up beacon period, Basic rates
784 * and operational rates.
785 */
786
787 memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
788
789 memcpy(adhoc_start->ssid,
790 ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
791 ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
792
793 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n",
794 adhoc_start->ssid);
795
796 memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
797 memcpy(bss_desc->ssid.ssid,
798 ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
799 ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
800
801 bss_desc->ssid.ssid_len =
802 ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len;
803
804 /* Set the BSS mode */
805 adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
806 bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
807 adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period);
808 bss_desc->beacon_period = priv->beacon_period;
809
810 /* Set Physical param set */
811/* Parameter IE Id */
812#define DS_PARA_IE_ID 3
813/* Parameter IE length */
814#define DS_PARA_IE_LEN 1
815
816 adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
817 adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
818
819 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
820 (priv, adapter->adhoc_start_band, (u16)
821 priv->adhoc_channel)) {
822 struct mwifiex_chan_freq_power *cfp;
823 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
824 adapter->adhoc_start_band, FIRST_VALID_CHANNEL);
825 if (cfp)
826 priv->adhoc_channel = (u8) cfp->channel;
827 }
828
829 if (!priv->adhoc_channel) {
830 dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
831 return -1;
832 }
833
834 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
835 priv->adhoc_channel);
836
837 priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
838 priv->curr_bss_params.band = adapter->adhoc_start_band;
839
840 bss_desc->channel = priv->adhoc_channel;
841 adhoc_start->phy_param_set.ds_param_set.current_chan =
842 priv->adhoc_channel;
843
844 memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set,
845 sizeof(union ieee_types_phy_param_set));
846
847 /* Set IBSS param set */
848/* IBSS parameter IE Id */
849#define IBSS_PARA_IE_ID 6
850/* IBSS parameter IE length */
851#define IBSS_PARA_IE_LEN 2
852
853 adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
854 adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
855 adhoc_start->ss_param_set.ibss_param_set.atim_window
856 = cpu_to_le16(priv->atim_window);
857 memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set,
858 sizeof(union ieee_types_ss_param_set));
859
860 /* Set Capability info */
861 bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS;
862 tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap);
863 tmp_cap &= ~WLAN_CAPABILITY_ESS;
864 tmp_cap |= WLAN_CAPABILITY_IBSS;
865
866 /* Set up privacy in bss_desc */
867 if (priv->sec_info.encryption_mode) {
868 /* Ad-Hoc capability privacy on */
869 dev_dbg(adapter->dev,
870 "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
871 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
872 tmp_cap |= WLAN_CAPABILITY_PRIVACY;
873 } else {
874 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set,"
875 " setting privacy to ACCEPT ALL\n");
876 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
877 }
878
879 memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
880 mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
881 if ((adapter->adhoc_start_band & BAND_G) &&
882 (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
883 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
884 HostCmd_ACT_GEN_SET, 0,
885 &priv->curr_pkt_filter)) {
886 dev_err(adapter->dev,
887 "ADHOC_S_CMD: G Protection config failed\n");
888 return -1;
889 }
890 }
891 /* Find the last non zero */
892 for (i = 0; i < sizeof(adhoc_start->DataRate) &&
893 adhoc_start->DataRate[i];
894 i++)
895 ;
896
897 priv->curr_bss_params.num_of_rates = i;
898
899 /* Copy the ad-hoc creating rates into Current BSS rate structure */
900 memcpy(&priv->curr_bss_params.data_rates,
901 &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
902
903 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
904 adhoc_start->DataRate[0], adhoc_start->DataRate[1],
905 adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
906
907 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
908
909 if (IS_SUPPORT_MULTI_BANDS(adapter)) {
910 /* Append a channel TLV */
911 chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
912 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
913 chan_tlv->header.len =
914 cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
915
916 memset(chan_tlv->chan_scan_param, 0x00,
917 sizeof(struct mwifiex_chan_scan_param_set));
918 chan_tlv->chan_scan_param[0].chan_number =
919 (u8) priv->curr_bss_params.bss_descriptor.channel;
920
921 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n",
922 chan_tlv->chan_scan_param[0].chan_number);
923
924 chan_tlv->chan_scan_param[0].radio_type
925 = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
926 if (adapter->adhoc_start_band & BAND_GN
927 || adapter->adhoc_start_band & BAND_AN) {
928 if (adapter->chan_offset == SEC_CHANNEL_ABOVE)
929 chan_tlv->chan_scan_param[0].radio_type |=
930 SECOND_CHANNEL_ABOVE;
931 else if (adapter->chan_offset == SEC_CHANNEL_BELOW)
932 chan_tlv->chan_scan_param[0].radio_type |=
933 SECOND_CHANNEL_BELOW;
934 }
935 dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n",
936 chan_tlv->chan_scan_param[0].radio_type);
937 pos += sizeof(chan_tlv->header) +
938 sizeof(struct mwifiex_chan_scan_param_set);
939 cmd_append_size +=
940 sizeof(chan_tlv->header) +
941 sizeof(struct mwifiex_chan_scan_param_set);
942 }
943
944 /* Append vendor specific IE TLV */
945 cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
946 MWIFIEX_VSIE_MASK_ADHOC, &pos);
947
948 if (priv->sec_info.wpa_enabled) {
949 rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
950 if (rsn_ie_len == -1)
951 return -1;
952 cmd_append_size += rsn_ie_len;
953 }
954
955 if (adapter->adhoc_11n_enabled) {
956 {
957 ht_cap = (struct mwifiex_ie_types_htcap *) pos;
958 memset(ht_cap, 0,
959 sizeof(struct mwifiex_ie_types_htcap));
960 ht_cap->header.type =
961 cpu_to_le16(WLAN_EID_HT_CAPABILITY);
962 ht_cap->header.len =
963 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
964 ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
965
966 ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
967 if (adapter->chan_offset) {
968 ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
969 ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
970 ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
971 SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
972 }
973
974 ht_cap->ht_cap.ampdu_params_info
975 = IEEE80211_HT_MAX_AMPDU_64K;
976 ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
977 pos += sizeof(struct mwifiex_ie_types_htcap);
978 cmd_append_size +=
979 sizeof(struct mwifiex_ie_types_htcap);
980 }
981 {
982 ht_info = (struct mwifiex_ie_types_htinfo *) pos;
983 memset(ht_info, 0,
984 sizeof(struct mwifiex_ie_types_htinfo));
985 ht_info->header.type =
986 cpu_to_le16(WLAN_EID_HT_INFORMATION);
987 ht_info->header.len =
988 cpu_to_le16(sizeof(struct ieee80211_ht_info));
989 ht_info->ht_info.control_chan =
990 (u8) priv->curr_bss_params.bss_descriptor.
991 channel;
992 if (adapter->chan_offset) {
993 ht_info->ht_info.ht_param =
994 adapter->chan_offset;
995 ht_info->ht_info.ht_param |=
996 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
997 }
998 ht_info->ht_info.operation_mode =
999 cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
1000 ht_info->ht_info.basic_set[0] = 0xff;
1001 pos += sizeof(struct mwifiex_ie_types_htinfo);
1002 cmd_append_size +=
1003 sizeof(struct mwifiex_ie_types_htinfo);
1004 }
1005 }
1006
1007 cmd->size = cpu_to_le16((u16)
1008 (sizeof(struct host_cmd_ds_802_11_ad_hoc_start)
1009 + S_DS_GEN + cmd_append_size));
1010
1011 if (adapter->adhoc_start_band == BAND_B)
1012 tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
1013 else
1014 tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
1015
1016 adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap);
1017
1018 return 0;
1019}
1020
1021/*
1022 * This function prepares command for ad-hoc join.
1023 *
1024 * Most of the parameters are set up by copying from the target BSS descriptor
1025 * from the scan response.
1026 *
1027 * In addition, the following TLVs are added -
1028 * - Channel TLV
1029 * - Vendor specific IE
1030 * - WPA/WPA2 IE
1031 * - 11n IE
1032 *
1033 * Preparation also includes -
1034 * - Setting command ID and proper size
1035 * - Ensuring correct endian-ness
1036 */
1037int
1038mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
1039 struct host_cmd_ds_command *cmd, void *data_buf)
1040{
1041 int rsn_ie_len = 0;
1042 struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
1043 &cmd->params.adhoc_join;
1044 struct mwifiex_bssdescriptor *bss_desc =
1045 (struct mwifiex_bssdescriptor *) data_buf;
1046 struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
1047 u32 cmd_append_size = 0;
1048 u16 tmp_cap;
1049 u32 i, rates_size = 0;
1050 u16 curr_pkt_filter;
1051 u8 *pos =
1052 (u8 *) adhoc_join +
1053 sizeof(struct host_cmd_ds_802_11_ad_hoc_join);
1054
1055/* Use G protection */
1056#define USE_G_PROTECTION 0x02
1057 if (bss_desc->erp_flags & USE_G_PROTECTION) {
1058 curr_pkt_filter =
1059 priv->
1060 curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
1061
1062 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
1063 HostCmd_ACT_GEN_SET, 0,
1064 &curr_pkt_filter)) {
1065 dev_err(priv->adapter->dev,
1066 "ADHOC_J_CMD: G Protection config failed\n");
1067 return -1;
1068 }
1069 }
1070
1071 priv->attempted_bss_desc = bss_desc;
1072
1073 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
1074
1075 adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
1076
1077 adhoc_join->bss_descriptor.beacon_period
1078 = cpu_to_le16(bss_desc->beacon_period);
1079
1080 memcpy(&adhoc_join->bss_descriptor.bssid,
1081 &bss_desc->mac_address, ETH_ALEN);
1082
1083 memcpy(&adhoc_join->bss_descriptor.ssid,
1084 &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len);
1085
1086 memcpy(&adhoc_join->bss_descriptor.phy_param_set,
1087 &bss_desc->phy_param_set,
1088 sizeof(union ieee_types_phy_param_set));
1089
1090 memcpy(&adhoc_join->bss_descriptor.ss_param_set,
1091 &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set));
1092
1093 tmp_cap = bss_desc->cap_info_bitmap;
1094
1095 tmp_cap &= CAPINFO_MASK;
1096
1097 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X"
1098 " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK);
1099
1100 /* Information on BSSID descriptor passed to FW */
1101 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n",
1102 adhoc_join->bss_descriptor.bssid,
1103 adhoc_join->bss_descriptor.ssid);
1104
1105 for (i = 0; bss_desc->supported_rates[i] &&
1106 i < MWIFIEX_SUPPORTED_RATES;
1107 i++)
1108 ;
1109 rates_size = i;
1110
1111 /* Copy Data Rates from the Rates recorded in scan response */
1112 memset(adhoc_join->bss_descriptor.data_rates, 0,
1113 sizeof(adhoc_join->bss_descriptor.data_rates));
1114 memcpy(adhoc_join->bss_descriptor.data_rates,
1115 bss_desc->supported_rates, rates_size);
1116
1117 /* Copy the adhoc join rates into Current BSS state structure */
1118 priv->curr_bss_params.num_of_rates = rates_size;
1119 memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates,
1120 rates_size);
1121
1122 /* Copy the channel information */
1123 priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
1124 priv->curr_bss_params.band = (u8) bss_desc->bss_band;
1125
1126 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
1127 || priv->sec_info.wpa_enabled)
1128 tmp_cap |= WLAN_CAPABILITY_PRIVACY;
1129
1130 if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
1131 /* Append a channel TLV */
1132 chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
1133 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
1134 chan_tlv->header.len =
1135 cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
1136
1137 memset(chan_tlv->chan_scan_param, 0x00,
1138 sizeof(struct mwifiex_chan_scan_param_set));
1139 chan_tlv->chan_scan_param[0].chan_number =
1140 (bss_desc->phy_param_set.ds_param_set.current_chan);
1141 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n",
1142 chan_tlv->chan_scan_param[0].chan_number);
1143
1144 chan_tlv->chan_scan_param[0].radio_type =
1145 mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
1146
1147 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n",
1148 chan_tlv->chan_scan_param[0].radio_type);
1149 pos += sizeof(chan_tlv->header) +
1150 sizeof(struct mwifiex_chan_scan_param_set);
1151 cmd_append_size += sizeof(chan_tlv->header) +
1152 sizeof(struct mwifiex_chan_scan_param_set);
1153 }
1154
1155 if (priv->sec_info.wpa_enabled)
1156 rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
1157 if (rsn_ie_len == -1)
1158 return -1;
1159 cmd_append_size += rsn_ie_len;
1160
1161 if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
1162 cmd_append_size += mwifiex_cmd_append_11n_tlv(priv,
1163 bss_desc, &pos);
1164
1165 /* Append vendor specific IE TLV */
1166 cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
1167 MWIFIEX_VSIE_MASK_ADHOC, &pos);
1168
1169 cmd->size = cpu_to_le16((u16)
1170 (sizeof(struct host_cmd_ds_802_11_ad_hoc_join)
1171 + S_DS_GEN + cmd_append_size));
1172
1173 adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
1174
1175 return 0;
1176}
1177
1178/*
1179 * This function handles the command response of ad-hoc start and
1180 * ad-hoc join.
1181 *
1182 * The function generates a device-connected event to notify
1183 * the applications, in case of successful ad-hoc start/join, and
1184 * saves the beacon buffer.
1185 */
1186int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
1187 struct host_cmd_ds_command *resp)
1188{
1189 int ret = 0;
1190 struct mwifiex_adapter *adapter = priv->adapter;
1191 struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result;
1192 struct mwifiex_bssdescriptor *bss_desc;
1193
1194 adhoc_result = &resp->params.adhoc_result;
1195
1196 bss_desc = priv->attempted_bss_desc;
1197
1198 /* Join result code 0 --> SUCCESS */
1199 if (le16_to_cpu(resp->result)) {
1200 dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
1201 if (priv->media_connected)
1202 mwifiex_reset_connect_state(priv);
1203
1204 memset(&priv->curr_bss_params.bss_descriptor,
1205 0x00, sizeof(struct mwifiex_bssdescriptor));
1206
1207 ret = -1;
1208 goto done;
1209 }
1210
1211 /* Send a Media Connected event, according to the Spec */
1212 priv->media_connected = true;
1213
1214 if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
1215 dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
1216 bss_desc->ssid.ssid);
1217
1218 /* Update the created network descriptor with the new BSSID */
1219 memcpy(bss_desc->mac_address,
1220 adhoc_result->bssid, ETH_ALEN);
1221
1222 priv->adhoc_state = ADHOC_STARTED;
1223 } else {
1224 /*
1225 * Now the join cmd should be successful.
1226 * If BSSID has changed use SSID to compare instead of BSSID
1227 */
1228 dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n",
1229 bss_desc->ssid.ssid);
1230
1231 /*
1232 * Make a copy of current BSSID descriptor, only needed for
1233 * join since the current descriptor is already being used
1234 * for adhoc start
1235 */
1236 memcpy(&priv->curr_bss_params.bss_descriptor,
1237 bss_desc, sizeof(struct mwifiex_bssdescriptor));
1238
1239 priv->adhoc_state = ADHOC_JOINED;
1240 }
1241
1242 dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n",
1243 priv->adhoc_channel);
1244 dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n",
1245 priv->curr_bss_params.bss_descriptor.mac_address);
1246
1247 if (!netif_carrier_ok(priv->netdev))
1248 netif_carrier_on(priv->netdev);
1249 if (netif_queue_stopped(priv->netdev))
1250 netif_wake_queue(priv->netdev);
1251
1252 mwifiex_save_curr_bcn(priv);
1253
1254done:
1255 /* Need to indicate IOCTL complete */
1256 if (adapter->curr_cmd->wait_q_enabled) {
1257 if (ret)
1258 adapter->cmd_wait_q.status = -1;
1259 else
1260 adapter->cmd_wait_q.status = 0;
1261
1262 }
1263
1264 return ret;
1265}
1266
1267/*
1268 * This function associates to a specific BSS discovered in a scan.
1269 *
1270 * It clears any past association response stored for application
1271 * retrieval and calls the command preparation routine to send the
1272 * command to firmware.
1273 */
1274int mwifiex_associate(struct mwifiex_private *priv,
1275 struct mwifiex_bssdescriptor *bss_desc)
1276{
1277 u8 current_bssid[ETH_ALEN];
1278
1279 /* Return error if the adapter or table entry is not marked as infra */
1280 if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
1281 (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
1282 return -1;
1283
1284 memcpy(&current_bssid,
1285 &priv->curr_bss_params.bss_descriptor.mac_address,
1286 sizeof(current_bssid));
1287
1288 /* Clear any past association response stored for application
1289 retrieval */
1290 priv->assoc_rsp_size = 0;
1291
1292 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE,
1293 HostCmd_ACT_GEN_SET, 0, bss_desc);
1294}
1295
1296/*
1297 * This function starts an ad-hoc network.
1298 *
1299 * It calls the command preparation routine to send the command to firmware.
1300 */
1301int
1302mwifiex_adhoc_start(struct mwifiex_private *priv,
1303 struct mwifiex_802_11_ssid *adhoc_ssid)
1304{
1305 dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
1306 priv->adhoc_channel);
1307 dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
1308 priv->curr_bss_params.bss_descriptor.channel);
1309 dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
1310 priv->curr_bss_params.band);
1311
1312 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
1313 HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
1314}
1315
1316/*
1317 * This function joins an ad-hoc network found in a previous scan.
1318 *
1319 * It calls the command preparation routine to send the command to firmware,
1320 * if already not connected to the requested SSID.
1321 */
1322int mwifiex_adhoc_join(struct mwifiex_private *priv,
1323 struct mwifiex_bssdescriptor *bss_desc)
1324{
1325 dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n",
1326 priv->curr_bss_params.bss_descriptor.ssid.ssid);
1327 dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n",
1328 priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
1329 dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n",
1330 bss_desc->ssid.ssid);
1331 dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n",
1332 bss_desc->ssid.ssid_len);
1333
1334 /* Check if the requested SSID is already joined */
1335 if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
1336 !mwifiex_ssid_cmp(&bss_desc->ssid,
1337 &priv->curr_bss_params.bss_descriptor.ssid) &&
1338 (priv->curr_bss_params.bss_descriptor.bss_mode ==
1339 NL80211_IFTYPE_ADHOC)) {
1340 dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID"
1341 " is the same as current; not attempting to re-join\n");
1342 return -1;
1343 }
1344
1345 dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
1346 priv->curr_bss_params.bss_descriptor.channel);
1347 dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
1348 priv->curr_bss_params.band);
1349
1350 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
1351 HostCmd_ACT_GEN_SET, 0, bss_desc);
1352}
1353
1354/*
1355 * This function deauthenticates/disconnects from infra network by sending
1356 * deauthentication request.
1357 */
1358static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
1359{
1360 u8 mac_address[ETH_ALEN];
1361 int ret;
1362 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
1363
1364 if (mac) {
1365 if (!memcmp(mac, zero_mac, sizeof(zero_mac)))
1366 memcpy((u8 *) &mac_address,
1367 (u8 *) &priv->curr_bss_params.bss_descriptor.
1368 mac_address, ETH_ALEN);
1369 else
1370 memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN);
1371 } else {
1372 memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params.
1373 bss_descriptor.mac_address, ETH_ALEN);
1374 }
1375
1376 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
1377 HostCmd_ACT_GEN_SET, 0, &mac_address);
1378
1379 return ret;
1380}
1381
1382/*
1383 * This function deauthenticates/disconnects from a BSS.
1384 *
1385 * In case of infra made, it sends deauthentication request, and
1386 * in case of ad-hoc mode, a stop network request is sent to the firmware.
1387 */
1388int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
1389{
1390 int ret = 0;
1391
1392 if (priv->media_connected) {
1393 if (priv->bss_mode == NL80211_IFTYPE_STATION) {
1394 ret = mwifiex_deauthenticate_infra(priv, mac);
1395 } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
1396 ret = mwifiex_send_cmd_sync(priv,
1397 HostCmd_CMD_802_11_AD_HOC_STOP,
1398 HostCmd_ACT_GEN_SET, 0, NULL);
1399 }
1400 }
1401
1402 return ret;
1403}
1404EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
1405
1406/*
1407 * This function converts band to radio type used in channel TLV.
1408 */
1409u8
1410mwifiex_band_to_radio_type(u8 band)
1411{
1412 switch (band) {
1413 case BAND_A:
1414 case BAND_AN:
1415 case BAND_A | BAND_AN:
1416 return HostCmd_SCAN_RADIO_TYPE_A;
1417 case BAND_B:
1418 case BAND_G:
1419 case BAND_B | BAND_G:
1420 default:
1421 return HostCmd_SCAN_RADIO_TYPE_BG;
1422 }
1423}
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
new file mode 100644
index 000000000000..f0582259c935
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -0,0 +1,1055 @@
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 = DRV_MODE_STA,
44 .intf_num = ARRAY_SIZE(mwifiex_bss_sta),
45 .bss_attr = mwifiex_bss_sta,
46 },
47};
48
49/*
50 * This function registers the device and performs all the necessary
51 * initializations.
52 *
53 * The following initialization operations are performed -
54 * - Allocate adapter structure
55 * - Save interface specific operations table in adapter
56 * - Call interface specific initialization routine
57 * - Allocate private structures
58 * - Set default adapter structure parameters
59 * - Initialize locks
60 *
61 * In case of any errors during inittialization, this function also ensures
62 * proper cleanup before exiting.
63 */
64static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
65 struct mwifiex_drv_mode *drv_mode_ptr)
66{
67 struct mwifiex_adapter *adapter;
68 int i;
69
70 adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
71 if (!adapter)
72 return -ENOMEM;
73
74 g_adapter = adapter;
75 adapter->card = card;
76
77 /* Save interface specific operations in adapter */
78 memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
79
80 /* card specific initialization has been deferred until now .. */
81 if (adapter->if_ops.init_if(adapter))
82 goto error;
83
84 adapter->priv_num = 0;
85 for (i = 0; i < drv_mode_ptr->intf_num; i++) {
86 adapter->priv[i] = NULL;
87
88 if (!drv_mode_ptr->bss_attr[i].active)
89 continue;
90
91 /* Allocate memory for private structure */
92 adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
93 GFP_KERNEL);
94 if (!adapter->priv[i]) {
95 dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
96 __func__, i);
97 goto error;
98 }
99
100 adapter->priv_num++;
101 adapter->priv[i]->adapter = adapter;
102 /* Save bss_type, frame_type & bss_priority */
103 adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type;
104 adapter->priv[i]->frame_type =
105 drv_mode_ptr->bss_attr[i].frame_type;
106 adapter->priv[i]->bss_priority =
107 drv_mode_ptr->bss_attr[i].bss_priority;
108
109 if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
110 adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
111 else if (drv_mode_ptr->bss_attr[i].bss_type ==
112 MWIFIEX_BSS_TYPE_UAP)
113 adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
114
115 /* Save bss_index & bss_num */
116 adapter->priv[i]->bss_index = i;
117 adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num;
118 }
119 adapter->drv_mode = drv_mode_ptr;
120
121 if (mwifiex_init_lock_list(adapter))
122 goto error;
123
124 init_timer(&adapter->cmd_timer);
125 adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
126 adapter->cmd_timer.data = (unsigned long) adapter;
127
128 return 0;
129
130error:
131 dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
132
133 mwifiex_free_lock_list(adapter);
134 for (i = 0; i < drv_mode_ptr->intf_num; i++)
135 kfree(adapter->priv[i]);
136 kfree(adapter);
137
138 return -1;
139}
140
141/*
142 * This function unregisters the device and performs all the necessary
143 * cleanups.
144 *
145 * The following cleanup operations are performed -
146 * - Free the timers
147 * - Free beacon buffers
148 * - Free private structures
149 * - Free adapter structure
150 */
151static int mwifiex_unregister(struct mwifiex_adapter *adapter)
152{
153 s32 i;
154
155 del_timer(&adapter->cmd_timer);
156
157 /* Free private structures */
158 for (i = 0; i < adapter->priv_num; i++) {
159 if (adapter->priv[i]) {
160 mwifiex_free_curr_bcn(adapter->priv[i]);
161 kfree(adapter->priv[i]);
162 }
163 }
164
165 kfree(adapter);
166 return 0;
167}
168
169/*
170 * The main process.
171 *
172 * This function is the main procedure of the driver and handles various driver
173 * operations. It runs in a loop and provides the core functionalities.
174 *
175 * The main responsibilities of this function are -
176 * - Ensure concurrency control
177 * - Handle pending interrupts and call interrupt handlers
178 * - Wake up the card if required
179 * - Handle command responses and call response handlers
180 * - Handle events and call event handlers
181 * - Execute pending commands
182 * - Transmit pending data packets
183 */
184int mwifiex_main_process(struct mwifiex_adapter *adapter)
185{
186 int ret = 0;
187 unsigned long flags;
188
189 spin_lock_irqsave(&adapter->main_proc_lock, flags);
190
191 /* Check if already processing */
192 if (adapter->mwifiex_processing) {
193 spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
194 goto exit_main_proc;
195 } else {
196 adapter->mwifiex_processing = true;
197 spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
198 }
199process_start:
200 do {
201 if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
202 (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
203 break;
204
205 /* Handle pending interrupt if any */
206 if (adapter->int_status) {
207 if (adapter->hs_activated)
208 mwifiex_process_hs_config(adapter);
209 adapter->if_ops.process_int_status(adapter);
210 }
211
212 /* Need to wake up the card ? */
213 if ((adapter->ps_state == PS_STATE_SLEEP) &&
214 (adapter->pm_wakeup_card_req &&
215 !adapter->pm_wakeup_fw_try) &&
216 (is_command_pending(adapter)
217 || !mwifiex_wmm_lists_empty(adapter))) {
218 adapter->pm_wakeup_fw_try = true;
219 adapter->if_ops.wakeup(adapter);
220 continue;
221 }
222 if (IS_CARD_RX_RCVD(adapter)) {
223 adapter->pm_wakeup_fw_try = false;
224 if (adapter->ps_state == PS_STATE_SLEEP)
225 adapter->ps_state = PS_STATE_AWAKE;
226 } else {
227 /* We have tried to wakeup the card already */
228 if (adapter->pm_wakeup_fw_try)
229 break;
230 if (adapter->ps_state != PS_STATE_AWAKE ||
231 adapter->tx_lock_flag)
232 break;
233
234 if (adapter->scan_processing || adapter->data_sent
235 || mwifiex_wmm_lists_empty(adapter)) {
236 if (adapter->cmd_sent || adapter->curr_cmd
237 || (!is_command_pending(adapter)))
238 break;
239 }
240 }
241
242 /* Check for Cmd Resp */
243 if (adapter->cmd_resp_received) {
244 adapter->cmd_resp_received = false;
245 mwifiex_process_cmdresp(adapter);
246
247 /* call mwifiex back when init_fw is done */
248 if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) {
249 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
250 mwifiex_init_fw_complete(adapter);
251 }
252 }
253
254 /* Check for event */
255 if (adapter->event_received) {
256 adapter->event_received = false;
257 mwifiex_process_event(adapter);
258 }
259
260 /* Check if we need to confirm Sleep Request
261 received previously */
262 if (adapter->ps_state == PS_STATE_PRE_SLEEP) {
263 if (!adapter->cmd_sent && !adapter->curr_cmd)
264 mwifiex_check_ps_cond(adapter);
265 }
266
267 /* * The ps_state may have been changed during processing of
268 * Sleep Request event.
269 */
270 if ((adapter->ps_state == PS_STATE_SLEEP)
271 || (adapter->ps_state == PS_STATE_PRE_SLEEP)
272 || (adapter->ps_state == PS_STATE_SLEEP_CFM)
273 || adapter->tx_lock_flag)
274 continue;
275
276 if (!adapter->cmd_sent && !adapter->curr_cmd) {
277 if (mwifiex_exec_next_cmd(adapter) == -1) {
278 ret = -1;
279 break;
280 }
281 }
282
283 if (!adapter->scan_processing && !adapter->data_sent &&
284 !mwifiex_wmm_lists_empty(adapter)) {
285 mwifiex_wmm_process_tx(adapter);
286 if (adapter->hs_activated) {
287 adapter->is_hs_configured = false;
288 mwifiex_hs_activated_event
289 (mwifiex_get_priv
290 (adapter, MWIFIEX_BSS_ROLE_ANY),
291 false);
292 }
293 }
294
295 if (adapter->delay_null_pkt && !adapter->cmd_sent &&
296 !adapter->curr_cmd && !is_command_pending(adapter)
297 && mwifiex_wmm_lists_empty(adapter)) {
298 if (!mwifiex_send_null_packet
299 (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
300 MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
301 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) {
302 adapter->delay_null_pkt = false;
303 adapter->ps_state = PS_STATE_SLEEP;
304 }
305 break;
306 }
307 } while (true);
308
309 if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter))
310 goto process_start;
311
312 spin_lock_irqsave(&adapter->main_proc_lock, flags);
313 adapter->mwifiex_processing = false;
314 spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
315
316exit_main_proc:
317 if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING)
318 mwifiex_shutdown_drv(adapter);
319 return ret;
320}
321
322/*
323 * This function initializes the software.
324 *
325 * The main work includes allocating and initializing the adapter structure
326 * and initializing the private structures.
327 */
328static int
329mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops)
330{
331 int i;
332 struct mwifiex_drv_mode *drv_mode_ptr;
333
334 /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
335 drv_mode_ptr = NULL;
336 for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
337 if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
338 drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
339 break;
340 }
341 }
342
343 if (!drv_mode_ptr) {
344 pr_err("invalid drv_mode=%d\n", drv_mode);
345 return -1;
346 }
347
348 if (mwifiex_register(card, if_ops, drv_mode_ptr))
349 return -1;
350
351 return 0;
352}
353
354/*
355 * This function frees the adapter structure.
356 *
357 * Additionally, this closes the netlink socket, frees the timers
358 * and private structures.
359 */
360static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
361{
362 if (!adapter) {
363 pr_err("%s: adapter is NULL\n", __func__);
364 return;
365 }
366
367 mwifiex_unregister(adapter);
368 pr_debug("info: %s: free adapter\n", __func__);
369}
370
371/*
372 * This function initializes the hardware and firmware.
373 *
374 * The main initialization steps followed are -
375 * - Download the correct firmware to card
376 * - Allocate and initialize the adapter structure
377 * - Initialize the private structures
378 * - Issue the init commands to firmware
379 */
380static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
381{
382 int ret, err;
383 struct mwifiex_fw_image fw;
384
385 memset(&fw, 0, sizeof(struct mwifiex_fw_image));
386
387 switch (adapter->revision_id) {
388 case SD8787_W0:
389 case SD8787_W1:
390 strcpy(fw_name, SD8787_W1_FW_NAME);
391 break;
392 case SD8787_A0:
393 case SD8787_A1:
394 strcpy(fw_name, SD8787_AX_FW_NAME);
395 break;
396 default:
397 break;
398 }
399
400 err = request_firmware(&adapter->firmware, fw_name, adapter->dev);
401 if (err < 0) {
402 dev_err(adapter->dev, "request_firmware() returned"
403 " error code %#x\n", err);
404 ret = -1;
405 goto done;
406 }
407 fw.fw_buf = (u8 *) adapter->firmware->data;
408 fw.fw_len = adapter->firmware->size;
409
410 ret = mwifiex_dnld_fw(adapter, &fw);
411 if (ret == -1)
412 goto done;
413
414 dev_notice(adapter->dev, "WLAN FW is active\n");
415
416 adapter->init_wait_q_woken = false;
417 ret = mwifiex_init_fw(adapter);
418 if (ret == -1) {
419 goto done;
420 } else if (!ret) {
421 adapter->hw_status = MWIFIEX_HW_STATUS_READY;
422 goto done;
423 }
424 /* Wait for mwifiex_init to complete */
425 wait_event_interruptible(adapter->init_wait_q,
426 adapter->init_wait_q_woken);
427 if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
428 ret = -1;
429 goto done;
430 }
431 ret = 0;
432
433done:
434 if (adapter->firmware)
435 release_firmware(adapter->firmware);
436 if (ret)
437 ret = -1;
438 return ret;
439}
440
441/*
442 * This function fills a driver buffer.
443 *
444 * The function associates a given SKB with the provided driver buffer
445 * and also updates some of the SKB parameters, including IP header,
446 * priority and timestamp.
447 */
448static void
449mwifiex_fill_buffer(struct sk_buff *skb)
450{
451 struct ethhdr *eth;
452 struct iphdr *iph;
453 struct timeval tv;
454 u8 tid = 0;
455
456 eth = (struct ethhdr *) skb->data;
457 switch (eth->h_proto) {
458 case __constant_htons(ETH_P_IP):
459 iph = ip_hdr(skb);
460 tid = IPTOS_PREC(iph->tos);
461 pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
462 eth->h_proto, tid, skb->priority);
463 break;
464 case __constant_htons(ETH_P_ARP):
465 pr_debug("data: ARP packet: %04x\n", eth->h_proto);
466 default:
467 break;
468 }
469/* Offset for TOS field in the IP header */
470#define IPTOS_OFFSET 5
471 tid = (tid >> IPTOS_OFFSET);
472 skb->priority = tid;
473 /* Record the current time the packet was queued; used to
474 determine the amount of time the packet was queued in
475 the driver before it was sent to the firmware.
476 The delay is then sent along with the packet to the
477 firmware for aggregate delay calculation for stats and
478 MSDU lifetime expiry.
479 */
480 do_gettimeofday(&tv);
481 skb->tstamp = timeval_to_ktime(tv);
482}
483
484/*
485 * CFG802.11 network device handler for open.
486 *
487 * Starts the data queue.
488 */
489static int
490mwifiex_open(struct net_device *dev)
491{
492 netif_start_queue(dev);
493 return 0;
494}
495
496/*
497 * CFG802.11 network device handler for close.
498 */
499static int
500mwifiex_close(struct net_device *dev)
501{
502 return 0;
503}
504
505/*
506 * CFG802.11 network device handler for data transmission.
507 */
508static int
509mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
510{
511 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
512 struct sk_buff *new_skb;
513 struct mwifiex_txinfo *tx_info;
514
515 dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n",
516 jiffies, priv->bss_index);
517
518 if (priv->adapter->surprise_removed) {
519 kfree_skb(skb);
520 priv->stats.tx_dropped++;
521 return 0;
522 }
523 if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
524 dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
525 kfree_skb(skb);
526 priv->stats.tx_dropped++;
527 return 0;
528 }
529 if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
530 dev_dbg(priv->adapter->dev,
531 "data: Tx: insufficient skb headroom %d\n",
532 skb_headroom(skb));
533 /* Insufficient skb headroom - allocate a new skb */
534 new_skb =
535 skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
536 if (unlikely(!new_skb)) {
537 dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
538 kfree_skb(skb);
539 priv->stats.tx_dropped++;
540 return 0;
541 }
542 kfree_skb(skb);
543 skb = new_skb;
544 dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n",
545 skb_headroom(skb));
546 }
547
548 tx_info = MWIFIEX_SKB_TXCB(skb);
549 tx_info->bss_index = priv->bss_index;
550 mwifiex_fill_buffer(skb);
551
552 mwifiex_wmm_add_buf_txqueue(priv->adapter, skb);
553 atomic_inc(&priv->adapter->tx_pending);
554
555 if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
556 netif_stop_queue(priv->netdev);
557 dev->trans_start = jiffies;
558 }
559
560 queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
561
562 return 0;
563}
564
565/*
566 * CFG802.11 network device handler for setting MAC address.
567 */
568static int
569mwifiex_set_mac_address(struct net_device *dev, void *addr)
570{
571 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
572 struct sockaddr *hw_addr = (struct sockaddr *) addr;
573 int ret;
574
575 memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
576
577 /* Send request to firmware */
578 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
579 HostCmd_ACT_GEN_SET, 0, NULL);
580
581 if (!ret)
582 memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
583 else
584 dev_err(priv->adapter->dev, "set mac address failed: ret=%d"
585 "\n", ret);
586
587 memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
588
589 return ret;
590}
591
592/*
593 * CFG802.11 network device handler for setting multicast list.
594 */
595static void mwifiex_set_multicast_list(struct net_device *dev)
596{
597 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
598 struct mwifiex_multicast_list mcast_list;
599
600 if (dev->flags & IFF_PROMISC) {
601 mcast_list.mode = MWIFIEX_PROMISC_MODE;
602 } else if (dev->flags & IFF_ALLMULTI ||
603 netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) {
604 mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
605 } else {
606 mcast_list.mode = MWIFIEX_MULTICAST_MODE;
607 if (netdev_mc_count(dev))
608 mcast_list.num_multicast_addr =
609 mwifiex_copy_mcast_addr(&mcast_list, dev);
610 }
611 mwifiex_request_set_multicast_list(priv, &mcast_list);
612}
613
614/*
615 * CFG802.11 network device handler for transmission timeout.
616 */
617static void
618mwifiex_tx_timeout(struct net_device *dev)
619{
620 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
621
622 dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n",
623 jiffies, priv->bss_index);
624 dev->trans_start = jiffies;
625 priv->num_tx_timeout++;
626}
627
628/*
629 * CFG802.11 network device handler for statistics retrieval.
630 */
631static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
632{
633 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
634
635 return &priv->stats;
636}
637
638/* Network device handlers */
639static const struct net_device_ops mwifiex_netdev_ops = {
640 .ndo_open = mwifiex_open,
641 .ndo_stop = mwifiex_close,
642 .ndo_start_xmit = mwifiex_hard_start_xmit,
643 .ndo_set_mac_address = mwifiex_set_mac_address,
644 .ndo_tx_timeout = mwifiex_tx_timeout,
645 .ndo_get_stats = mwifiex_get_stats,
646 .ndo_set_multicast_list = mwifiex_set_multicast_list,
647};
648
649/*
650 * This function initializes the private structure parameters.
651 *
652 * The following wait queues are initialized -
653 * - IOCTL wait queue
654 * - Command wait queue
655 * - Statistics wait queue
656 *
657 * ...and the following default parameters are set -
658 * - Current key index : Set to 0
659 * - Rate index : Set to auto
660 * - Media connected : Set to disconnected
661 * - Adhoc link sensed : Set to false
662 * - Nick name : Set to null
663 * - Number of Tx timeout : Set to 0
664 * - Device address : Set to current address
665 *
666 * In addition, the CFG80211 work queue is also created.
667 */
668static void
669mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
670{
671 dev->netdev_ops = &mwifiex_netdev_ops;
672 /* Initialize private structure */
673 priv->current_key_index = 0;
674 priv->media_connected = false;
675 memset(&priv->nick_name, 0, sizeof(priv->nick_name));
676 priv->num_tx_timeout = 0;
677 priv->workqueue = create_singlethread_workqueue("cfg80211_wq");
678 INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results);
679 memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
680}
681
682/*
683 * This function adds a new logical interface.
684 *
685 * It allocates, initializes and registers the interface by performing
686 * the following opearations -
687 * - Allocate a new net device structure
688 * - Assign device name
689 * - Register the new device with CFG80211 subsystem
690 * - Initialize semaphore and private structure
691 * - Register the new device with kernel
692 * - Create the complete debug FS structure if configured
693 */
694static struct mwifiex_private *mwifiex_add_interface(
695 struct mwifiex_adapter *adapter,
696 u8 bss_index, u8 bss_type)
697{
698 struct net_device *dev;
699 struct mwifiex_private *priv;
700 void *mdev_priv;
701
702 dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
703 ether_setup, 1);
704 if (!dev) {
705 dev_err(adapter->dev, "no memory available for netdevice\n");
706 goto error;
707 }
708
709 if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
710 adapter->priv[bss_index]) != 0) {
711 dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
712 goto error;
713 }
714 /* Save the priv pointer in netdev */
715 priv = adapter->priv[bss_index];
716 mdev_priv = netdev_priv(dev);
717 *((unsigned long *) mdev_priv) = (unsigned long) priv;
718
719 priv->netdev = dev;
720
721 sema_init(&priv->async_sem, 1);
722 priv->scan_pending_on_block = false;
723
724 mwifiex_init_priv_params(priv, dev);
725
726 SET_NETDEV_DEV(dev, adapter->dev);
727
728 /* Register network device */
729 if (register_netdev(dev)) {
730 dev_err(adapter->dev, "cannot register virtual network device\n");
731 goto error;
732 }
733
734 dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
735#ifdef CONFIG_DEBUG_FS
736 mwifiex_dev_debugfs_init(priv);
737#endif
738 return priv;
739error:
740 if (dev)
741 free_netdev(dev);
742 return NULL;
743}
744
745/*
746 * This function removes a logical interface.
747 *
748 * It deregisters, resets and frees the interface by performing
749 * the following operations -
750 * - Disconnect the device if connected, send wireless event to
751 * notify applications.
752 * - Remove the debug FS structure if configured
753 * - Unregister the device from kernel
754 * - Free the net device structure
755 * - Cancel all works and destroy work queue
756 * - Unregister and free the wireless device from CFG80211 subsystem
757 */
758static void
759mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
760{
761 struct net_device *dev;
762 struct mwifiex_private *priv = adapter->priv[bss_index];
763
764 if (!priv)
765 return;
766 dev = priv->netdev;
767
768 if (priv->media_connected)
769 priv->media_connected = false;
770
771#ifdef CONFIG_DEBUG_FS
772 mwifiex_dev_debugfs_remove(priv);
773#endif
774 /* Last reference is our one */
775 dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
776 dev->name, netdev_refcnt_read(dev));
777
778 if (dev->reg_state == NETREG_REGISTERED)
779 unregister_netdev(dev);
780
781 /* Clear the priv in adapter */
782 priv->netdev = NULL;
783 if (dev)
784 free_netdev(dev);
785
786 cancel_work_sync(&priv->cfg_workqueue);
787 flush_workqueue(priv->workqueue);
788 destroy_workqueue(priv->workqueue);
789 wiphy_unregister(priv->wdev->wiphy);
790 wiphy_free(priv->wdev->wiphy);
791 kfree(priv->wdev);
792}
793
794/*
795 * This function check if command is pending.
796 */
797int is_command_pending(struct mwifiex_adapter *adapter)
798{
799 unsigned long flags;
800 int is_cmd_pend_q_empty;
801
802 spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
803 is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
804 spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
805
806 return !is_cmd_pend_q_empty;
807}
808
809/*
810 * This function returns the correct private structure pointer based
811 * upon the BSS number.
812 */
813struct mwifiex_private *
814mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index)
815{
816 if (!adapter || (bss_index >= adapter->priv_num))
817 return NULL;
818 return adapter->priv[bss_index];
819}
820
821/*
822 * This is the main work queue function.
823 *
824 * It handles the main process, which in turn handles the complete
825 * driver operations.
826 */
827static void mwifiex_main_work_queue(struct work_struct *work)
828{
829 struct mwifiex_adapter *adapter =
830 container_of(work, struct mwifiex_adapter, main_work);
831
832 if (adapter->surprise_removed)
833 return;
834 mwifiex_main_process(adapter);
835}
836
837/*
838 * This function cancels all works in the queue and destroys
839 * the main workqueue.
840 */
841static void
842mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
843{
844 flush_workqueue(adapter->workqueue);
845 destroy_workqueue(adapter->workqueue);
846 adapter->workqueue = NULL;
847}
848
849/*
850 * This function adds the card.
851 *
852 * This function follows the following major steps to set up the device -
853 * - Initialize software. This includes probing the card, registering
854 * the interface operations table, and allocating/initializing the
855 * adapter structure
856 * - Set up the netlink socket
857 * - Create and start the main work queue
858 * - Register the device
859 * - Initialize firmware and hardware
860 * - Add logical interfaces
861 */
862int
863mwifiex_add_card(void *card, struct semaphore *sem,
864 struct mwifiex_if_ops *if_ops)
865{
866 int i;
867 struct mwifiex_adapter *adapter;
868
869 if (down_interruptible(sem))
870 goto exit_sem_err;
871
872 if (mwifiex_init_sw(card, if_ops)) {
873 pr_err("%s: software init failed\n", __func__);
874 goto err_init_sw;
875 }
876
877 adapter = g_adapter;
878
879 adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
880 adapter->surprise_removed = false;
881 init_waitqueue_head(&adapter->init_wait_q);
882 adapter->is_suspended = false;
883 adapter->hs_activated = false;
884 init_waitqueue_head(&adapter->hs_activate_wait_q);
885 adapter->cmd_wait_q_required = false;
886 init_waitqueue_head(&adapter->cmd_wait_q.wait);
887 adapter->cmd_wait_q.condition = false;
888 adapter->cmd_wait_q.status = 0;
889
890 adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
891 if (!adapter->workqueue)
892 goto err_kmalloc;
893
894 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
895
896 /* Register the device. Fill up the private data structure with relevant
897 information from the card and request for the required IRQ. */
898 if (adapter->if_ops.register_dev(adapter)) {
899 pr_err("%s: failed to register mwifiex device\n", __func__);
900 goto err_registerdev;
901 }
902
903 if (mwifiex_init_hw_fw(adapter)) {
904 pr_err("%s: firmware init failed\n", __func__);
905 goto err_init_fw;
906 }
907
908 /* Add interfaces */
909 for (i = 0; i < adapter->drv_mode->intf_num; i++) {
910 if (!mwifiex_add_interface(adapter, i,
911 adapter->drv_mode->bss_attr[i].bss_type)) {
912 goto err_add_intf;
913 }
914 }
915
916 up(sem);
917
918 return 0;
919
920err_add_intf:
921 for (i = 0; i < adapter->priv_num; i++)
922 mwifiex_remove_interface(adapter, i);
923err_init_fw:
924 pr_debug("info: %s: unregister device\n", __func__);
925 adapter->if_ops.unregister_dev(adapter);
926err_registerdev:
927 adapter->surprise_removed = true;
928 mwifiex_terminate_workqueue(adapter);
929err_kmalloc:
930 if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
931 (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
932 pr_debug("info: %s: shutdown mwifiex\n", __func__);
933 adapter->init_wait_q_woken = false;
934
935 if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
936 wait_event_interruptible(adapter->init_wait_q,
937 adapter->init_wait_q_woken);
938 }
939
940 mwifiex_free_adapter(adapter);
941
942err_init_sw:
943 up(sem);
944
945exit_sem_err:
946 return -1;
947}
948EXPORT_SYMBOL_GPL(mwifiex_add_card);
949
950/*
951 * This function removes the card.
952 *
953 * This function follows the following major steps to remove the device -
954 * - Stop data traffic
955 * - Shutdown firmware
956 * - Remove the logical interfaces
957 * - Terminate the work queue
958 * - Unregister the device
959 * - Free the adapter structure
960 */
961int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
962{
963 struct mwifiex_private *priv = NULL;
964 int i;
965
966 if (down_interruptible(sem))
967 goto exit_sem_err;
968
969 if (!adapter)
970 goto exit_remove;
971
972 adapter->surprise_removed = true;
973
974 /* Stop data */
975 for (i = 0; i < adapter->priv_num; i++) {
976 priv = adapter->priv[i];
977 if (priv) {
978 if (!netif_queue_stopped(priv->netdev))
979 netif_stop_queue(priv->netdev);
980 if (netif_carrier_ok(priv->netdev))
981 netif_carrier_off(priv->netdev);
982 }
983 }
984
985 dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
986 adapter->init_wait_q_woken = false;
987
988 if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
989 wait_event_interruptible(adapter->init_wait_q,
990 adapter->init_wait_q_woken);
991 dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n");
992 if (atomic_read(&adapter->rx_pending) ||
993 atomic_read(&adapter->tx_pending) ||
994 atomic_read(&adapter->cmd_pending)) {
995 dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
996 "cmd_pending=%d\n",
997 atomic_read(&adapter->rx_pending),
998 atomic_read(&adapter->tx_pending),
999 atomic_read(&adapter->cmd_pending));
1000 }
1001
1002 /* Remove interface */
1003 for (i = 0; i < adapter->priv_num; i++)
1004 mwifiex_remove_interface(adapter, i);
1005
1006 mwifiex_terminate_workqueue(adapter);
1007
1008 /* Unregister device */
1009 dev_dbg(adapter->dev, "info: unregister device\n");
1010 adapter->if_ops.unregister_dev(adapter);
1011 /* Free adapter structure */
1012 dev_dbg(adapter->dev, "info: free adapter\n");
1013 mwifiex_free_adapter(adapter);
1014
1015exit_remove:
1016 up(sem);
1017exit_sem_err:
1018 return 0;
1019}
1020EXPORT_SYMBOL_GPL(mwifiex_remove_card);
1021
1022/*
1023 * This function initializes the module.
1024 *
1025 * The debug FS is also initialized if configured.
1026 */
1027static int
1028mwifiex_init_module(void)
1029{
1030#ifdef CONFIG_DEBUG_FS
1031 mwifiex_debugfs_init();
1032#endif
1033 return 0;
1034}
1035
1036/*
1037 * This function cleans up the module.
1038 *
1039 * The debug FS is removed if available.
1040 */
1041static void
1042mwifiex_cleanup_module(void)
1043{
1044#ifdef CONFIG_DEBUG_FS
1045 mwifiex_debugfs_remove();
1046#endif
1047}
1048
1049module_init(mwifiex_init_module);
1050module_exit(mwifiex_cleanup_module);
1051
1052MODULE_AUTHOR("Marvell International Ltd.");
1053MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION);
1054MODULE_VERSION(VERSION);
1055MODULE_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..8316b3cd92cd
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -0,0 +1,1009 @@
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_ASYNC_CMD,
46 MWIFIEX_SYNC_CMD
47};
48
49#define DRV_MODE_STA 0x1
50
51#define SD8787_W0 0x30
52#define SD8787_W1 0x31
53#define SD8787_A0 0x40
54#define SD8787_A1 0x41
55
56#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
57#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin"
58#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin"
59
60struct mwifiex_drv_mode {
61 u16 drv_mode;
62 u16 intf_num;
63 struct mwifiex_bss_attr *bss_attr;
64};
65
66
67#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
68
69#define MWIFIEX_TIMER_10S 10000
70#define MWIFIEX_TIMER_1S 1000
71
72#define MAX_TX_PENDING 100
73#define LOW_TX_PENDING 80
74
75#define MWIFIEX_UPLD_SIZE (2312)
76
77#define MAX_EVENT_SIZE 1024
78
79#define ARP_FILTER_MAX_BUF_SIZE 68
80
81#define MWIFIEX_KEY_BUFFER_SIZE 16
82#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10
83#define MWIFIEX_MAX_REGION_CODE 7
84
85#define DEFAULT_BCN_AVG_FACTOR 8
86#define DEFAULT_DATA_AVG_FACTOR 8
87
88#define FIRST_VALID_CHANNEL 0xff
89#define DEFAULT_AD_HOC_CHANNEL 6
90#define DEFAULT_AD_HOC_CHANNEL_A 36
91
92#define DEFAULT_BCN_MISS_TIMEOUT 5
93
94#define MAX_SCAN_BEACON_BUFFER 8000
95
96#define SCAN_BEACON_ENTRY_PAD 6
97
98#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200
99#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200
100#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110
101
102#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
103
104#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
105
106#define RSN_GTK_OUI_OFFSET 2
107
108#define MWIFIEX_OUI_NOT_PRESENT 0
109#define MWIFIEX_OUI_PRESENT 1
110
111#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
112 adapter->event_received || \
113 adapter->data_received)
114
115#define MWIFIEX_TYPE_CMD 1
116#define MWIFIEX_TYPE_DATA 0
117#define MWIFIEX_TYPE_EVENT 3
118
119#define DBG_CMD_NUM 5
120
121#define MAX_BITMAP_RATES_SIZE 10
122
123#define MAX_CHANNEL_BAND_BG 14
124
125#define MAX_FREQUENCY_BAND_BG 2484
126
127struct mwifiex_dbg {
128 u32 num_cmd_host_to_card_failure;
129 u32 num_cmd_sleep_cfm_host_to_card_failure;
130 u32 num_tx_host_to_card_failure;
131 u32 num_event_deauth;
132 u32 num_event_disassoc;
133 u32 num_event_link_lost;
134 u32 num_cmd_deauth;
135 u32 num_cmd_assoc_success;
136 u32 num_cmd_assoc_failure;
137 u32 num_tx_timeout;
138 u32 num_cmd_timeout;
139 u16 timeout_cmd_id;
140 u16 timeout_cmd_act;
141 u16 last_cmd_id[DBG_CMD_NUM];
142 u16 last_cmd_act[DBG_CMD_NUM];
143 u16 last_cmd_index;
144 u16 last_cmd_resp_id[DBG_CMD_NUM];
145 u16 last_cmd_resp_index;
146 u16 last_event[DBG_CMD_NUM];
147 u16 last_event_index;
148};
149
150enum MWIFIEX_HARDWARE_STATUS {
151 MWIFIEX_HW_STATUS_READY,
152 MWIFIEX_HW_STATUS_INITIALIZING,
153 MWIFIEX_HW_STATUS_FW_READY,
154 MWIFIEX_HW_STATUS_INIT_DONE,
155 MWIFIEX_HW_STATUS_RESET,
156 MWIFIEX_HW_STATUS_CLOSING,
157 MWIFIEX_HW_STATUS_NOT_READY
158};
159
160enum MWIFIEX_802_11_POWER_MODE {
161 MWIFIEX_802_11_POWER_MODE_CAM,
162 MWIFIEX_802_11_POWER_MODE_PSP
163};
164
165struct mwifiex_tx_param {
166 u32 next_pkt_len;
167};
168
169enum MWIFIEX_PS_STATE {
170 PS_STATE_AWAKE,
171 PS_STATE_PRE_SLEEP,
172 PS_STATE_SLEEP_CFM,
173 PS_STATE_SLEEP
174};
175
176struct mwifiex_add_ba_param {
177 u32 tx_win_size;
178 u32 rx_win_size;
179 u32 timeout;
180};
181
182struct mwifiex_tx_aggr {
183 u8 ampdu_user;
184 u8 ampdu_ap;
185 u8 amsdu;
186};
187
188struct mwifiex_ra_list_tbl {
189 struct list_head list;
190 struct sk_buff_head skb_head;
191 u8 ra[ETH_ALEN];
192 u32 total_pkts_size;
193 u32 is_11n_enabled;
194};
195
196struct mwifiex_tid_tbl {
197 struct list_head ra_list;
198 /* spin lock for tid table */
199 spinlock_t tid_tbl_lock;
200 struct mwifiex_ra_list_tbl *ra_list_curr;
201};
202
203#define WMM_HIGHEST_PRIORITY 7
204#define HIGH_PRIO_TID 7
205#define LOW_PRIO_TID 0
206#define NO_PKT_PRIO_TID (-1)
207
208struct mwifiex_wmm_desc {
209 struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
210 u32 packets_out[MAX_NUM_TID];
211 /* spin lock to protect ra_list */
212 spinlock_t ra_list_spinlock;
213 struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES];
214 enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES];
215 u32 drv_pkt_delay_max;
216 u8 queue_priority[IEEE80211_MAX_QUEUES];
217 u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
218 /* Number of transmit packets queued */
219 atomic_t tx_pkts_queued;
220 /* Tracks highest priority with a packet queued */
221 atomic_t highest_queued_prio;
222};
223
224struct mwifiex_802_11_security {
225 u8 wpa_enabled;
226 u8 wpa2_enabled;
227 u8 wapi_enabled;
228 u8 wapi_key_on;
229 enum MWIFIEX_802_11_WEP_STATUS wep_status;
230 u32 authentication_mode;
231 u32 encryption_mode;
232};
233
234struct ieee_types_header {
235 u8 element_id;
236 u8 len;
237} __packed;
238
239struct ieee_obss_scan_param {
240 u16 obss_scan_passive_dwell;
241 u16 obss_scan_active_dwell;
242 u16 bss_chan_width_trigger_scan_int;
243 u16 obss_scan_passive_total;
244 u16 obss_scan_active_total;
245 u16 bss_width_chan_trans_delay;
246 u16 obss_scan_active_threshold;
247} __packed;
248
249struct ieee_types_obss_scan_param {
250 struct ieee_types_header ieee_hdr;
251 struct ieee_obss_scan_param obss_scan;
252} __packed;
253
254#define MWIFIEX_SUPPORTED_RATES 14
255
256#define MWIFIEX_SUPPORTED_RATES_EXT 32
257
258#define IEEE_MAX_IE_SIZE 256
259
260struct ieee_types_vendor_specific {
261 struct ieee_types_vendor_header vend_hdr;
262 u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)];
263} __packed;
264
265struct ieee_types_generic {
266 struct ieee_types_header ieee_hdr;
267 u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)];
268} __packed;
269
270struct mwifiex_bssdescriptor {
271 u8 mac_address[ETH_ALEN];
272 struct mwifiex_802_11_ssid ssid;
273 u32 privacy;
274 s32 rssi;
275 u32 channel;
276 u32 freq;
277 u16 beacon_period;
278 u8 erp_flags;
279 u32 bss_mode;
280 u8 supported_rates[MWIFIEX_SUPPORTED_RATES];
281 u8 data_rates[MWIFIEX_SUPPORTED_RATES];
282 /* Network band.
283 * BAND_B(0x01): 'b' band
284 * BAND_G(0x02): 'g' band
285 * BAND_A(0X04): 'a' band
286 */
287 u16 bss_band;
288 u64 network_tsf;
289 u8 time_stamp[8];
290 union ieee_types_phy_param_set phy_param_set;
291 union ieee_types_ss_param_set ss_param_set;
292 u16 cap_info_bitmap;
293 struct ieee_types_wmm_parameter wmm_ie;
294 u8 disable_11n;
295 struct ieee80211_ht_cap *bcn_ht_cap;
296 u16 ht_cap_offset;
297 struct ieee80211_ht_info *bcn_ht_info;
298 u16 ht_info_offset;
299 u8 *bcn_bss_co_2040;
300 u16 bss_co_2040_offset;
301 u8 *bcn_ext_cap;
302 u16 ext_cap_offset;
303 struct ieee_types_obss_scan_param *bcn_obss_scan;
304 u16 overlap_bss_offset;
305 struct ieee_types_vendor_specific *bcn_wpa_ie;
306 u16 wpa_offset;
307 struct ieee_types_generic *bcn_rsn_ie;
308 u16 rsn_offset;
309 struct ieee_types_generic *bcn_wapi_ie;
310 u16 wapi_offset;
311 u8 *beacon_buf;
312 u32 beacon_buf_size;
313 u32 beacon_buf_size_max;
314
315};
316
317struct mwifiex_current_bss_params {
318 struct mwifiex_bssdescriptor bss_descriptor;
319 u8 wmm_enabled;
320 u8 wmm_uapsd_enabled;
321 u8 band;
322 u32 num_of_rates;
323 u8 data_rates[MWIFIEX_SUPPORTED_RATES];
324};
325
326struct mwifiex_sleep_params {
327 u16 sp_error;
328 u16 sp_offset;
329 u16 sp_stable_time;
330 u8 sp_cal_control;
331 u8 sp_ext_sleep_clk;
332 u16 sp_reserved;
333};
334
335struct mwifiex_sleep_period {
336 u16 period;
337 u16 reserved;
338};
339
340struct mwifiex_wep_key {
341 u32 length;
342 u32 key_index;
343 u32 key_length;
344 u8 key_material[MWIFIEX_KEY_BUFFER_SIZE];
345};
346
347#define MAX_REGION_CHANNEL_NUM 2
348
349struct mwifiex_chan_freq_power {
350 u16 channel;
351 u32 freq;
352 u16 max_tx_power;
353 u8 unsupported;
354};
355
356enum state_11d_t {
357 DISABLE_11D = 0,
358 ENABLE_11D = 1,
359};
360
361#define MWIFIEX_MAX_TRIPLET_802_11D 83
362
363struct mwifiex_802_11d_domain_reg {
364 u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
365 u8 no_of_triplet;
366 struct ieee80211_country_ie_triplet
367 triplet[MWIFIEX_MAX_TRIPLET_802_11D];
368};
369
370struct mwifiex_vendor_spec_cfg_ie {
371 u16 mask;
372 u16 flag;
373 u8 ie[MWIFIEX_MAX_VSIE_LEN];
374};
375
376struct wps {
377 u8 session_enable;
378};
379
380struct mwifiex_adapter;
381struct mwifiex_private;
382
383struct mwifiex_private {
384 struct mwifiex_adapter *adapter;
385 u8 bss_index;
386 u8 bss_type;
387 u8 bss_role;
388 u8 bss_priority;
389 u8 bss_num;
390 u8 frame_type;
391 u8 curr_addr[ETH_ALEN];
392 u8 media_connected;
393 u32 num_tx_timeout;
394 struct net_device *netdev;
395 struct net_device_stats stats;
396 u16 curr_pkt_filter;
397 u32 bss_mode;
398 u32 pkt_tx_ctrl;
399 u16 tx_power_level;
400 u8 max_tx_power_level;
401 u8 min_tx_power_level;
402 u8 tx_rate;
403 u8 tx_htinfo;
404 u8 rxpd_htinfo;
405 u8 rxpd_rate;
406 u16 rate_bitmap;
407 u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
408 u32 data_rate;
409 u8 is_data_rate_auto;
410 u16 bcn_avg_factor;
411 u16 data_avg_factor;
412 s16 data_rssi_last;
413 s16 data_nf_last;
414 s16 data_rssi_avg;
415 s16 data_nf_avg;
416 s16 bcn_rssi_last;
417 s16 bcn_nf_last;
418 s16 bcn_rssi_avg;
419 s16 bcn_nf_avg;
420 struct mwifiex_bssdescriptor *attempted_bss_desc;
421 struct mwifiex_802_11_ssid prev_ssid;
422 u8 prev_bssid[ETH_ALEN];
423 struct mwifiex_current_bss_params curr_bss_params;
424 u16 beacon_period;
425 u16 listen_interval;
426 u16 atim_window;
427 u8 adhoc_channel;
428 u8 adhoc_is_link_sensed;
429 u8 adhoc_state;
430 struct mwifiex_802_11_security sec_info;
431 struct mwifiex_wep_key wep_key[NUM_WEP_KEYS];
432 u16 wep_key_curr_index;
433 u8 wpa_ie[256];
434 u8 wpa_ie_len;
435 u8 wpa_is_gtk_set;
436 struct host_cmd_ds_802_11_key_material aes_key;
437 u8 wapi_ie[256];
438 u8 wapi_ie_len;
439 u8 wmm_required;
440 u8 wmm_enabled;
441 u8 wmm_qosinfo;
442 struct mwifiex_wmm_desc wmm;
443 struct list_head tx_ba_stream_tbl_ptr;
444 /* spin lock for tx_ba_stream_tbl_ptr queue */
445 spinlock_t tx_ba_stream_tbl_lock;
446 struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID];
447 struct mwifiex_add_ba_param add_ba_param;
448 u16 rx_seq[MAX_NUM_TID];
449 struct list_head rx_reorder_tbl_ptr;
450 /* spin lock for rx_reorder_tbl_ptr queue */
451 spinlock_t rx_reorder_tbl_lock;
452 /* spin lock for Rx packets */
453 spinlock_t rx_pkt_lock;
454
455#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500
456 u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE];
457 u32 assoc_rsp_size;
458
459#define MWIFIEX_GENIE_BUF_SIZE 256
460 u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE];
461 u8 gen_ie_buf_len;
462
463 struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM];
464
465#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256
466 u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE];
467 u8 assoc_tlv_buf_len;
468
469 u8 *curr_bcn_buf;
470 u32 curr_bcn_size;
471 /* spin lock for beacon buffer */
472 spinlock_t curr_bcn_buf_lock;
473 struct wireless_dev *wdev;
474 struct mwifiex_chan_freq_power cfp;
475 char version_str[128];
476#ifdef CONFIG_DEBUG_FS
477 struct dentry *dfs_dev_dir;
478#endif
479 u8 nick_name[16];
480 struct iw_statistics w_stats;
481 u16 current_key_index;
482 struct semaphore async_sem;
483 u8 scan_pending_on_block;
484 u8 report_scan_result;
485 struct cfg80211_scan_request *scan_request;
486 int scan_result_status;
487 int assoc_request;
488 u16 assoc_result;
489 int ibss_join_request;
490 u16 ibss_join_result;
491 bool disconnect;
492 u8 cfg_bssid[6];
493 struct workqueue_struct *workqueue;
494 struct work_struct cfg_workqueue;
495 u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
496 struct wps wps;
497 u8 scan_block;
498};
499
500enum mwifiex_ba_status {
501 BA_STREAM_NOT_SETUP = 0,
502 BA_STREAM_SETUP_INPROGRESS,
503 BA_STREAM_SETUP_COMPLETE
504};
505
506struct mwifiex_tx_ba_stream_tbl {
507 struct list_head list;
508 int tid;
509 u8 ra[ETH_ALEN];
510 enum mwifiex_ba_status ba_status;
511};
512
513struct mwifiex_rx_reorder_tbl;
514
515struct reorder_tmr_cnxt {
516 struct timer_list timer;
517 struct mwifiex_rx_reorder_tbl *ptr;
518 struct mwifiex_private *priv;
519};
520
521struct mwifiex_rx_reorder_tbl {
522 struct list_head list;
523 int tid;
524 u8 ta[ETH_ALEN];
525 int start_win;
526 int win_size;
527 void **rx_reorder_ptr;
528 struct reorder_tmr_cnxt timer_context;
529};
530
531struct mwifiex_bss_prio_node {
532 struct list_head list;
533 struct mwifiex_private *priv;
534};
535
536struct mwifiex_bss_prio_tbl {
537 struct list_head bss_prio_head;
538 /* spin lock for bss priority */
539 spinlock_t bss_prio_lock;
540 struct mwifiex_bss_prio_node *bss_prio_cur;
541};
542
543struct cmd_ctrl_node {
544 struct list_head list;
545 struct mwifiex_private *priv;
546 u32 cmd_oid;
547 u32 cmd_flag;
548 struct sk_buff *cmd_skb;
549 struct sk_buff *resp_skb;
550 void *data_buf;
551 u32 wait_q_enabled;
552 struct sk_buff *skb;
553};
554
555struct mwifiex_if_ops {
556 int (*init_if) (struct mwifiex_adapter *);
557 void (*cleanup_if) (struct mwifiex_adapter *);
558 int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
559 int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
560 int (*register_dev) (struct mwifiex_adapter *);
561 void (*unregister_dev) (struct mwifiex_adapter *);
562 int (*enable_int) (struct mwifiex_adapter *);
563 int (*process_int_status) (struct mwifiex_adapter *);
564 int (*host_to_card) (struct mwifiex_adapter *, u8,
565 u8 *payload, u32 pkt_len,
566 struct mwifiex_tx_param *);
567 int (*wakeup) (struct mwifiex_adapter *);
568 int (*wakeup_complete) (struct mwifiex_adapter *);
569
570 void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
571 void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
572};
573
574struct mwifiex_adapter {
575 struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
576 u8 priv_num;
577 struct mwifiex_drv_mode *drv_mode;
578 const struct firmware *firmware;
579 struct device *dev;
580 bool surprise_removed;
581 u32 fw_release_number;
582 u32 revision_id;
583 u16 init_wait_q_woken;
584 wait_queue_head_t init_wait_q;
585 void *card;
586 struct mwifiex_if_ops if_ops;
587 atomic_t rx_pending;
588 atomic_t tx_pending;
589 atomic_t cmd_pending;
590 struct workqueue_struct *workqueue;
591 struct work_struct main_work;
592 struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
593 /* spin lock for init/shutdown */
594 spinlock_t mwifiex_lock;
595 /* spin lock for main process */
596 spinlock_t main_proc_lock;
597 u32 mwifiex_processing;
598 u16 max_tx_buf_size;
599 u16 tx_buf_size;
600 u16 curr_tx_buf_size;
601 u32 ioport;
602 enum MWIFIEX_HARDWARE_STATUS hw_status;
603 u16 number_of_antenna;
604 u32 fw_cap_info;
605 /* spin lock for interrupt handling */
606 spinlock_t int_lock;
607 u8 int_status;
608 u32 event_cause;
609 struct sk_buff *event_skb;
610 u8 upld_buf[MWIFIEX_UPLD_SIZE];
611 u8 data_sent;
612 u8 cmd_sent;
613 u8 cmd_resp_received;
614 u8 event_received;
615 u8 data_received;
616 u16 seq_num;
617 struct cmd_ctrl_node *cmd_pool;
618 struct cmd_ctrl_node *curr_cmd;
619 /* spin lock for command */
620 spinlock_t mwifiex_cmd_lock;
621 u32 num_cmd_timeout;
622 u16 last_init_cmd;
623 struct timer_list cmd_timer;
624 struct list_head cmd_free_q;
625 /* spin lock for cmd_free_q */
626 spinlock_t cmd_free_q_lock;
627 struct list_head cmd_pending_q;
628 /* spin lock for cmd_pending_q */
629 spinlock_t cmd_pending_q_lock;
630 struct list_head scan_pending_q;
631 /* spin lock for scan_pending_q */
632 spinlock_t scan_pending_q_lock;
633 u32 scan_processing;
634 u16 region_code;
635 struct mwifiex_802_11d_domain_reg domain_reg;
636 struct mwifiex_bssdescriptor *scan_table;
637 u32 num_in_scan_table;
638 u16 scan_probes;
639 u32 scan_mode;
640 u16 specific_scan_time;
641 u16 active_scan_time;
642 u16 passive_scan_time;
643 u8 bcn_buf[MAX_SCAN_BEACON_BUFFER];
644 u8 *bcn_buf_end;
645 u8 fw_bands;
646 u8 adhoc_start_band;
647 u8 config_bands;
648 struct mwifiex_chan_scan_param_set *scan_channels;
649 u8 tx_lock_flag;
650 struct mwifiex_sleep_params sleep_params;
651 struct mwifiex_sleep_period sleep_period;
652 u16 ps_mode;
653 u32 ps_state;
654 u8 need_to_wakeup;
655 u16 multiple_dtim;
656 u16 local_listen_interval;
657 u16 null_pkt_interval;
658 struct sk_buff *sleep_cfm;
659 u16 bcn_miss_time_out;
660 u16 adhoc_awake_period;
661 u8 is_deep_sleep;
662 u8 delay_null_pkt;
663 u16 delay_to_ps;
664 u16 enhanced_ps_mode;
665 u8 pm_wakeup_card_req;
666 u16 gen_null_pkt;
667 u16 pps_uapsd_mode;
668 u32 pm_wakeup_fw_try;
669 u8 is_hs_configured;
670 struct mwifiex_hs_config_param hs_cfg;
671 u8 hs_activated;
672 u16 hs_activate_wait_q_woken;
673 wait_queue_head_t hs_activate_wait_q;
674 bool is_suspended;
675 u8 event_body[MAX_EVENT_SIZE];
676 u32 hw_dot_11n_dev_cap;
677 u8 hw_dev_mcs_support;
678 u8 adhoc_11n_enabled;
679 u8 chan_offset;
680 struct mwifiex_dbg dbg;
681 u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
682 u32 arp_filter_size;
683 u16 cmd_wait_q_required;
684 struct mwifiex_wait_queue cmd_wait_q;
685};
686
687int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
688void mwifiex_free_lock_list(struct mwifiex_adapter *adapter);
689
690int mwifiex_init_fw(struct mwifiex_adapter *adapter);
691
692int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter);
693
694int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter);
695
696int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);
697
698int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
699
700int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
701
702int mwifiex_process_event(struct mwifiex_adapter *adapter);
703
704int mwifiex_complete_cmd(struct mwifiex_adapter *adapter);
705
706int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
707 u16 cmd_action, u32 cmd_oid, void *data_buf);
708
709int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
710 u16 cmd_action, u32 cmd_oid, void *data_buf);
711
712void mwifiex_cmd_timeout_func(unsigned long function_context);
713
714int mwifiex_get_debug_info(struct mwifiex_private *,
715 struct mwifiex_debug_info *);
716
717int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter);
718int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
719void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
720void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
721
722void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
723 struct cmd_ctrl_node *cmd_node);
724
725void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
726 struct cmd_ctrl_node *cmd_node,
727 u32 addtail);
728
729int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter);
730int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter);
731int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
732 struct sk_buff *skb);
733int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
734 struct mwifiex_tx_param *tx_param);
735int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);
736int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
737 struct sk_buff *skb, int status);
738int mwifiex_recv_packet_complete(struct mwifiex_adapter *,
739 struct sk_buff *skb, int status);
740void mwifiex_clean_txrx(struct mwifiex_private *priv);
741u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);
742void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter);
743void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *,
744 u32);
745int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
746 struct host_cmd_ds_command *cmd,
747 u16 cmd_action, uint16_t ps_bitmap,
748 void *data_buf);
749int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
750 struct host_cmd_ds_command *resp,
751 void *data_buf);
752void mwifiex_process_hs_config(struct mwifiex_adapter *adapter);
753void mwifiex_hs_activated_event(struct mwifiex_private *priv,
754 u8 activated);
755int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
756 struct host_cmd_ds_command *resp);
757int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
758 struct sk_buff *skb);
759int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
760 u16 cmd_action, u32 cmd_oid,
761 void *data_buf, void *cmd_buf);
762int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
763 void *cmd_buf);
764int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
765 struct sk_buff *skb);
766int mwifiex_process_sta_event(struct mwifiex_private *);
767void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
768int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
769int mwifiex_scan_networks(struct mwifiex_private *priv,
770 const struct mwifiex_user_scan_cfg *user_scan_in);
771int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
772 void *data_buf);
773void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
774 struct cmd_ctrl_node *cmd_node);
775int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
776 struct host_cmd_ds_command *resp);
777s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
778 struct mwifiex_802_11_ssid *ssid, u8 *bssid,
779 u32 mode);
780s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
781 u32 mode);
782int mwifiex_find_best_network(struct mwifiex_private *priv,
783 struct mwifiex_ssid_bssid *req_ssid_bssid);
784s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
785 struct mwifiex_802_11_ssid *ssid2);
786int mwifiex_associate(struct mwifiex_private *priv,
787 struct mwifiex_bssdescriptor *bss_desc);
788int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
789 struct host_cmd_ds_command
790 *cmd, void *data_buf);
791int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
792 struct host_cmd_ds_command *resp);
793void mwifiex_reset_connect_state(struct mwifiex_private *priv);
794void mwifiex_2040_coex_event(struct mwifiex_private *priv);
795u8 mwifiex_band_to_radio_type(u8 band);
796int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
797int mwifiex_adhoc_start(struct mwifiex_private *priv,
798 struct mwifiex_802_11_ssid *adhoc_ssid);
799int mwifiex_adhoc_join(struct mwifiex_private *priv,
800 struct mwifiex_bssdescriptor *bss_desc);
801int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
802 struct host_cmd_ds_command *cmd,
803 void *data_buf);
804int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
805 struct host_cmd_ds_command *cmd,
806 void *data_buf);
807int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
808 struct host_cmd_ds_command *resp);
809int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd);
810struct mwifiex_chan_freq_power *
811 mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
812 struct mwifiex_private *priv,
813 u8 band, u16 channel);
814struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
815 struct mwifiex_private *priv,
816 u8 band, u32 freq);
817u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info);
818u32 mwifiex_find_freq_from_band_chan(u8, u8);
819int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
820 u8 **buffer);
821u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv,
822 u8 *rates);
823u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates);
824u8 mwifiex_data_rate_to_index(u32 rate);
825u8 mwifiex_is_rate_auto(struct mwifiex_private *priv);
826int mwifiex_get_rate_index(u16 *rateBitmap, int size);
827extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE];
828void mwifiex_save_curr_bcn(struct mwifiex_private *priv);
829void mwifiex_free_curr_bcn(struct mwifiex_private *priv);
830int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
831 struct host_cmd_ds_command *cmd);
832int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
833 struct host_cmd_ds_command *resp);
834int is_command_pending(struct mwifiex_adapter *adapter);
835
836/*
837 * This function checks if the queuing is RA based or not.
838 */
839static inline u8
840mwifiex_queuing_ra_based(struct mwifiex_private *priv)
841{
842 /*
843 * Currently we assume if we are in Infra, then DA=RA. This might not be
844 * true in the future
845 */
846 if ((priv->bss_mode == NL80211_IFTYPE_STATION) &&
847 (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA))
848 return false;
849
850 return true;
851}
852
853/*
854 * This function copies rates.
855 */
856static inline u32
857mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len)
858{
859 int i;
860
861 for (i = 0; i < len && src[i]; i++, pos++) {
862 if (pos >= MWIFIEX_SUPPORTED_RATES)
863 break;
864 dest[pos] = src[i];
865 }
866
867 return pos;
868}
869
870/*
871 * This function returns the correct private structure pointer based
872 * upon the BSS type and BSS number.
873 */
874static inline struct mwifiex_private *
875mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter,
876 u8 bss_num, u8 bss_type)
877{
878 int i;
879
880 for (i = 0; i < adapter->priv_num; i++) {
881 if (adapter->priv[i]) {
882 if ((adapter->priv[i]->bss_num == bss_num)
883 && (adapter->priv[i]->bss_type == bss_type))
884 break;
885 }
886 }
887 return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
888}
889
890/*
891 * This function returns the first available private structure pointer
892 * based upon the BSS role.
893 */
894static inline struct mwifiex_private *
895mwifiex_get_priv(struct mwifiex_adapter *adapter,
896 enum mwifiex_bss_role bss_role)
897{
898 int i;
899
900 for (i = 0; i < adapter->priv_num; i++) {
901 if (adapter->priv[i]) {
902 if (bss_role == MWIFIEX_BSS_ROLE_ANY ||
903 GET_BSS_ROLE(adapter->priv[i]) == bss_role)
904 break;
905 }
906 }
907
908 return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
909}
910
911/*
912 * This function returns the driver private structure of a network device.
913 */
914static inline struct mwifiex_private *
915mwifiex_netdev_get_priv(struct net_device *dev)
916{
917 return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev));
918}
919
920struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
921 *adapter, u8 bss_index);
922int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
923 u32 func_init_shutdown);
924int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
925int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
926
927void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
928 int maxlen);
929int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
930 struct mwifiex_multicast_list *mcast_list);
931int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
932 struct net_device *dev);
933int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
934int mwifiex_bss_start(struct mwifiex_private *priv,
935 struct mwifiex_ssid_bssid *ssid_bssid);
936int mwifiex_set_hs_params(struct mwifiex_private *priv,
937 u16 action, int cmd_type,
938 struct mwifiex_ds_hs_cfg *hscfg);
939int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
940int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
941int mwifiex_get_signal_info(struct mwifiex_private *priv,
942 struct mwifiex_ds_get_signal *signal);
943int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
944 struct mwifiex_rate_cfg *rate);
945int mwifiex_find_best_bss(struct mwifiex_private *priv,
946 struct mwifiex_ssid_bssid *ssid_bssid);
947int mwifiex_request_scan(struct mwifiex_private *priv,
948 struct mwifiex_802_11_ssid *req_ssid);
949int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
950 struct mwifiex_user_scan_cfg *scan_req);
951int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel);
952int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
953
954int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel);
955
956int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
957 int key_len, u8 key_index, int disable);
958
959int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
960
961int mwifiex_get_ver_ext(struct mwifiex_private *priv);
962
963int mwifiex_get_stats_info(struct mwifiex_private *priv,
964 struct mwifiex_ds_get_stats *log);
965
966int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
967 u32 reg_offset, u32 reg_value);
968
969int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
970 u32 reg_offset, u32 *value);
971
972int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
973 u8 *value);
974
975int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data);
976
977int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data);
978
979int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index);
980
981int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index);
982
983int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode);
984
985int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter,
986 char *version, int max_len);
987
988int mwifiex_set_tx_power(struct mwifiex_private *priv,
989 struct mwifiex_power_cfg *power_cfg);
990
991int mwifiex_main_process(struct mwifiex_adapter *);
992
993int mwifiex_bss_set_channel(struct mwifiex_private *,
994 struct mwifiex_chan_freq_power *cfp);
995int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *,
996 struct mwifiex_ssid_bssid *);
997int mwifiex_set_radio_band_cfg(struct mwifiex_private *,
998 struct mwifiex_ds_band_cfg *);
999int mwifiex_get_bss_info(struct mwifiex_private *,
1000 struct mwifiex_bss_info *);
1001
1002#ifdef CONFIG_DEBUG_FS
1003void mwifiex_debugfs_init(void);
1004void mwifiex_debugfs_remove(void);
1005
1006void mwifiex_dev_debugfs_init(struct mwifiex_private *priv);
1007void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv);
1008#endif
1009#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..5c22860fb40a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -0,0 +1,3025 @@
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;
121 struct ie_body *iebody;
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;
148 struct ie_body *iebody;
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 struct mwifiex_ssid_bssid *ssid_bssid)
182{
183 struct mwifiex_ssid_bssid tmp_ssid_bssid;
184 u8 *mac;
185
186 if (!ssid_bssid)
187 return -1;
188
189 memcpy(&tmp_ssid_bssid, ssid_bssid,
190 sizeof(struct mwifiex_ssid_bssid));
191
192 if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) {
193 memcpy(ssid_bssid, &tmp_ssid_bssid,
194 sizeof(struct mwifiex_ssid_bssid));
195 mac = (u8 *) &ssid_bssid->bssid;
196 dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
197 " %pM\n", ssid_bssid->ssid.ssid, mac);
198 return 0;
199 }
200
201 return -1;
202}
203
204/*
205 * Sends IOCTL request to start a scan with user configurations.
206 *
207 * This function allocates the IOCTL request buffer, fills it
208 * with requisite parameters and calls the IOCTL handler.
209 *
210 * Upon completion, it also generates a wireless event to notify
211 * applications.
212 */
213int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
214 struct mwifiex_user_scan_cfg *scan_req)
215{
216 int status;
217
218 priv->adapter->cmd_wait_q.condition = false;
219
220 status = mwifiex_scan_networks(priv, scan_req);
221 if (!status)
222 status = mwifiex_wait_queue_complete(priv->adapter);
223
224 return status;
225}
226
227/*
228 * This function checks if wapi is enabled in driver and scanned network is
229 * compatible with it.
230 */
231static bool
232mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv,
233 struct mwifiex_bssdescriptor *bss_desc)
234{
235 if (priv->sec_info.wapi_enabled &&
236 (bss_desc->bcn_wapi_ie &&
237 ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id ==
238 WLAN_EID_BSS_AC_ACCESS_DELAY))) {
239 return true;
240 }
241 return false;
242}
243
244/*
245 * This function checks if driver is configured with no security mode and
246 * scanned network is compatible with it.
247 */
248static bool
249mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
250 struct mwifiex_bssdescriptor *bss_desc)
251{
252 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
253 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
254 && ((!bss_desc->bcn_wpa_ie) ||
255 ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
256 WLAN_EID_WPA))
257 && ((!bss_desc->bcn_rsn_ie) ||
258 ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
259 WLAN_EID_RSN))
260 && !priv->sec_info.encryption_mode
261 && !bss_desc->privacy) {
262 return true;
263 }
264 return false;
265}
266
267/*
268 * This function checks if static WEP is enabled in driver and scanned network
269 * is compatible with it.
270 */
271static bool
272mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
273 struct mwifiex_bssdescriptor *bss_desc)
274{
275 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
276 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
277 && bss_desc->privacy) {
278 return true;
279 }
280 return false;
281}
282
283/*
284 * This function checks if wpa is enabled in driver and scanned network is
285 * compatible with it.
286 */
287static bool
288mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
289 struct mwifiex_bssdescriptor *bss_desc,
290 int index)
291{
292 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
293 && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
294 && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
295 element_id == WLAN_EID_WPA))
296 /*
297 * Privacy bit may NOT be set in some APs like
298 * LinkSys WRT54G && bss_desc->privacy
299 */
300 ) {
301 dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
302 " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
303 "EncMode=%#x privacy=%#x\n", __func__, index,
304 (bss_desc->bcn_wpa_ie) ?
305 (*(bss_desc->bcn_wpa_ie)).
306 vend_hdr.element_id : 0,
307 (bss_desc->bcn_rsn_ie) ?
308 (*(bss_desc->bcn_rsn_ie)).
309 ieee_hdr.element_id : 0,
310 (priv->sec_info.wep_status ==
311 MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
312 (priv->sec_info.wpa_enabled) ? "e" : "d",
313 (priv->sec_info.wpa2_enabled) ? "e" : "d",
314 priv->sec_info.encryption_mode,
315 bss_desc->privacy);
316 return true;
317 }
318 return false;
319}
320
321/*
322 * This function checks if wpa2 is enabled in driver and scanned network is
323 * compatible with it.
324 */
325static bool
326mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
327 struct mwifiex_bssdescriptor *bss_desc,
328 int index)
329{
330 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
331 && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
332 && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
333 element_id == WLAN_EID_RSN))
334 /*
335 * Privacy bit may NOT be set in some APs like
336 * LinkSys WRT54G && bss_desc->privacy
337 */
338 ) {
339 dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
340 " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
341 "EncMode=%#x privacy=%#x\n", __func__, index,
342 (bss_desc->bcn_wpa_ie) ?
343 (*(bss_desc->bcn_wpa_ie)).
344 vend_hdr.element_id : 0,
345 (bss_desc->bcn_rsn_ie) ?
346 (*(bss_desc->bcn_rsn_ie)).
347 ieee_hdr.element_id : 0,
348 (priv->sec_info.wep_status ==
349 MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
350 (priv->sec_info.wpa_enabled) ? "e" : "d",
351 (priv->sec_info.wpa2_enabled) ? "e" : "d",
352 priv->sec_info.encryption_mode,
353 bss_desc->privacy);
354 return true;
355 }
356 return false;
357}
358
359/*
360 * This function checks if adhoc AES is enabled in driver and scanned network is
361 * compatible with it.
362 */
363static bool
364mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
365 struct mwifiex_bssdescriptor *bss_desc)
366{
367 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
368 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
369 && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
370 element_id != WLAN_EID_WPA))
371 && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
372 element_id != WLAN_EID_RSN))
373 && !priv->sec_info.encryption_mode
374 && bss_desc->privacy) {
375 return true;
376 }
377 return false;
378}
379
380/*
381 * This function checks if dynamic WEP is enabled in driver and scanned network
382 * is compatible with it.
383 */
384static bool
385mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
386 struct mwifiex_bssdescriptor *bss_desc,
387 int index)
388{
389 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
390 && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
391 && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
392 element_id != WLAN_EID_WPA))
393 && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
394 element_id != WLAN_EID_RSN))
395 && priv->sec_info.encryption_mode
396 && bss_desc->privacy) {
397 dev_dbg(priv->adapter->dev, "info: %s: dynamic "
398 "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x "
399 "EncMode=%#x privacy=%#x\n",
400 __func__, index,
401 (bss_desc->bcn_wpa_ie) ?
402 (*(bss_desc->bcn_wpa_ie)).
403 vend_hdr.element_id : 0,
404 (bss_desc->bcn_rsn_ie) ?
405 (*(bss_desc->bcn_rsn_ie)).
406 ieee_hdr.element_id : 0,
407 priv->sec_info.encryption_mode,
408 bss_desc->privacy);
409 return true;
410 }
411 return false;
412}
413
414/*
415 * This function checks if a scanned network is compatible with the driver
416 * settings.
417 *
418 * WEP WPA WPA2 ad-hoc encrypt Network
419 * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
420 * 0 0 0 0 NONE 0 0 0 yes No security
421 * 0 1 0 0 x 1x 1 x yes WPA (disable
422 * HT if no AES)
423 * 0 0 1 0 x 1x x 1 yes WPA2 (disable
424 * HT if no AES)
425 * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
426 * 1 0 0 0 NONE 1 0 0 yes Static WEP
427 * (disable HT)
428 * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
429 *
430 * Compatibility is not matched while roaming, except for mode.
431 */
432static s32
433mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
434{
435 struct mwifiex_adapter *adapter = priv->adapter;
436 struct mwifiex_bssdescriptor *bss_desc;
437
438 bss_desc = &adapter->scan_table[index];
439 bss_desc->disable_11n = false;
440
441 /* Don't check for compatibility if roaming */
442 if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION)
443 && (bss_desc->bss_mode == NL80211_IFTYPE_STATION))
444 return index;
445
446 if (priv->wps.session_enable) {
447 dev_dbg(adapter->dev,
448 "info: return success directly in WPS period\n");
449 return index;
450 }
451
452 if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
453 dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
454 return index;
455 }
456
457 if (bss_desc->bss_mode == mode) {
458 if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
459 /* No security */
460 return index;
461 } else if (mwifiex_is_network_compatible_for_static_wep(priv,
462 bss_desc)) {
463 /* Static WEP enabled */
464 dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
465 bss_desc->disable_11n = true;
466 return index;
467 } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc,
468 index)) {
469 /* WPA enabled */
470 if (((priv->adapter->config_bands & BAND_GN
471 || priv->adapter->config_bands & BAND_AN)
472 && bss_desc->bcn_ht_cap)
473 && !mwifiex_is_wpa_oui_present(bss_desc,
474 CIPHER_SUITE_CCMP)) {
475
476 if (mwifiex_is_wpa_oui_present(bss_desc,
477 CIPHER_SUITE_TKIP)) {
478 dev_dbg(adapter->dev,
479 "info: Disable 11n if AES "
480 "is not supported by AP\n");
481 bss_desc->disable_11n = true;
482 } else {
483 return -1;
484 }
485 }
486 return index;
487 } else if (mwifiex_is_network_compatible_for_wpa2(priv,
488 bss_desc, index)) {
489 /* WPA2 enabled */
490 if (((priv->adapter->config_bands & BAND_GN
491 || priv->adapter->config_bands & BAND_AN)
492 && bss_desc->bcn_ht_cap)
493 && !mwifiex_is_rsn_oui_present(bss_desc,
494 CIPHER_SUITE_CCMP)) {
495
496 if (mwifiex_is_rsn_oui_present(bss_desc,
497 CIPHER_SUITE_TKIP)) {
498 dev_dbg(adapter->dev,
499 "info: Disable 11n if AES "
500 "is not supported by AP\n");
501 bss_desc->disable_11n = true;
502 } else {
503 return -1;
504 }
505 }
506 return index;
507 } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
508 bss_desc)) {
509 /* Ad-hoc AES enabled */
510 return index;
511 } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
512 bss_desc, index)) {
513 /* Dynamic WEP enabled */
514 return index;
515 }
516
517 /* Security doesn't match */
518 dev_dbg(adapter->dev, "info: %s: failed: index=%d "
519 "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
520 "=%#x privacy=%#x\n",
521 __func__, index,
522 (bss_desc->bcn_wpa_ie) ?
523 (*(bss_desc->bcn_wpa_ie)).vend_hdr.
524 element_id : 0,
525 (bss_desc->bcn_rsn_ie) ?
526 (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
527 element_id : 0,
528 (priv->sec_info.wep_status ==
529 MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
530 (priv->sec_info.wpa_enabled) ? "e" : "d",
531 (priv->sec_info.wpa2_enabled) ? "e" : "d",
532 priv->sec_info.encryption_mode, bss_desc->privacy);
533 return -1;
534 }
535
536 /* Mode doesn't match */
537 return -1;
538}
539
540/*
541 * This function finds the best SSID in the scan list.
542 *
543 * It searches the scan table for the best SSID that also matches the current
544 * adapter network preference (mode, security etc.).
545 */
546static s32
547mwifiex_find_best_network_in_list(struct mwifiex_private *priv)
548{
549 struct mwifiex_adapter *adapter = priv->adapter;
550 u32 mode = priv->bss_mode;
551 s32 best_net = -1;
552 s32 best_rssi = 0;
553 u32 i;
554
555 dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n",
556 adapter->num_in_scan_table);
557
558 for (i = 0; i < adapter->num_in_scan_table; i++) {
559 switch (mode) {
560 case NL80211_IFTYPE_STATION:
561 case NL80211_IFTYPE_ADHOC:
562 if (mwifiex_is_network_compatible(priv, i, mode) >= 0) {
563 if (SCAN_RSSI(adapter->scan_table[i].rssi) >
564 best_rssi) {
565 best_rssi = SCAN_RSSI(adapter->
566 scan_table[i].rssi);
567 best_net = i;
568 }
569 }
570 break;
571 case NL80211_IFTYPE_UNSPECIFIED:
572 default:
573 if (SCAN_RSSI(adapter->scan_table[i].rssi) >
574 best_rssi) {
575 best_rssi = SCAN_RSSI(adapter->scan_table[i].
576 rssi);
577 best_net = i;
578 }
579 break;
580 }
581 }
582
583 return best_net;
584}
585
586/*
587 * This function creates a channel list for the driver to scan, based
588 * on region/band information.
589 *
590 * This routine is used for any scan that is not provided with a
591 * specific channel list to scan.
592 */
593static void
594mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
595 const struct mwifiex_user_scan_cfg
596 *user_scan_in,
597 struct mwifiex_chan_scan_param_set
598 *scan_chan_list,
599 u8 filtered_scan)
600{
601 enum ieee80211_band band;
602 struct ieee80211_supported_band *sband;
603 struct ieee80211_channel *ch;
604 struct mwifiex_adapter *adapter = priv->adapter;
605 int chan_idx = 0, i;
606 u8 scan_type;
607
608 for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
609
610 if (!priv->wdev->wiphy->bands[band])
611 continue;
612
613 sband = priv->wdev->wiphy->bands[band];
614
615 for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
616 ch = &sband->channels[i];
617 if (ch->flags & IEEE80211_CHAN_DISABLED)
618 continue;
619 scan_chan_list[chan_idx].radio_type = band;
620 scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN;
621 if (user_scan_in &&
622 user_scan_in->chan_list[0].scan_time)
623 scan_chan_list[chan_idx].max_scan_time =
624 cpu_to_le16((u16) user_scan_in->
625 chan_list[0].scan_time);
626 else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
627 scan_chan_list[chan_idx].max_scan_time =
628 cpu_to_le16(adapter->passive_scan_time);
629 else
630 scan_chan_list[chan_idx].max_scan_time =
631 cpu_to_le16(adapter->active_scan_time);
632 if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
633 scan_chan_list[chan_idx].chan_scan_mode_bitmap
634 |= MWIFIEX_PASSIVE_SCAN;
635 else
636 scan_chan_list[chan_idx].chan_scan_mode_bitmap
637 &= ~MWIFIEX_PASSIVE_SCAN;
638 scan_chan_list[chan_idx].chan_number =
639 (u32) ch->hw_value;
640 if (filtered_scan) {
641 scan_chan_list[chan_idx].max_scan_time =
642 cpu_to_le16(adapter->specific_scan_time);
643 scan_chan_list[chan_idx].chan_scan_mode_bitmap
644 |= MWIFIEX_DISABLE_CHAN_FILT;
645 }
646 }
647
648 }
649}
650
651/*
652 * This function constructs and sends multiple scan config commands to
653 * the firmware.
654 *
655 * Previous routines in the code flow have created a scan command configuration
656 * with any requested TLVs. This function splits the channel TLV into maximum
657 * channels supported per scan lists and sends the portion of the channel TLV,
658 * along with the other TLVs, to the firmware.
659 */
660static int
661mwifiex_scan_channel_list(struct mwifiex_private *priv,
662 u32 max_chan_per_scan, u8 filtered_scan,
663 struct mwifiex_scan_cmd_config *scan_cfg_out,
664 struct mwifiex_ie_types_chan_list_param_set
665 *chan_tlv_out,
666 struct mwifiex_chan_scan_param_set *scan_chan_list)
667{
668 int ret = 0;
669 struct mwifiex_chan_scan_param_set *tmp_chan_list;
670 struct mwifiex_chan_scan_param_set *start_chan;
671
672 u32 tlv_idx;
673 u32 total_scan_time;
674 u32 done_early;
675
676 if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
677 dev_dbg(priv->adapter->dev,
678 "info: Scan: Null detect: %p, %p, %p\n",
679 scan_cfg_out, chan_tlv_out, scan_chan_list);
680 return -1;
681 }
682
683 chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
684
685 /* Set the temp channel struct pointer to the start of the desired
686 list */
687 tmp_chan_list = scan_chan_list;
688
689 /* Loop through the desired channel list, sending a new firmware scan
690 commands for each max_chan_per_scan channels (or for 1,6,11
691 individually if configured accordingly) */
692 while (tmp_chan_list->chan_number) {
693
694 tlv_idx = 0;
695 total_scan_time = 0;
696 chan_tlv_out->header.len = 0;
697 start_chan = tmp_chan_list;
698 done_early = false;
699
700 /*
701 * Construct the Channel TLV for the scan command. Continue to
702 * insert channel TLVs until:
703 * - the tlv_idx hits the maximum configured per scan command
704 * - the next channel to insert is 0 (end of desired channel
705 * list)
706 * - done_early is set (controlling individual scanning of
707 * 1,6,11)
708 */
709 while (tlv_idx < max_chan_per_scan
710 && tmp_chan_list->chan_number && !done_early) {
711
712 dev_dbg(priv->adapter->dev,
713 "info: Scan: Chan(%3d), Radio(%d),"
714 " Mode(%d, %d), Dur(%d)\n",
715 tmp_chan_list->chan_number,
716 tmp_chan_list->radio_type,
717 tmp_chan_list->chan_scan_mode_bitmap
718 & MWIFIEX_PASSIVE_SCAN,
719 (tmp_chan_list->chan_scan_mode_bitmap
720 & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
721 le16_to_cpu(tmp_chan_list->max_scan_time));
722
723 /* Copy the current channel TLV to the command being
724 prepared */
725 memcpy(chan_tlv_out->chan_scan_param + tlv_idx,
726 tmp_chan_list,
727 sizeof(chan_tlv_out->chan_scan_param));
728
729 /* Increment the TLV header length by the size
730 appended */
731 chan_tlv_out->header.len =
732 cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) +
733 (sizeof(chan_tlv_out->chan_scan_param)));
734
735 /*
736 * The tlv buffer length is set to the number of bytes
737 * of the between the channel tlv pointer and the start
738 * of the tlv buffer. This compensates for any TLVs
739 * that were appended before the channel list.
740 */
741 scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out -
742 scan_cfg_out->tlv_buf);
743
744 /* Add the size of the channel tlv header and the data
745 length */
746 scan_cfg_out->tlv_buf_len +=
747 (sizeof(chan_tlv_out->header)
748 + le16_to_cpu(chan_tlv_out->header.len));
749
750 /* Increment the index to the channel tlv we are
751 constructing */
752 tlv_idx++;
753
754 /* Count the total scan time per command */
755 total_scan_time +=
756 le16_to_cpu(tmp_chan_list->max_scan_time);
757
758 done_early = false;
759
760 /* Stop the loop if the *current* channel is in the
761 1,6,11 set and we are not filtering on a BSSID
762 or SSID. */
763 if (!filtered_scan && (tmp_chan_list->chan_number == 1
764 || tmp_chan_list->chan_number == 6
765 || tmp_chan_list->chan_number == 11))
766 done_early = true;
767
768 /* Increment the tmp pointer to the next channel to
769 be scanned */
770 tmp_chan_list++;
771
772 /* Stop the loop if the *next* channel is in the 1,6,11
773 set. This will cause it to be the only channel
774 scanned on the next interation */
775 if (!filtered_scan && (tmp_chan_list->chan_number == 1
776 || tmp_chan_list->chan_number == 6
777 || tmp_chan_list->chan_number == 11))
778 done_early = true;
779 }
780
781 /* The total scan time should be less than scan command timeout
782 value */
783 if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
784 dev_err(priv->adapter->dev, "total scan time %dms"
785 " is over limit (%dms), scan skipped\n",
786 total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
787 ret = -1;
788 break;
789 }
790
791 priv->adapter->scan_channels = start_chan;
792
793 /* Send the scan command to the firmware with the specified
794 cfg */
795 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN,
796 HostCmd_ACT_GEN_SET, 0,
797 scan_cfg_out);
798 if (ret)
799 break;
800 }
801
802 if (ret)
803 return -1;
804
805 return 0;
806}
807
808/*
809 * This function constructs a scan command configuration structure to use
810 * in scan commands.
811 *
812 * Application layer or other functions can invoke network scanning
813 * with a scan configuration supplied in a user scan configuration structure.
814 * This structure is used as the basis of one or many scan command configuration
815 * commands that are sent to the command processing module and eventually to the
816 * firmware.
817 *
818 * This function creates a scan command configuration structure based on the
819 * following user supplied parameters (if present):
820 * - SSID filter
821 * - BSSID filter
822 * - Number of Probes to be sent
823 * - Channel list
824 *
825 * If the SSID or BSSID filter is not present, the filter is disabled/cleared.
826 * If the number of probes is not set, adapter default setting is used.
827 */
828static void
829mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
830 const struct mwifiex_user_scan_cfg *user_scan_in,
831 struct mwifiex_scan_cmd_config *scan_cfg_out,
832 struct mwifiex_ie_types_chan_list_param_set
833 **chan_list_out,
834 struct mwifiex_chan_scan_param_set
835 *scan_chan_list,
836 u8 *max_chan_per_scan, u8 *filtered_scan,
837 u8 *scan_current_only)
838{
839 struct mwifiex_adapter *adapter = priv->adapter;
840 struct mwifiex_ie_types_num_probes *num_probes_tlv;
841 struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
842 struct mwifiex_ie_types_rates_param_set *rates_tlv;
843 const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
844 u8 *tlv_pos;
845 u32 num_probes;
846 u32 ssid_len;
847 u32 chan_idx;
848 u32 scan_type;
849 u16 scan_dur;
850 u8 channel;
851 u8 radio_type;
852 u32 ssid_idx;
853 u8 ssid_filter;
854 u8 rates[MWIFIEX_SUPPORTED_RATES];
855 u32 rates_size;
856 struct mwifiex_ie_types_htcap *ht_cap;
857
858 /* The tlv_buf_len is calculated for each scan command. The TLVs added
859 in this routine will be preserved since the routine that sends the
860 command will append channelTLVs at *chan_list_out. The difference
861 between the *chan_list_out and the tlv_buf start will be used to
862 calculate the size of anything we add in this routine. */
863 scan_cfg_out->tlv_buf_len = 0;
864
865 /* Running tlv pointer. Assigned to chan_list_out at end of function
866 so later routines know where channels can be added to the command
867 buf */
868 tlv_pos = scan_cfg_out->tlv_buf;
869
870 /* Initialize the scan as un-filtered; the flag is later set to TRUE
871 below if a SSID or BSSID filter is sent in the command */
872 *filtered_scan = false;
873
874 /* Initialize the scan as not being only on the current channel. If
875 the channel list is customized, only contains one channel, and is
876 the active channel, this is set true and data flow is not halted. */
877 *scan_current_only = false;
878
879 if (user_scan_in) {
880
881 /* Default the ssid_filter flag to TRUE, set false under
882 certain wildcard conditions and qualified by the existence
883 of an SSID list before marking the scan as filtered */
884 ssid_filter = true;
885
886 /* Set the BSS type scan filter, use Adapter setting if
887 unset */
888 scan_cfg_out->bss_mode =
889 (user_scan_in->bss_mode ? (u8) user_scan_in->
890 bss_mode : (u8) adapter->scan_mode);
891
892 /* Set the number of probes to send, use Adapter setting
893 if unset */
894 num_probes =
895 (user_scan_in->num_probes ? user_scan_in->
896 num_probes : adapter->scan_probes);
897
898 /*
899 * Set the BSSID filter to the incoming configuration,
900 * if non-zero. If not set, it will remain disabled
901 * (all zeros).
902 */
903 memcpy(scan_cfg_out->specific_bssid,
904 user_scan_in->specific_bssid,
905 sizeof(scan_cfg_out->specific_bssid));
906
907 for (ssid_idx = 0;
908 ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list))
909 && (*user_scan_in->ssid_list[ssid_idx].ssid
910 || user_scan_in->ssid_list[ssid_idx].max_len));
911 ssid_idx++) {
912
913 ssid_len = strlen(user_scan_in->ssid_list[ssid_idx].
914 ssid) + 1;
915
916 wildcard_ssid_tlv =
917 (struct mwifiex_ie_types_wildcard_ssid_params *)
918 tlv_pos;
919 wildcard_ssid_tlv->header.type =
920 cpu_to_le16(TLV_TYPE_WILDCARDSSID);
921 wildcard_ssid_tlv->header.len = cpu_to_le16(
922 (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
923 max_ssid_length)));
924 wildcard_ssid_tlv->max_ssid_length =
925 user_scan_in->ssid_list[ssid_idx].max_len;
926
927 memcpy(wildcard_ssid_tlv->ssid,
928 user_scan_in->ssid_list[ssid_idx].ssid,
929 ssid_len);
930
931 tlv_pos += (sizeof(wildcard_ssid_tlv->header)
932 + le16_to_cpu(wildcard_ssid_tlv->header.len));
933
934 dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n",
935 ssid_idx, wildcard_ssid_tlv->ssid,
936 wildcard_ssid_tlv->max_ssid_length);
937
938 /* Empty wildcard ssid with a maxlen will match many or
939 potentially all SSIDs (maxlen == 32), therefore do
940 not treat the scan as
941 filtered. */
942 if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
943 ssid_filter = false;
944
945 }
946
947 /*
948 * The default number of channels sent in the command is low to
949 * ensure the response buffer from the firmware does not
950 * truncate scan results. That is not an issue with an SSID
951 * or BSSID filter applied to the scan results in the firmware.
952 */
953 if ((ssid_idx && ssid_filter)
954 || memcmp(scan_cfg_out->specific_bssid, &zero_mac,
955 sizeof(zero_mac)))
956 *filtered_scan = true;
957 } else {
958 scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
959 num_probes = adapter->scan_probes;
960 }
961
962 /*
963 * If a specific BSSID or SSID is used, the number of channels in the
964 * scan command will be increased to the absolute maximum.
965 */
966 if (*filtered_scan)
967 *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
968 else
969 *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
970
971 /* If the input config or adapter has the number of Probes set,
972 add tlv */
973 if (num_probes) {
974
975 dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
976 num_probes);
977
978 num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
979 num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
980 num_probes_tlv->header.len =
981 cpu_to_le16(sizeof(num_probes_tlv->num_probes));
982 num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes);
983
984 tlv_pos += sizeof(num_probes_tlv->header) +
985 le16_to_cpu(num_probes_tlv->header.len);
986
987 }
988
989 /* Append rates tlv */
990 memset(rates, 0, sizeof(rates));
991
992 rates_size = mwifiex_get_supported_rates(priv, rates);
993
994 rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos;
995 rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
996 rates_tlv->header.len = cpu_to_le16((u16) rates_size);
997 memcpy(rates_tlv->rates, rates, rates_size);
998 tlv_pos += sizeof(rates_tlv->header) + rates_size;
999
1000 dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size);
1001
1002 if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
1003 && (priv->adapter->config_bands & BAND_GN
1004 || priv->adapter->config_bands & BAND_AN)) {
1005 ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos;
1006 memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
1007 ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1008 ht_cap->header.len =
1009 cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1010 radio_type =
1011 mwifiex_band_to_radio_type(priv->adapter->config_bands);
1012 mwifiex_fill_cap_info(priv, radio_type, ht_cap);
1013 tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
1014 }
1015
1016 /* Append vendor specific IE TLV */
1017 mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos);
1018
1019 /*
1020 * Set the output for the channel TLV to the address in the tlv buffer
1021 * past any TLVs that were added in this function (SSID, num_probes).
1022 * Channel TLVs will be added past this for each scan command,
1023 * preserving the TLVs that were previously added.
1024 */
1025 *chan_list_out =
1026 (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos;
1027
1028 if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
1029
1030 dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
1031
1032 for (chan_idx = 0;
1033 chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX
1034 && user_scan_in->chan_list[chan_idx].chan_number;
1035 chan_idx++) {
1036
1037 channel = user_scan_in->chan_list[chan_idx].chan_number;
1038 (scan_chan_list + chan_idx)->chan_number = channel;
1039
1040 radio_type =
1041 user_scan_in->chan_list[chan_idx].radio_type;
1042 (scan_chan_list + chan_idx)->radio_type = radio_type;
1043
1044 scan_type = user_scan_in->chan_list[chan_idx].scan_type;
1045
1046 if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1047 (scan_chan_list +
1048 chan_idx)->chan_scan_mode_bitmap
1049 |= MWIFIEX_PASSIVE_SCAN;
1050 else
1051 (scan_chan_list +
1052 chan_idx)->chan_scan_mode_bitmap
1053 &= ~MWIFIEX_PASSIVE_SCAN;
1054
1055 if (user_scan_in->chan_list[chan_idx].scan_time) {
1056 scan_dur = (u16) user_scan_in->
1057 chan_list[chan_idx].scan_time;
1058 } else {
1059 if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1060 scan_dur = adapter->passive_scan_time;
1061 else if (*filtered_scan)
1062 scan_dur = adapter->specific_scan_time;
1063 else
1064 scan_dur = adapter->active_scan_time;
1065 }
1066
1067 (scan_chan_list + chan_idx)->min_scan_time =
1068 cpu_to_le16(scan_dur);
1069 (scan_chan_list + chan_idx)->max_scan_time =
1070 cpu_to_le16(scan_dur);
1071 }
1072
1073 /* Check if we are only scanning the current channel */
1074 if ((chan_idx == 1)
1075 && (user_scan_in->chan_list[0].chan_number
1076 == priv->curr_bss_params.bss_descriptor.channel)) {
1077 *scan_current_only = true;
1078 dev_dbg(adapter->dev,
1079 "info: Scan: Scanning current channel only\n");
1080 }
1081
1082 } else {
1083 dev_dbg(adapter->dev,
1084 "info: Scan: Creating full region channel list\n");
1085 mwifiex_scan_create_channel_list(priv, user_scan_in,
1086 scan_chan_list,
1087 *filtered_scan);
1088 }
1089}
1090
1091/*
1092 * This function inspects the scan response buffer for pointers to
1093 * expected TLVs.
1094 *
1095 * TLVs can be included at the end of the scan response BSS information.
1096 *
1097 * Data in the buffer is parsed pointers to TLVs that can potentially
1098 * be passed back in the response.
1099 */
1100static void
1101mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
1102 struct mwifiex_ie_types_data *tlv,
1103 u32 tlv_buf_size, u32 req_tlv_type,
1104 struct mwifiex_ie_types_data **tlv_data)
1105{
1106 struct mwifiex_ie_types_data *current_tlv;
1107 u32 tlv_buf_left;
1108 u32 tlv_type;
1109 u32 tlv_len;
1110
1111 current_tlv = tlv;
1112 tlv_buf_left = tlv_buf_size;
1113 *tlv_data = NULL;
1114
1115 dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
1116 tlv_buf_size);
1117
1118 while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
1119
1120 tlv_type = le16_to_cpu(current_tlv->header.type);
1121 tlv_len = le16_to_cpu(current_tlv->header.len);
1122
1123 if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
1124 dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
1125 break;
1126 }
1127
1128 if (req_tlv_type == tlv_type) {
1129 switch (tlv_type) {
1130 case TLV_TYPE_TSFTIMESTAMP:
1131 dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
1132 "timestamp TLV, len = %d\n", tlv_len);
1133 *tlv_data = (struct mwifiex_ie_types_data *)
1134 current_tlv;
1135 break;
1136 case TLV_TYPE_CHANNELBANDLIST:
1137 dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
1138 " band list TLV, len = %d\n", tlv_len);
1139 *tlv_data = (struct mwifiex_ie_types_data *)
1140 current_tlv;
1141 break;
1142 default:
1143 dev_err(adapter->dev,
1144 "SCAN_RESP: unhandled TLV = %d\n",
1145 tlv_type);
1146 /* Give up, this seems corrupted */
1147 return;
1148 }
1149 }
1150
1151 if (*tlv_data)
1152 break;
1153
1154
1155 tlv_buf_left -= (sizeof(tlv->header) + tlv_len);
1156 current_tlv =
1157 (struct mwifiex_ie_types_data *) (current_tlv->data +
1158 tlv_len);
1159
1160 } /* while */
1161}
1162
1163/*
1164 * This function interprets a BSS scan response returned from the firmware.
1165 *
1166 * The various fixed fields and IEs are parsed and passed back for a BSS
1167 * probe response or beacon from scan command. Information is recorded as
1168 * needed in the scan table for that entry.
1169 *
1170 * The following IE types are recognized and parsed -
1171 * - SSID
1172 * - Supported rates
1173 * - FH parameters set
1174 * - DS parameters set
1175 * - CF parameters set
1176 * - IBSS parameters set
1177 * - ERP information
1178 * - Extended supported rates
1179 * - Vendor specific (221)
1180 * - RSN IE
1181 * - WAPI IE
1182 * - HT capability
1183 * - HT operation
1184 * - BSS Coexistence 20/40
1185 * - Extended capability
1186 * - Overlapping BSS scan parameters
1187 */
1188static int
1189mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
1190 struct mwifiex_bssdescriptor *bss_entry,
1191 u8 **beacon_info, u32 *bytes_left)
1192{
1193 int ret = 0;
1194 u8 element_id;
1195 struct ieee_types_fh_param_set *fh_param_set;
1196 struct ieee_types_ds_param_set *ds_param_set;
1197 struct ieee_types_cf_param_set *cf_param_set;
1198 struct ieee_types_ibss_param_set *ibss_param_set;
1199 __le16 beacon_interval;
1200 __le16 capabilities;
1201 u8 *current_ptr;
1202 u8 *rate;
1203 u8 element_len;
1204 u16 total_ie_len;
1205 u8 bytes_to_copy;
1206 u8 rate_size;
1207 u16 beacon_size;
1208 u8 found_data_rate_ie;
1209 u32 bytes_left_for_current_beacon;
1210 struct ieee_types_vendor_specific *vendor_ie;
1211 const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
1212 const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
1213
1214 found_data_rate_ie = false;
1215 rate_size = 0;
1216 beacon_size = 0;
1217
1218 if (*bytes_left >= sizeof(beacon_size)) {
1219 /* Extract & convert beacon size from the command buffer */
1220 memcpy(&beacon_size, *beacon_info, sizeof(beacon_size));
1221 *bytes_left -= sizeof(beacon_size);
1222 *beacon_info += sizeof(beacon_size);
1223 }
1224
1225 if (!beacon_size || beacon_size > *bytes_left) {
1226 *beacon_info += *bytes_left;
1227 *bytes_left = 0;
1228 return -1;
1229 }
1230
1231 /* Initialize the current working beacon pointer for this BSS
1232 iteration */
1233 current_ptr = *beacon_info;
1234
1235 /* Advance the return beacon pointer past the current beacon */
1236 *beacon_info += beacon_size;
1237 *bytes_left -= beacon_size;
1238
1239 bytes_left_for_current_beacon = beacon_size;
1240
1241 memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN);
1242 dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n",
1243 bss_entry->mac_address);
1244
1245 current_ptr += ETH_ALEN;
1246 bytes_left_for_current_beacon -= ETH_ALEN;
1247
1248 if (bytes_left_for_current_beacon < 12) {
1249 dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
1250 return -1;
1251 }
1252
1253 /*
1254 * Next 4 fields are RSSI, time stamp, beacon interval,
1255 * and capability information
1256 */
1257
1258 /* RSSI is 1 byte long */
1259 bss_entry->rssi = (s32) (*current_ptr);
1260 dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr);
1261 current_ptr += 1;
1262 bytes_left_for_current_beacon -= 1;
1263
1264 /*
1265 * The RSSI is not part of the beacon/probe response. After we have
1266 * advanced current_ptr past the RSSI field, save the remaining
1267 * data for use at the application layer
1268 */
1269 bss_entry->beacon_buf = current_ptr;
1270 bss_entry->beacon_buf_size = bytes_left_for_current_beacon;
1271
1272 /* Time stamp is 8 bytes long */
1273 memcpy(bss_entry->time_stamp, current_ptr, 8);
1274 current_ptr += 8;
1275 bytes_left_for_current_beacon -= 8;
1276
1277 /* Beacon interval is 2 bytes long */
1278 memcpy(&beacon_interval, current_ptr, 2);
1279 bss_entry->beacon_period = le16_to_cpu(beacon_interval);
1280 current_ptr += 2;
1281 bytes_left_for_current_beacon -= 2;
1282
1283 /* Capability information is 2 bytes long */
1284 memcpy(&capabilities, current_ptr, 2);
1285 dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
1286 capabilities);
1287 bss_entry->cap_info_bitmap = le16_to_cpu(capabilities);
1288 current_ptr += 2;
1289 bytes_left_for_current_beacon -= 2;
1290
1291 /* Rest of the current buffer are IE's */
1292 dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
1293 bytes_left_for_current_beacon);
1294
1295 if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
1296 dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n");
1297 bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
1298 } else {
1299 bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
1300 }
1301
1302 if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
1303 bss_entry->bss_mode = NL80211_IFTYPE_ADHOC;
1304 else
1305 bss_entry->bss_mode = NL80211_IFTYPE_STATION;
1306
1307
1308 /* Process variable IE */
1309 while (bytes_left_for_current_beacon >= 2) {
1310 element_id = *current_ptr;
1311 element_len = *(current_ptr + 1);
1312 total_ie_len = element_len + sizeof(struct ieee_types_header);
1313
1314 if (bytes_left_for_current_beacon < total_ie_len) {
1315 dev_err(adapter->dev, "err: InterpretIE: in processing"
1316 " IE, bytes left < IE length\n");
1317 bytes_left_for_current_beacon = 0;
1318 ret = -1;
1319 continue;
1320 }
1321 switch (element_id) {
1322 case WLAN_EID_SSID:
1323 bss_entry->ssid.ssid_len = element_len;
1324 memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
1325 element_len);
1326 dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n",
1327 bss_entry->ssid.ssid);
1328 break;
1329
1330 case WLAN_EID_SUPP_RATES:
1331 memcpy(bss_entry->data_rates, current_ptr + 2,
1332 element_len);
1333 memcpy(bss_entry->supported_rates, current_ptr + 2,
1334 element_len);
1335 rate_size = element_len;
1336 found_data_rate_ie = true;
1337 break;
1338
1339 case WLAN_EID_FH_PARAMS:
1340 fh_param_set =
1341 (struct ieee_types_fh_param_set *) current_ptr;
1342 memcpy(&bss_entry->phy_param_set.fh_param_set,
1343 fh_param_set,
1344 sizeof(struct ieee_types_fh_param_set));
1345 break;
1346
1347 case WLAN_EID_DS_PARAMS:
1348 ds_param_set =
1349 (struct ieee_types_ds_param_set *) current_ptr;
1350
1351 bss_entry->channel = ds_param_set->current_chan;
1352
1353 memcpy(&bss_entry->phy_param_set.ds_param_set,
1354 ds_param_set,
1355 sizeof(struct ieee_types_ds_param_set));
1356 break;
1357
1358 case WLAN_EID_CF_PARAMS:
1359 cf_param_set =
1360 (struct ieee_types_cf_param_set *) current_ptr;
1361 memcpy(&bss_entry->ss_param_set.cf_param_set,
1362 cf_param_set,
1363 sizeof(struct ieee_types_cf_param_set));
1364 break;
1365
1366 case WLAN_EID_IBSS_PARAMS:
1367 ibss_param_set =
1368 (struct ieee_types_ibss_param_set *)
1369 current_ptr;
1370 memcpy(&bss_entry->ss_param_set.ibss_param_set,
1371 ibss_param_set,
1372 sizeof(struct ieee_types_ibss_param_set));
1373 break;
1374
1375 case WLAN_EID_ERP_INFO:
1376 bss_entry->erp_flags = *(current_ptr + 2);
1377 break;
1378
1379 case WLAN_EID_EXT_SUPP_RATES:
1380 /*
1381 * Only process extended supported rate
1382 * if data rate is already found.
1383 * Data rate IE should come before
1384 * extended supported rate IE
1385 */
1386 if (found_data_rate_ie) {
1387 if ((element_len + rate_size) >
1388 MWIFIEX_SUPPORTED_RATES)
1389 bytes_to_copy =
1390 (MWIFIEX_SUPPORTED_RATES -
1391 rate_size);
1392 else
1393 bytes_to_copy = element_len;
1394
1395 rate = (u8 *) bss_entry->data_rates;
1396 rate += rate_size;
1397 memcpy(rate, current_ptr + 2, bytes_to_copy);
1398
1399 rate = (u8 *) bss_entry->supported_rates;
1400 rate += rate_size;
1401 memcpy(rate, current_ptr + 2, bytes_to_copy);
1402 }
1403 break;
1404
1405 case WLAN_EID_VENDOR_SPECIFIC:
1406 vendor_ie = (struct ieee_types_vendor_specific *)
1407 current_ptr;
1408
1409 if (!memcmp
1410 (vendor_ie->vend_hdr.oui, wpa_oui,
1411 sizeof(wpa_oui))) {
1412 bss_entry->bcn_wpa_ie =
1413 (struct ieee_types_vendor_specific *)
1414 current_ptr;
1415 bss_entry->wpa_offset = (u16) (current_ptr -
1416 bss_entry->beacon_buf);
1417 } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
1418 sizeof(wmm_oui))) {
1419 if (total_ie_len ==
1420 sizeof(struct ieee_types_wmm_parameter)
1421 || total_ie_len ==
1422 sizeof(struct ieee_types_wmm_info))
1423 /*
1424 * Only accept and copy the WMM IE if
1425 * it matches the size expected for the
1426 * WMM Info IE or the WMM Parameter IE.
1427 */
1428 memcpy((u8 *) &bss_entry->wmm_ie,
1429 current_ptr, total_ie_len);
1430 }
1431 break;
1432 case WLAN_EID_RSN:
1433 bss_entry->bcn_rsn_ie =
1434 (struct ieee_types_generic *) current_ptr;
1435 bss_entry->rsn_offset = (u16) (current_ptr -
1436 bss_entry->beacon_buf);
1437 break;
1438 case WLAN_EID_BSS_AC_ACCESS_DELAY:
1439 bss_entry->bcn_wapi_ie =
1440 (struct ieee_types_generic *) current_ptr;
1441 bss_entry->wapi_offset = (u16) (current_ptr -
1442 bss_entry->beacon_buf);
1443 break;
1444 case WLAN_EID_HT_CAPABILITY:
1445 bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
1446 (current_ptr +
1447 sizeof(struct ieee_types_header));
1448 bss_entry->ht_cap_offset = (u16) (current_ptr +
1449 sizeof(struct ieee_types_header) -
1450 bss_entry->beacon_buf);
1451 break;
1452 case WLAN_EID_HT_INFORMATION:
1453 bss_entry->bcn_ht_info = (struct ieee80211_ht_info *)
1454 (current_ptr +
1455 sizeof(struct ieee_types_header));
1456 bss_entry->ht_info_offset = (u16) (current_ptr +
1457 sizeof(struct ieee_types_header) -
1458 bss_entry->beacon_buf);
1459 break;
1460 case WLAN_EID_BSS_COEX_2040:
1461 bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr +
1462 sizeof(struct ieee_types_header));
1463 bss_entry->bss_co_2040_offset = (u16) (current_ptr +
1464 sizeof(struct ieee_types_header) -
1465 bss_entry->beacon_buf);
1466 break;
1467 case WLAN_EID_EXT_CAPABILITY:
1468 bss_entry->bcn_ext_cap = (u8 *) (current_ptr +
1469 sizeof(struct ieee_types_header));
1470 bss_entry->ext_cap_offset = (u16) (current_ptr +
1471 sizeof(struct ieee_types_header) -
1472 bss_entry->beacon_buf);
1473 break;
1474 case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
1475 bss_entry->bcn_obss_scan =
1476 (struct ieee_types_obss_scan_param *)
1477 current_ptr;
1478 bss_entry->overlap_bss_offset = (u16) (current_ptr -
1479 bss_entry->beacon_buf);
1480 break;
1481 default:
1482 break;
1483 }
1484
1485 current_ptr += element_len + 2;
1486
1487 /* Need to account for IE ID and IE Len */
1488 bytes_left_for_current_beacon -= (element_len + 2);
1489
1490 } /* while (bytes_left_for_current_beacon > 2) */
1491 return ret;
1492}
1493
1494/*
1495 * This function adjusts the pointers used in beacon buffers to reflect
1496 * shifts.
1497 *
1498 * The memory allocated for beacon buffers is of fixed sizes where all the
1499 * saved beacons must be stored. New beacons are added in the free portion
1500 * of this memory, space permitting; while duplicate beacon buffers are
1501 * placed at the same start location. However, since duplicate beacon
1502 * buffers may not match the size of the old one, all the following buffers
1503 * in the memory must be shifted to either make space, or to fill up freed
1504 * up space.
1505 *
1506 * This function is used to update the beacon buffer pointers that are past
1507 * an existing beacon buffer that is updated with a new one of different
1508 * size. The pointers are shifted by a fixed amount, either forward or
1509 * backward.
1510 *
1511 * the following pointers in every affected beacon buffers are changed, if
1512 * present -
1513 * - WPA IE pointer
1514 * - RSN IE pointer
1515 * - WAPI IE pointer
1516 * - HT capability IE pointer
1517 * - HT information IE pointer
1518 * - BSS coexistence 20/40 IE pointer
1519 * - Extended capability IE pointer
1520 * - Overlapping BSS scan parameter IE pointer
1521 */
1522static void
1523mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance,
1524 u8 *bcn_store, u32 rem_bcn_size,
1525 u32 num_of_ent)
1526{
1527 struct mwifiex_adapter *adapter = priv->adapter;
1528 u32 adj_idx;
1529 for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
1530 if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) {
1531
1532 if (advance)
1533 adapter->scan_table[adj_idx].beacon_buf +=
1534 rem_bcn_size;
1535 else
1536 adapter->scan_table[adj_idx].beacon_buf -=
1537 rem_bcn_size;
1538
1539 if (adapter->scan_table[adj_idx].bcn_wpa_ie)
1540 adapter->scan_table[adj_idx].bcn_wpa_ie =
1541 (struct ieee_types_vendor_specific *)
1542 (adapter->scan_table[adj_idx].beacon_buf +
1543 adapter->scan_table[adj_idx].wpa_offset);
1544 if (adapter->scan_table[adj_idx].bcn_rsn_ie)
1545 adapter->scan_table[adj_idx].bcn_rsn_ie =
1546 (struct ieee_types_generic *)
1547 (adapter->scan_table[adj_idx].beacon_buf +
1548 adapter->scan_table[adj_idx].rsn_offset);
1549 if (adapter->scan_table[adj_idx].bcn_wapi_ie)
1550 adapter->scan_table[adj_idx].bcn_wapi_ie =
1551 (struct ieee_types_generic *)
1552 (adapter->scan_table[adj_idx].beacon_buf +
1553 adapter->scan_table[adj_idx].wapi_offset);
1554 if (adapter->scan_table[adj_idx].bcn_ht_cap)
1555 adapter->scan_table[adj_idx].bcn_ht_cap =
1556 (struct ieee80211_ht_cap *)
1557 (adapter->scan_table[adj_idx].beacon_buf +
1558 adapter->scan_table[adj_idx].ht_cap_offset);
1559
1560 if (adapter->scan_table[adj_idx].bcn_ht_info)
1561 adapter->scan_table[adj_idx].bcn_ht_info =
1562 (struct ieee80211_ht_info *)
1563 (adapter->scan_table[adj_idx].beacon_buf +
1564 adapter->scan_table[adj_idx].ht_info_offset);
1565 if (adapter->scan_table[adj_idx].bcn_bss_co_2040)
1566 adapter->scan_table[adj_idx].bcn_bss_co_2040 =
1567 (u8 *)
1568 (adapter->scan_table[adj_idx].beacon_buf +
1569 adapter->scan_table[adj_idx].bss_co_2040_offset);
1570 if (adapter->scan_table[adj_idx].bcn_ext_cap)
1571 adapter->scan_table[adj_idx].bcn_ext_cap =
1572 (u8 *)
1573 (adapter->scan_table[adj_idx].beacon_buf +
1574 adapter->scan_table[adj_idx].ext_cap_offset);
1575 if (adapter->scan_table[adj_idx].bcn_obss_scan)
1576 adapter->scan_table[adj_idx].bcn_obss_scan =
1577 (struct ieee_types_obss_scan_param *)
1578 (adapter->scan_table[adj_idx].beacon_buf +
1579 adapter->scan_table[adj_idx].overlap_bss_offset);
1580 }
1581 }
1582}
1583
1584/*
1585 * This function updates the pointers used in beacon buffer for given bss
1586 * descriptor to reflect shifts
1587 *
1588 * Following pointers are updated
1589 * - WPA IE pointer
1590 * - RSN IE pointer
1591 * - WAPI IE pointer
1592 * - HT capability IE pointer
1593 * - HT information IE pointer
1594 * - BSS coexistence 20/40 IE pointer
1595 * - Extended capability IE pointer
1596 * - Overlapping BSS scan parameter IE pointer
1597 */
1598static void
1599mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon)
1600{
1601 if (beacon->bcn_wpa_ie)
1602 beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *)
1603 (beacon->beacon_buf + beacon->wpa_offset);
1604 if (beacon->bcn_rsn_ie)
1605 beacon->bcn_rsn_ie = (struct ieee_types_generic *)
1606 (beacon->beacon_buf + beacon->rsn_offset);
1607 if (beacon->bcn_wapi_ie)
1608 beacon->bcn_wapi_ie = (struct ieee_types_generic *)
1609 (beacon->beacon_buf + beacon->wapi_offset);
1610 if (beacon->bcn_ht_cap)
1611 beacon->bcn_ht_cap = (struct ieee80211_ht_cap *)
1612 (beacon->beacon_buf + beacon->ht_cap_offset);
1613 if (beacon->bcn_ht_info)
1614 beacon->bcn_ht_info = (struct ieee80211_ht_info *)
1615 (beacon->beacon_buf + beacon->ht_info_offset);
1616 if (beacon->bcn_bss_co_2040)
1617 beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf +
1618 beacon->bss_co_2040_offset);
1619 if (beacon->bcn_ext_cap)
1620 beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf +
1621 beacon->ext_cap_offset);
1622 if (beacon->bcn_obss_scan)
1623 beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *)
1624 (beacon->beacon_buf + beacon->overlap_bss_offset);
1625}
1626
1627/*
1628 * This function stores a beacon or probe response for a BSS returned
1629 * in the scan.
1630 *
1631 * This stores a new scan response or an update for a previous scan response.
1632 * New entries need to verify that they do not exceed the total amount of
1633 * memory allocated for the table.
1634 *
1635 * Replacement entries need to take into consideration the amount of space
1636 * currently allocated for the beacon/probe response and adjust the entry
1637 * as needed.
1638 *
1639 * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
1640 * for an entry in case it is a beacon since a probe response for the
1641 * network will by larger per the standard. This helps to reduce the
1642 * amount of memory copying to fit a new probe response into an entry
1643 * already occupied by a network's previously stored beacon.
1644 */
1645static void
1646mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv,
1647 u32 beacon_idx, u32 num_of_ent,
1648 struct mwifiex_bssdescriptor *new_beacon)
1649{
1650 struct mwifiex_adapter *adapter = priv->adapter;
1651 u8 *bcn_store;
1652 u32 new_bcn_size;
1653 u32 old_bcn_size;
1654 u32 bcn_space;
1655
1656 if (adapter->scan_table[beacon_idx].beacon_buf) {
1657
1658 new_bcn_size = new_beacon->beacon_buf_size;
1659 old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size;
1660 bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max;
1661 bcn_store = adapter->scan_table[beacon_idx].beacon_buf;
1662
1663 /* Set the max to be the same as current entry unless changed
1664 below */
1665 new_beacon->beacon_buf_size_max = bcn_space;
1666 if (new_bcn_size == old_bcn_size) {
1667 /*
1668 * Beacon is the same size as the previous entry.
1669 * Replace the previous contents with the scan result
1670 */
1671 memcpy(bcn_store, new_beacon->beacon_buf,
1672 new_beacon->beacon_buf_size);
1673
1674 } else if (new_bcn_size <= bcn_space) {
1675 /*
1676 * New beacon size will fit in the amount of space
1677 * we have previously allocated for it
1678 */
1679
1680 /* Copy the new beacon buffer entry over the old one */
1681 memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
1682
1683 /*
1684 * If the old beacon size was less than the maximum
1685 * we had alloted for the entry, and the new entry
1686 * is even smaller, reset the max size to the old
1687 * beacon entry and compress the storage space
1688 * (leaving a new pad space of (old_bcn_size -
1689 * new_bcn_size).
1690 */
1691 if (old_bcn_size < bcn_space
1692 && new_bcn_size <= old_bcn_size) {
1693 /*
1694 * Old Beacon size is smaller than the alloted
1695 * storage size. Shrink the alloted storage
1696 * space.
1697 */
1698 dev_dbg(adapter->dev, "info: AppControl:"
1699 " smaller duplicate beacon "
1700 "(%d), old = %d, new = %d, space = %d,"
1701 "left = %d\n",
1702 beacon_idx, old_bcn_size, new_bcn_size,
1703 bcn_space,
1704 (int)(sizeof(adapter->bcn_buf) -
1705 (adapter->bcn_buf_end -
1706 adapter->bcn_buf)));
1707
1708 /*
1709 * memmove (since the memory overlaps) the
1710 * data after the beacon we just stored to the
1711 * end of the current beacon. This cleans up
1712 * any unused space the old larger beacon was
1713 * using in the buffer
1714 */
1715 memmove(bcn_store + old_bcn_size,
1716 bcn_store + bcn_space,
1717 adapter->bcn_buf_end - (bcn_store +
1718 bcn_space));
1719
1720 /*
1721 * Decrement the end pointer by the difference
1722 * between the old larger size and the new
1723 * smaller size since we are using less space
1724 * due to the new beacon being smaller
1725 */
1726 adapter->bcn_buf_end -=
1727 (bcn_space - old_bcn_size);
1728
1729 /* Set the maximum storage size to the old
1730 beacon size */
1731 new_beacon->beacon_buf_size_max = old_bcn_size;
1732
1733 /* Adjust beacon buffer pointers that are past
1734 the current */
1735 mwifiex_adjust_beacon_buffer_ptrs(priv, 0,
1736 bcn_store, (bcn_space - old_bcn_size),
1737 num_of_ent);
1738 }
1739 } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space)
1740 < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) {
1741 /*
1742 * Beacon is larger than space previously allocated
1743 * (bcn_space) and there is enough space left in the
1744 * beaconBuffer to store the additional data
1745 */
1746 dev_dbg(adapter->dev, "info: AppControl:"
1747 " larger duplicate beacon (%d), "
1748 "old = %d, new = %d, space = %d, left = %d\n",
1749 beacon_idx, old_bcn_size, new_bcn_size,
1750 bcn_space,
1751 (int)(sizeof(adapter->bcn_buf) -
1752 (adapter->bcn_buf_end -
1753 adapter->bcn_buf)));
1754
1755 /*
1756 * memmove (since the memory overlaps) the data
1757 * after the beacon we just stored to the end of
1758 * the current beacon. This moves the data for
1759 * the beacons after this further in memory to
1760 * make space for the new larger beacon we are
1761 * about to copy in.
1762 */
1763 memmove(bcn_store + new_bcn_size,
1764 bcn_store + bcn_space,
1765 adapter->bcn_buf_end - (bcn_store + bcn_space));
1766
1767 /* Copy the new beacon buffer entry over the old one */
1768 memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
1769
1770 /* Move the beacon end pointer by the amount of new
1771 beacon data we are adding */
1772 adapter->bcn_buf_end += (new_bcn_size - bcn_space);
1773
1774 /*
1775 * This entry is bigger than the alloted max space
1776 * previously reserved. Increase the max space to
1777 * be equal to the new beacon size
1778 */
1779 new_beacon->beacon_buf_size_max = new_bcn_size;
1780
1781 /* Adjust beacon buffer pointers that are past the
1782 current */
1783 mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store,
1784 (new_bcn_size - bcn_space),
1785 num_of_ent);
1786 } else {
1787 /*
1788 * Beacon is larger than the previously allocated space,
1789 * but there is not enough free space to store the
1790 * additional data.
1791 */
1792 dev_err(adapter->dev, "AppControl: larger duplicate "
1793 " beacon (%d), old = %d new = %d, space = %d,"
1794 " left = %d\n", beacon_idx, old_bcn_size,
1795 new_bcn_size, bcn_space,
1796 (int)(sizeof(adapter->bcn_buf) -
1797 (adapter->bcn_buf_end - adapter->bcn_buf)));
1798
1799 /* Storage failure, keep old beacon intact */
1800 new_beacon->beacon_buf_size = old_bcn_size;
1801 if (new_beacon->bcn_wpa_ie)
1802 new_beacon->wpa_offset =
1803 adapter->scan_table[beacon_idx].
1804 wpa_offset;
1805 if (new_beacon->bcn_rsn_ie)
1806 new_beacon->rsn_offset =
1807 adapter->scan_table[beacon_idx].
1808 rsn_offset;
1809 if (new_beacon->bcn_wapi_ie)
1810 new_beacon->wapi_offset =
1811 adapter->scan_table[beacon_idx].
1812 wapi_offset;
1813 if (new_beacon->bcn_ht_cap)
1814 new_beacon->ht_cap_offset =
1815 adapter->scan_table[beacon_idx].
1816 ht_cap_offset;
1817 if (new_beacon->bcn_ht_info)
1818 new_beacon->ht_info_offset =
1819 adapter->scan_table[beacon_idx].
1820 ht_info_offset;
1821 if (new_beacon->bcn_bss_co_2040)
1822 new_beacon->bss_co_2040_offset =
1823 adapter->scan_table[beacon_idx].
1824 bss_co_2040_offset;
1825 if (new_beacon->bcn_ext_cap)
1826 new_beacon->ext_cap_offset =
1827 adapter->scan_table[beacon_idx].
1828 ext_cap_offset;
1829 if (new_beacon->bcn_obss_scan)
1830 new_beacon->overlap_bss_offset =
1831 adapter->scan_table[beacon_idx].
1832 overlap_bss_offset;
1833 }
1834 /* Point the new entry to its permanent storage space */
1835 new_beacon->beacon_buf = bcn_store;
1836 mwifiex_update_beacon_buffer_ptrs(new_beacon);
1837 } else {
1838 /*
1839 * No existing beacon data exists for this entry, check to see
1840 * if we can fit it in the remaining space
1841 */
1842 if (adapter->bcn_buf_end + new_beacon->beacon_buf_size +
1843 SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf +
1844 sizeof(adapter->bcn_buf))) {
1845
1846 /*
1847 * Copy the beacon buffer data from the local entry to
1848 * the adapter dev struct buffer space used to store
1849 * the raw beacon data for each entry in the scan table
1850 */
1851 memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf,
1852 new_beacon->beacon_buf_size);
1853
1854 /* Update the beacon ptr to point to the table save
1855 area */
1856 new_beacon->beacon_buf = adapter->bcn_buf_end;
1857 new_beacon->beacon_buf_size_max =
1858 (new_beacon->beacon_buf_size +
1859 SCAN_BEACON_ENTRY_PAD);
1860
1861 mwifiex_update_beacon_buffer_ptrs(new_beacon);
1862
1863 /* Increment the end pointer by the size reserved */
1864 adapter->bcn_buf_end += new_beacon->beacon_buf_size_max;
1865
1866 dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]"
1867 " sz=%03d, used = %04d, left = %04d\n",
1868 beacon_idx,
1869 new_beacon->beacon_buf_size,
1870 (int)(adapter->bcn_buf_end - adapter->bcn_buf),
1871 (int)(sizeof(adapter->bcn_buf) -
1872 (adapter->bcn_buf_end -
1873 adapter->bcn_buf)));
1874 } else {
1875 /* No space for new beacon */
1876 dev_dbg(adapter->dev, "info: AppControl: no space for"
1877 " beacon (%d): %pM sz=%03d, left=%03d\n",
1878 beacon_idx, new_beacon->mac_address,
1879 new_beacon->beacon_buf_size,
1880 (int)(sizeof(adapter->bcn_buf) -
1881 (adapter->bcn_buf_end -
1882 adapter->bcn_buf)));
1883
1884 /* Storage failure; clear storage records for this
1885 bcn */
1886 new_beacon->beacon_buf = NULL;
1887 new_beacon->beacon_buf_size = 0;
1888 new_beacon->beacon_buf_size_max = 0;
1889 new_beacon->bcn_wpa_ie = NULL;
1890 new_beacon->wpa_offset = 0;
1891 new_beacon->bcn_rsn_ie = NULL;
1892 new_beacon->rsn_offset = 0;
1893 new_beacon->bcn_wapi_ie = NULL;
1894 new_beacon->wapi_offset = 0;
1895 new_beacon->bcn_ht_cap = NULL;
1896 new_beacon->ht_cap_offset = 0;
1897 new_beacon->bcn_ht_info = NULL;
1898 new_beacon->ht_info_offset = 0;
1899 new_beacon->bcn_bss_co_2040 = NULL;
1900 new_beacon->bss_co_2040_offset = 0;
1901 new_beacon->bcn_ext_cap = NULL;
1902 new_beacon->ext_cap_offset = 0;
1903 new_beacon->bcn_obss_scan = NULL;
1904 new_beacon->overlap_bss_offset = 0;
1905 }
1906 }
1907}
1908
1909/*
1910 * This function restores a beacon buffer of the current BSS descriptor.
1911 */
1912static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv)
1913{
1914 struct mwifiex_adapter *adapter = priv->adapter;
1915 struct mwifiex_bssdescriptor *curr_bss =
1916 &priv->curr_bss_params.bss_descriptor;
1917 unsigned long flags;
1918
1919 if (priv->curr_bcn_buf &&
1920 ((adapter->bcn_buf_end + priv->curr_bcn_size) <
1921 (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) {
1922 spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
1923
1924 /* restore the current beacon buffer */
1925 memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf,
1926 priv->curr_bcn_size);
1927 curr_bss->beacon_buf = adapter->bcn_buf_end;
1928 curr_bss->beacon_buf_size = priv->curr_bcn_size;
1929 adapter->bcn_buf_end += priv->curr_bcn_size;
1930
1931 /* adjust the pointers in the current BSS descriptor */
1932 if (curr_bss->bcn_wpa_ie)
1933 curr_bss->bcn_wpa_ie =
1934 (struct ieee_types_vendor_specific *)
1935 (curr_bss->beacon_buf +
1936 curr_bss->wpa_offset);
1937
1938 if (curr_bss->bcn_rsn_ie)
1939 curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
1940 (curr_bss->beacon_buf +
1941 curr_bss->rsn_offset);
1942
1943 if (curr_bss->bcn_ht_cap)
1944 curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
1945 (curr_bss->beacon_buf +
1946 curr_bss->ht_cap_offset);
1947
1948 if (curr_bss->bcn_ht_info)
1949 curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
1950 (curr_bss->beacon_buf +
1951 curr_bss->ht_info_offset);
1952
1953 if (curr_bss->bcn_bss_co_2040)
1954 curr_bss->bcn_bss_co_2040 =
1955 (u8 *) (curr_bss->beacon_buf +
1956 curr_bss->bss_co_2040_offset);
1957
1958 if (curr_bss->bcn_ext_cap)
1959 curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
1960 curr_bss->ext_cap_offset);
1961
1962 if (curr_bss->bcn_obss_scan)
1963 curr_bss->bcn_obss_scan =
1964 (struct ieee_types_obss_scan_param *)
1965 (curr_bss->beacon_buf +
1966 curr_bss->overlap_bss_offset);
1967
1968 spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
1969
1970 dev_dbg(adapter->dev, "info: current beacon restored %d\n",
1971 priv->curr_bcn_size);
1972 } else {
1973 dev_warn(adapter->dev,
1974 "curr_bcn_buf not saved or bcn_buf has no space\n");
1975 }
1976}
1977
1978/*
1979 * This function post processes the scan table after a new scan command has
1980 * completed.
1981 *
1982 * It inspects each entry of the scan table and tries to find an entry that
1983 * matches with our current associated/joined network from the scan. If
1984 * one is found, the stored copy of the BSS descriptor of our current network
1985 * is updated.
1986 *
1987 * It also debug dumps the current scan table contents after processing is over.
1988 */
1989static void
1990mwifiex_process_scan_results(struct mwifiex_private *priv)
1991{
1992 struct mwifiex_adapter *adapter = priv->adapter;
1993 s32 j;
1994 u32 i;
1995 unsigned long flags;
1996
1997 if (priv->media_connected) {
1998
1999 j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params.
2000 bss_descriptor.ssid,
2001 priv->curr_bss_params.
2002 bss_descriptor.mac_address,
2003 priv->bss_mode);
2004
2005 if (j >= 0) {
2006 spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
2007 priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
2008 priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
2009 priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
2010 priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
2011 priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
2012 priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
2013 priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
2014 priv->curr_bss_params.bss_descriptor.ht_cap_offset =
2015 0;
2016 priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
2017 priv->curr_bss_params.bss_descriptor.ht_info_offset =
2018 0;
2019 priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
2020 NULL;
2021 priv->curr_bss_params.bss_descriptor.
2022 bss_co_2040_offset = 0;
2023 priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
2024 priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
2025 priv->curr_bss_params.bss_descriptor.
2026 bcn_obss_scan = NULL;
2027 priv->curr_bss_params.bss_descriptor.
2028 overlap_bss_offset = 0;
2029 priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
2030 priv->curr_bss_params.bss_descriptor.beacon_buf_size =
2031 0;
2032 priv->curr_bss_params.bss_descriptor.
2033 beacon_buf_size_max = 0;
2034
2035 dev_dbg(adapter->dev, "info: Found current ssid/bssid"
2036 " in list @ index #%d\n", j);
2037 /* Make a copy of current BSSID descriptor */
2038 memcpy(&priv->curr_bss_params.bss_descriptor,
2039 &adapter->scan_table[j],
2040 sizeof(priv->curr_bss_params.bss_descriptor));
2041
2042 mwifiex_save_curr_bcn(priv);
2043 spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
2044
2045 } else {
2046 mwifiex_restore_curr_bcn(priv);
2047 }
2048 }
2049
2050 for (i = 0; i < adapter->num_in_scan_table; i++)
2051 dev_dbg(adapter->dev, "info: scan:(%02d) %pM "
2052 "RSSI[%03d], SSID[%s]\n",
2053 i, adapter->scan_table[i].mac_address,
2054 (s32) adapter->scan_table[i].rssi,
2055 adapter->scan_table[i].ssid.ssid);
2056}
2057
2058/*
2059 * This function converts radio type scan parameter to a band configuration
2060 * to be used in join command.
2061 */
2062static u8
2063mwifiex_radio_type_to_band(u8 radio_type)
2064{
2065 switch (radio_type) {
2066 case HostCmd_SCAN_RADIO_TYPE_A:
2067 return BAND_A;
2068 case HostCmd_SCAN_RADIO_TYPE_BG:
2069 default:
2070 return BAND_G;
2071 }
2072}
2073
2074/*
2075 * This function deletes a specific indexed entry from the scan table.
2076 *
2077 * This also compacts the remaining entries and adjusts any buffering
2078 * of beacon/probe response data if needed.
2079 */
2080static void
2081mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx)
2082{
2083 struct mwifiex_adapter *adapter = priv->adapter;
2084 u32 del_idx;
2085 u32 beacon_buf_adj;
2086 u8 *beacon_buf;
2087
2088 /*
2089 * Shift the saved beacon buffer data for the scan table back over the
2090 * entry being removed. Update the end of buffer pointer. Save the
2091 * deleted buffer allocation size for pointer adjustments for entries
2092 * compacted after the deleted index.
2093 */
2094 beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max;
2095
2096 dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer "
2097 "removal = %d bytes\n", table_idx, beacon_buf_adj);
2098
2099 /* Check if the table entry had storage allocated for its beacon */
2100 if (beacon_buf_adj) {
2101 beacon_buf = adapter->scan_table[table_idx].beacon_buf;
2102
2103 /*
2104 * Remove the entry's buffer space, decrement the table end
2105 * pointer by the amount we are removing
2106 */
2107 adapter->bcn_buf_end -= beacon_buf_adj;
2108
2109 dev_dbg(adapter->dev, "info: scan: delete entry %d,"
2110 " compact data: %p <- %p (sz = %d)\n",
2111 table_idx, beacon_buf,
2112 beacon_buf + beacon_buf_adj,
2113 (int)(adapter->bcn_buf_end - beacon_buf));
2114
2115 /*
2116 * Compact data storage. Copy all data after the deleted
2117 * entry's end address (beacon_buf + beacon_buf_adj) back
2118 * to the original start address (beacon_buf).
2119 *
2120 * Scan table entries affected by the move will have their
2121 * entry pointer adjusted below.
2122 *
2123 * Use memmove since the dest/src memory regions overlap.
2124 */
2125 memmove(beacon_buf, beacon_buf + beacon_buf_adj,
2126 adapter->bcn_buf_end - beacon_buf);
2127 }
2128
2129 dev_dbg(adapter->dev,
2130 "info: Scan: Delete Entry %d, num_in_scan_table = %d\n",
2131 table_idx, adapter->num_in_scan_table);
2132
2133 /* Shift all of the entries after the table_idx back by one, compacting
2134 the table and removing the requested entry */
2135 for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table;
2136 del_idx++) {
2137 /* Copy the next entry over this one */
2138 memcpy(adapter->scan_table + del_idx,
2139 adapter->scan_table + del_idx + 1,
2140 sizeof(struct mwifiex_bssdescriptor));
2141
2142 /*
2143 * Adjust this entry's pointer to its beacon buffer based on
2144 * the removed/compacted entry from the deleted index. Don't
2145 * decrement if the buffer pointer is NULL (no data stored for
2146 * this entry).
2147 */
2148 if (adapter->scan_table[del_idx].beacon_buf) {
2149 adapter->scan_table[del_idx].beacon_buf -=
2150 beacon_buf_adj;
2151 if (adapter->scan_table[del_idx].bcn_wpa_ie)
2152 adapter->scan_table[del_idx].bcn_wpa_ie =
2153 (struct ieee_types_vendor_specific *)
2154 (adapter->scan_table[del_idx].
2155 beacon_buf +
2156 adapter->scan_table[del_idx].
2157 wpa_offset);
2158 if (adapter->scan_table[del_idx].bcn_rsn_ie)
2159 adapter->scan_table[del_idx].bcn_rsn_ie =
2160 (struct ieee_types_generic *)
2161 (adapter->scan_table[del_idx].
2162 beacon_buf +
2163 adapter->scan_table[del_idx].
2164 rsn_offset);
2165 if (adapter->scan_table[del_idx].bcn_wapi_ie)
2166 adapter->scan_table[del_idx].bcn_wapi_ie =
2167 (struct ieee_types_generic *)
2168 (adapter->scan_table[del_idx].beacon_buf
2169 + adapter->scan_table[del_idx].
2170 wapi_offset);
2171 if (adapter->scan_table[del_idx].bcn_ht_cap)
2172 adapter->scan_table[del_idx].bcn_ht_cap =
2173 (struct ieee80211_ht_cap *)
2174 (adapter->scan_table[del_idx].beacon_buf
2175 + adapter->scan_table[del_idx].
2176 ht_cap_offset);
2177
2178 if (adapter->scan_table[del_idx].bcn_ht_info)
2179 adapter->scan_table[del_idx].bcn_ht_info =
2180 (struct ieee80211_ht_info *)
2181 (adapter->scan_table[del_idx].beacon_buf
2182 + adapter->scan_table[del_idx].
2183 ht_info_offset);
2184 if (adapter->scan_table[del_idx].bcn_bss_co_2040)
2185 adapter->scan_table[del_idx].bcn_bss_co_2040 =
2186 (u8 *)
2187 (adapter->scan_table[del_idx].beacon_buf
2188 + adapter->scan_table[del_idx].
2189 bss_co_2040_offset);
2190 if (adapter->scan_table[del_idx].bcn_ext_cap)
2191 adapter->scan_table[del_idx].bcn_ext_cap =
2192 (u8 *)
2193 (adapter->scan_table[del_idx].beacon_buf
2194 + adapter->scan_table[del_idx].
2195 ext_cap_offset);
2196 if (adapter->scan_table[del_idx].bcn_obss_scan)
2197 adapter->scan_table[del_idx].
2198 bcn_obss_scan =
2199 (struct ieee_types_obss_scan_param *)
2200 (adapter->scan_table[del_idx].beacon_buf
2201 + adapter->scan_table[del_idx].
2202 overlap_bss_offset);
2203 }
2204 }
2205
2206 /* The last entry is invalid now that it has been deleted or moved
2207 back */
2208 memset(adapter->scan_table + adapter->num_in_scan_table - 1,
2209 0x00, sizeof(struct mwifiex_bssdescriptor));
2210
2211 adapter->num_in_scan_table--;
2212}
2213
2214/*
2215 * This function deletes all occurrences of a given SSID from the scan table.
2216 *
2217 * This iterates through the scan table and deletes all entries that match
2218 * the given SSID. It also compacts the remaining scan table entries.
2219 */
2220static int
2221mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
2222 struct mwifiex_802_11_ssid *del_ssid)
2223{
2224 s32 table_idx = -1;
2225
2226 dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
2227 del_ssid->ssid);
2228
2229 /* If the requested SSID is found in the table, delete it. Then keep
2230 searching the table for multiple entires for the SSID until no
2231 more are found */
2232 while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL,
2233 NL80211_IFTYPE_UNSPECIFIED)) >= 0) {
2234 dev_dbg(priv->adapter->dev,
2235 "info: Scan: Delete SSID Entry: Found Idx = %d\n",
2236 table_idx);
2237 mwifiex_scan_delete_table_entry(priv, table_idx);
2238 }
2239
2240 return table_idx == -1 ? -1 : 0;
2241}
2242
2243/*
2244 * This is an internal function used to start a scan based on an input
2245 * configuration.
2246 *
2247 * This uses the input user scan configuration information when provided in
2248 * order to send the appropriate scan commands to firmware to populate or
2249 * update the internal driver scan table.
2250 */
2251int mwifiex_scan_networks(struct mwifiex_private *priv,
2252 const struct mwifiex_user_scan_cfg *user_scan_in)
2253{
2254 int ret = 0;
2255 struct mwifiex_adapter *adapter = priv->adapter;
2256 struct cmd_ctrl_node *cmd_node;
2257 union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
2258 struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
2259 u32 buf_size;
2260 struct mwifiex_chan_scan_param_set *scan_chan_list;
2261 u8 keep_previous_scan;
2262 u8 filtered_scan;
2263 u8 scan_current_chan_only;
2264 u8 max_chan_per_scan;
2265 unsigned long flags;
2266
2267 if (adapter->scan_processing) {
2268 dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
2269 return ret;
2270 }
2271
2272 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2273 adapter->scan_processing = true;
2274 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2275
2276 if (priv->scan_block) {
2277 dev_dbg(adapter->dev,
2278 "cmd: Scan is blocked during association...\n");
2279 return ret;
2280 }
2281
2282 scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
2283 GFP_KERNEL);
2284 if (!scan_cfg_out) {
2285 dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
2286 return -ENOMEM;
2287 }
2288
2289 buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
2290 MWIFIEX_USER_SCAN_CHAN_MAX;
2291 scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
2292 if (!scan_chan_list) {
2293 dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
2294 kfree(scan_cfg_out);
2295 return -ENOMEM;
2296 }
2297
2298 keep_previous_scan = false;
2299
2300 mwifiex_scan_setup_scan_config(priv, user_scan_in,
2301 &scan_cfg_out->config, &chan_list_out,
2302 scan_chan_list, &max_chan_per_scan,
2303 &filtered_scan, &scan_current_chan_only);
2304
2305 if (user_scan_in)
2306 keep_previous_scan = user_scan_in->keep_previous_scan;
2307
2308
2309 if (!keep_previous_scan) {
2310 memset(adapter->scan_table, 0x00,
2311 sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
2312 adapter->num_in_scan_table = 0;
2313 adapter->bcn_buf_end = adapter->bcn_buf;
2314 }
2315
2316 ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
2317 &scan_cfg_out->config, chan_list_out,
2318 scan_chan_list);
2319
2320 /* Get scan command from scan_pending_q and put to cmd_pending_q */
2321 if (!ret) {
2322 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2323 if (!list_empty(&adapter->scan_pending_q)) {
2324 cmd_node = list_first_entry(&adapter->scan_pending_q,
2325 struct cmd_ctrl_node, list);
2326 list_del(&cmd_node->list);
2327 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
2328 flags);
2329 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
2330 true);
2331 } else {
2332 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
2333 flags);
2334 }
2335 } else {
2336 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2337 adapter->scan_processing = true;
2338 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2339 }
2340
2341 kfree(scan_cfg_out);
2342 kfree(scan_chan_list);
2343 return ret;
2344}
2345
2346/*
2347 * This function prepares a scan command to be sent to the firmware.
2348 *
2349 * This uses the scan command configuration sent to the command processing
2350 * module in command preparation stage to configure a scan command structure
2351 * to send to firmware.
2352 *
2353 * The fixed fields specifying the BSS type and BSSID filters as well as a
2354 * variable number/length of TLVs are sent in the command to firmware.
2355 *
2356 * Preparation also includes -
2357 * - Setting command ID, and proper size
2358 * - Ensuring correct endian-ness
2359 */
2360int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf)
2361{
2362 struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
2363 struct mwifiex_scan_cmd_config *scan_cfg;
2364
2365 scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf;
2366
2367 /* Set fixed field variables in scan command */
2368 scan_cmd->bss_mode = scan_cfg->bss_mode;
2369 memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
2370 sizeof(scan_cmd->bssid));
2371 memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
2372
2373 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
2374
2375 /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
2376 cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
2377 + sizeof(scan_cmd->bssid)
2378 + scan_cfg->tlv_buf_len + S_DS_GEN));
2379
2380 return 0;
2381}
2382
2383/*
2384 * This function handles the command response of scan.
2385 *
2386 * The response buffer for the scan command has the following
2387 * memory layout:
2388 *
2389 * .-------------------------------------------------------------.
2390 * | Header (4 * sizeof(t_u16)): Standard command response hdr |
2391 * .-------------------------------------------------------------.
2392 * | BufSize (t_u16) : sizeof the BSS Description data |
2393 * .-------------------------------------------------------------.
2394 * | NumOfSet (t_u8) : Number of BSS Descs returned |
2395 * .-------------------------------------------------------------.
2396 * | BSSDescription data (variable, size given in BufSize) |
2397 * .-------------------------------------------------------------.
2398 * | TLV data (variable, size calculated using Header->Size, |
2399 * | BufSize and sizeof the fixed fields above) |
2400 * .-------------------------------------------------------------.
2401 */
2402int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
2403 struct host_cmd_ds_command *resp)
2404{
2405 int ret = 0;
2406 struct mwifiex_adapter *adapter = priv->adapter;
2407 struct cmd_ctrl_node *cmd_node;
2408 struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
2409 struct mwifiex_bssdescriptor *bss_new_entry = NULL;
2410 struct mwifiex_ie_types_data *tlv_data;
2411 struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
2412 u8 *bss_info;
2413 u32 scan_resp_size;
2414 u32 bytes_left;
2415 u32 num_in_table;
2416 u32 bss_idx;
2417 u32 idx;
2418 u32 tlv_buf_size;
2419 long long tsf_val;
2420 struct mwifiex_chan_freq_power *cfp;
2421 struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
2422 struct chan_band_param_set *chan_band;
2423 u8 band;
2424 u8 is_bgscan_resp;
2425 unsigned long flags;
2426
2427 is_bgscan_resp = (le16_to_cpu(resp->command)
2428 == HostCmd_CMD_802_11_BG_SCAN_QUERY);
2429 if (is_bgscan_resp)
2430 scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
2431 else
2432 scan_rsp = &resp->params.scan_resp;
2433
2434
2435 if (scan_rsp->number_of_sets > IW_MAX_AP) {
2436 dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
2437 scan_rsp->number_of_sets);
2438 ret = -1;
2439 goto done;
2440 }
2441
2442 bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
2443 dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
2444 bytes_left);
2445
2446 scan_resp_size = le16_to_cpu(resp->size);
2447
2448 dev_dbg(adapter->dev,
2449 "info: SCAN_RESP: returned %d APs before parsing\n",
2450 scan_rsp->number_of_sets);
2451
2452 num_in_table = adapter->num_in_scan_table;
2453 bss_info = scan_rsp->bss_desc_and_tlv_buffer;
2454
2455 /*
2456 * The size of the TLV buffer is equal to the entire command response
2457 * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
2458 * BSS Descriptions (bss_descript_size as bytesLef) and the command
2459 * response header (S_DS_GEN)
2460 */
2461 tlv_buf_size = scan_resp_size - (bytes_left
2462 + sizeof(scan_rsp->bss_descript_size)
2463 + sizeof(scan_rsp->number_of_sets)
2464 + S_DS_GEN);
2465
2466 tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
2467 bss_desc_and_tlv_buffer +
2468 bytes_left);
2469
2470 /* Search the TLV buffer space in the scan response for any valid
2471 TLVs */
2472 mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2473 TLV_TYPE_TSFTIMESTAMP,
2474 (struct mwifiex_ie_types_data **)
2475 &tsf_tlv);
2476
2477 /* Search the TLV buffer space in the scan response for any valid
2478 TLVs */
2479 mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2480 TLV_TYPE_CHANNELBANDLIST,
2481 (struct mwifiex_ie_types_data **)
2482 &chan_band_tlv);
2483
2484 /*
2485 * Process each scan response returned (scan_rsp->number_of_sets).
2486 * Save the information in the bss_new_entry and then insert into the
2487 * driver scan table either as an update to an existing entry
2488 * or as an addition at the end of the table
2489 */
2490 bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor),
2491 GFP_KERNEL);
2492 if (!bss_new_entry) {
2493 dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
2494 return -ENOMEM;
2495 }
2496
2497 for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
2498 /* Zero out the bss_new_entry we are about to store info in */
2499 memset(bss_new_entry, 0x00,
2500 sizeof(struct mwifiex_bssdescriptor));
2501
2502 if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry,
2503 &bss_info,
2504 &bytes_left)) {
2505 /* Error parsing/interpreting scan response, skipped */
2506 dev_err(adapter->dev, "SCAN_RESP: "
2507 "mwifiex_interpret_bss_desc_with_ie "
2508 "returned ERROR\n");
2509 continue;
2510 }
2511
2512 /* Process the data fields and IEs returned for this BSS */
2513 dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n",
2514 bss_new_entry->mac_address);
2515
2516 /* Search the scan table for the same bssid */
2517 for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
2518 if (memcmp(bss_new_entry->mac_address,
2519 adapter->scan_table[bss_idx].mac_address,
2520 sizeof(bss_new_entry->mac_address))) {
2521 continue;
2522 }
2523 /*
2524 * If the SSID matches as well, it is a
2525 * duplicate of this entry. Keep the bss_idx
2526 * set to this entry so we replace the old
2527 * contents in the table
2528 */
2529 if ((bss_new_entry->ssid.ssid_len
2530 == adapter->scan_table[bss_idx]. ssid.ssid_len)
2531 && (!memcmp(bss_new_entry->ssid.ssid,
2532 adapter->scan_table[bss_idx].ssid.ssid,
2533 bss_new_entry->ssid.ssid_len))) {
2534 dev_dbg(adapter->dev, "info: SCAN_RESP:"
2535 " duplicate of index: %d\n", bss_idx);
2536 break;
2537 }
2538 }
2539 /*
2540 * If the bss_idx is equal to the number of entries in
2541 * the table, the new entry was not a duplicate; append
2542 * it to the scan table
2543 */
2544 if (bss_idx == num_in_table) {
2545 /* Range check the bss_idx, keep it limited to
2546 the last entry */
2547 if (bss_idx == IW_MAX_AP)
2548 bss_idx--;
2549 else
2550 num_in_table++;
2551 }
2552
2553 /*
2554 * Save the beacon/probe response returned for later application
2555 * retrieval. Duplicate beacon/probe responses are updated if
2556 * possible
2557 */
2558 mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx,
2559 num_in_table, bss_new_entry);
2560 /*
2561 * If the TSF TLV was appended to the scan results, save this
2562 * entry's TSF value in the networkTSF field.The networkTSF is
2563 * the firmware's TSF value at the time the beacon or probe
2564 * response was received.
2565 */
2566 if (tsf_tlv) {
2567 memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE]
2568 , sizeof(tsf_val));
2569 memcpy(&bss_new_entry->network_tsf, &tsf_val,
2570 sizeof(bss_new_entry->network_tsf));
2571 }
2572 band = BAND_G;
2573 if (chan_band_tlv) {
2574 chan_band = &chan_band_tlv->chan_band_param[idx];
2575 band = mwifiex_radio_type_to_band(chan_band->radio_type
2576 & (BIT(0) | BIT(1)));
2577 }
2578
2579 /* Save the band designation for this entry for use in join */
2580 bss_new_entry->bss_band = band;
2581 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
2582 (u8) bss_new_entry->bss_band,
2583 (u16)bss_new_entry->channel);
2584
2585 if (cfp)
2586 bss_new_entry->freq = cfp->freq;
2587 else
2588 bss_new_entry->freq = 0;
2589
2590 /* Copy the locally created bss_new_entry to the scan table */
2591 memcpy(&adapter->scan_table[bss_idx], bss_new_entry,
2592 sizeof(adapter->scan_table[bss_idx]));
2593
2594 }
2595
2596 dev_dbg(adapter->dev,
2597 "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
2598 scan_rsp->number_of_sets,
2599 num_in_table - adapter->num_in_scan_table, num_in_table);
2600
2601 /* Update the total number of BSSIDs in the scan table */
2602 adapter->num_in_scan_table = num_in_table;
2603
2604 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2605 if (list_empty(&adapter->scan_pending_q)) {
2606 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2607 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
2608 adapter->scan_processing = false;
2609 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
2610 /*
2611 * Process the resulting scan table:
2612 * - Remove any bad ssids
2613 * - Update our current BSS information from scan data
2614 */
2615 mwifiex_process_scan_results(priv);
2616
2617 /* Need to indicate IOCTL complete */
2618 if (adapter->curr_cmd->wait_q_enabled) {
2619 adapter->cmd_wait_q.status = 0;
2620 mwifiex_complete_cmd(adapter);
2621 }
2622 if (priv->report_scan_result)
2623 priv->report_scan_result = false;
2624 if (priv->scan_pending_on_block) {
2625 priv->scan_pending_on_block = false;
2626 up(&priv->async_sem);
2627 }
2628
2629 } else {
2630 /* Get scan command from scan_pending_q and put to
2631 cmd_pending_q */
2632 cmd_node = list_first_entry(&adapter->scan_pending_q,
2633 struct cmd_ctrl_node, list);
2634 list_del(&cmd_node->list);
2635 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2636
2637 mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
2638 }
2639
2640done:
2641 kfree((u8 *) bss_new_entry);
2642 return ret;
2643}
2644
2645/*
2646 * This function prepares command for background scan query.
2647 *
2648 * Preparation includes -
2649 * - Setting command ID and proper size
2650 * - Setting background scan flush parameter
2651 * - Ensuring correct endian-ness
2652 */
2653int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
2654{
2655 struct host_cmd_ds_802_11_bg_scan_query *bg_query =
2656 &cmd->params.bg_scan_query;
2657
2658 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
2659 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
2660 + S_DS_GEN);
2661
2662 bg_query->flush = 1;
2663
2664 return 0;
2665}
2666
2667/*
2668 * This function finds a SSID in the scan table.
2669 *
2670 * A BSSID may optionally be provided to qualify the SSID.
2671 * For non-Auto mode, further check is made to make sure the
2672 * BSS found in the scan table is compatible with the current
2673 * settings of the driver.
2674 */
2675s32
2676mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
2677 struct mwifiex_802_11_ssid *ssid, u8 *bssid,
2678 u32 mode)
2679{
2680 struct mwifiex_adapter *adapter = priv->adapter;
2681 s32 net = -1, j;
2682 u8 best_rssi = 0;
2683 u32 i;
2684
2685 dev_dbg(adapter->dev, "info: num of entries in table = %d\n",
2686 adapter->num_in_scan_table);
2687
2688 /*
2689 * Loop through the table until the maximum is reached or until a match
2690 * is found based on the bssid field comparison
2691 */
2692 for (i = 0;
2693 i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0));
2694 i++) {
2695 if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) &&
2696 (!bssid
2697 || !memcmp(adapter->scan_table[i].mac_address, bssid,
2698 ETH_ALEN))
2699 &&
2700 (mwifiex_get_cfp_by_band_and_channel_from_cfg80211
2701 (priv, (u8) adapter->scan_table[i].bss_band,
2702 (u16) adapter->scan_table[i].channel))) {
2703 switch (mode) {
2704 case NL80211_IFTYPE_STATION:
2705 case NL80211_IFTYPE_ADHOC:
2706 j = mwifiex_is_network_compatible(priv, i,
2707 mode);
2708
2709 if (j >= 0) {
2710 if (SCAN_RSSI
2711 (adapter->scan_table[i].rssi) >
2712 best_rssi) {
2713 best_rssi = SCAN_RSSI(adapter->
2714 scan_table
2715 [i].rssi);
2716 net = i;
2717 }
2718 } else {
2719 if (net == -1)
2720 net = j;
2721 }
2722 break;
2723 case NL80211_IFTYPE_UNSPECIFIED:
2724 default:
2725 /*
2726 * Do not check compatibility if the mode
2727 * requested is Auto/Unknown. Allows generic
2728 * find to work without verifying against the
2729 * Adapter security settings
2730 */
2731 if (SCAN_RSSI(adapter->scan_table[i].rssi) >
2732 best_rssi) {
2733 best_rssi = SCAN_RSSI(adapter->
2734 scan_table[i].rssi);
2735 net = i;
2736 }
2737 break;
2738 }
2739 }
2740 }
2741
2742 return net;
2743}
2744
2745/*
2746 * This function finds a specific compatible BSSID in the scan list.
2747 *
2748 * This function loops through the scan table looking for a compatible
2749 * match. If a BSSID matches, but the BSS is found to be not compatible
2750 * the function ignores it and continues to search through the rest of
2751 * the entries in case there is an AP with multiple SSIDs assigned to
2752 * the same BSSID.
2753 */
2754s32
2755mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
2756 u32 mode)
2757{
2758 struct mwifiex_adapter *adapter = priv->adapter;
2759 s32 net = -1;
2760 u32 i;
2761
2762 if (!bssid)
2763 return -1;
2764
2765 dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n",
2766 adapter->num_in_scan_table);
2767
2768 /*
2769 * Look through the scan table for a compatible match. The ret return
2770 * variable will be equal to the index in the scan table (greater
2771 * than zero) if the network is compatible. The loop will continue
2772 * past a matched bssid that is not compatible in case there is an
2773 * AP with multiple SSIDs assigned to the same BSSID
2774 */
2775 for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) {
2776 if (!memcmp
2777 (adapter->scan_table[i].mac_address, bssid, ETH_ALEN)
2778 && mwifiex_get_cfp_by_band_and_channel_from_cfg80211
2779 (priv,
2780 (u8) adapter->
2781 scan_table[i].
2782 bss_band,
2783 (u16) adapter->
2784 scan_table[i].
2785 channel)) {
2786 switch (mode) {
2787 case NL80211_IFTYPE_STATION:
2788 case NL80211_IFTYPE_ADHOC:
2789 net = mwifiex_is_network_compatible(priv, i,
2790 mode);
2791 break;
2792 default:
2793 net = i;
2794 break;
2795 }
2796 }
2797 }
2798
2799 return net;
2800}
2801
2802/*
2803 * This function inserts scan command node to the scan pending queue.
2804 */
2805void
2806mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
2807 struct cmd_ctrl_node *cmd_node)
2808{
2809 struct mwifiex_adapter *adapter = priv->adapter;
2810 unsigned long flags;
2811
2812 cmd_node->wait_q_enabled = true;
2813 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
2814 list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
2815 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
2816}
2817
2818/*
2819 * This function finds an AP with specific ssid in the scan list.
2820 */
2821int mwifiex_find_best_network(struct mwifiex_private *priv,
2822 struct mwifiex_ssid_bssid *req_ssid_bssid)
2823{
2824 struct mwifiex_adapter *adapter = priv->adapter;
2825 struct mwifiex_bssdescriptor *req_bss;
2826 s32 i;
2827
2828 memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
2829
2830 i = mwifiex_find_best_network_in_list(priv);
2831
2832 if (i >= 0) {
2833 req_bss = &adapter->scan_table[i];
2834 memcpy(&req_ssid_bssid->ssid, &req_bss->ssid,
2835 sizeof(struct mwifiex_802_11_ssid));
2836 memcpy((u8 *) &req_ssid_bssid->bssid,
2837 (u8 *) &req_bss->mac_address, ETH_ALEN);
2838
2839 /* Make sure we are in the right mode */
2840 if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED)
2841 priv->bss_mode = req_bss->bss_mode;
2842 }
2843
2844 if (!req_ssid_bssid->ssid.ssid_len)
2845 return -1;
2846
2847 dev_dbg(adapter->dev, "info: Best network found = [%s], "
2848 "[%pM]\n", req_ssid_bssid->ssid.ssid,
2849 req_ssid_bssid->bssid);
2850
2851 return 0;
2852}
2853
2854/*
2855 * This function sends a scan command for all available channels to the
2856 * firmware, filtered on a specific SSID.
2857 */
2858static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
2859 struct mwifiex_802_11_ssid *req_ssid)
2860{
2861 struct mwifiex_adapter *adapter = priv->adapter;
2862 int ret = 0;
2863 struct mwifiex_user_scan_cfg *scan_cfg;
2864
2865 if (!req_ssid)
2866 return -1;
2867
2868 if (adapter->scan_processing) {
2869 dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
2870 return ret;
2871 }
2872
2873 if (priv->scan_block) {
2874 dev_dbg(adapter->dev,
2875 "cmd: Scan is blocked during association...\n");
2876 return ret;
2877 }
2878
2879 mwifiex_scan_delete_ssid_table_entry(priv, req_ssid);
2880
2881 scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
2882 if (!scan_cfg) {
2883 dev_err(adapter->dev, "failed to alloc scan_cfg\n");
2884 return -ENOMEM;
2885 }
2886
2887 memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
2888 req_ssid->ssid_len);
2889 scan_cfg->keep_previous_scan = true;
2890
2891 ret = mwifiex_scan_networks(priv, scan_cfg);
2892
2893 kfree(scan_cfg);
2894 return ret;
2895}
2896
2897/*
2898 * Sends IOCTL request to start a scan.
2899 *
2900 * This function allocates the IOCTL request buffer, fills it
2901 * with requisite parameters and calls the IOCTL handler.
2902 *
2903 * Scan command can be issued for both normal scan and specific SSID
2904 * scan, depending upon whether an SSID is provided or not.
2905 */
2906int mwifiex_request_scan(struct mwifiex_private *priv,
2907 struct mwifiex_802_11_ssid *req_ssid)
2908{
2909 int ret;
2910
2911 if (down_interruptible(&priv->async_sem)) {
2912 dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
2913 __func__);
2914 return -1;
2915 }
2916 priv->scan_pending_on_block = true;
2917
2918 priv->adapter->cmd_wait_q.condition = false;
2919
2920 if (req_ssid && req_ssid->ssid_len != 0)
2921 /* Specific SSID scan */
2922 ret = mwifiex_scan_specific_ssid(priv, req_ssid);
2923 else
2924 /* Normal scan */
2925 ret = mwifiex_scan_networks(priv, NULL);
2926
2927 if (!ret)
2928 ret = mwifiex_wait_queue_complete(priv->adapter);
2929
2930 if (ret == -1) {
2931 priv->scan_pending_on_block = false;
2932 up(&priv->async_sem);
2933 }
2934
2935 return ret;
2936}
2937
2938/*
2939 * This function appends the vendor specific IE TLV to a buffer.
2940 */
2941int
2942mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
2943 u16 vsie_mask, u8 **buffer)
2944{
2945 int id, ret_len = 0;
2946 struct mwifiex_ie_types_vendor_param_set *vs_param_set;
2947
2948 if (!buffer)
2949 return 0;
2950 if (!(*buffer))
2951 return 0;
2952
2953 /*
2954 * Traverse through the saved vendor specific IE array and append
2955 * the selected(scan/assoc/adhoc) IE as TLV to the command
2956 */
2957 for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
2958 if (priv->vs_ie[id].mask & vsie_mask) {
2959 vs_param_set =
2960 (struct mwifiex_ie_types_vendor_param_set *)
2961 *buffer;
2962 vs_param_set->header.type =
2963 cpu_to_le16(TLV_TYPE_PASSTHROUGH);
2964 vs_param_set->header.len =
2965 cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
2966 & 0x00FF) + 2);
2967 memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
2968 le16_to_cpu(vs_param_set->header.len));
2969 *buffer += le16_to_cpu(vs_param_set->header.len) +
2970 sizeof(struct mwifiex_ie_types_header);
2971 ret_len += le16_to_cpu(vs_param_set->header.len) +
2972 sizeof(struct mwifiex_ie_types_header);
2973 }
2974 }
2975 return ret_len;
2976}
2977
2978/*
2979 * This function saves a beacon buffer of the current BSS descriptor.
2980 *
2981 * The current beacon buffer is saved so that it can be restored in the
2982 * following cases that makes the beacon buffer not to contain the current
2983 * ssid's beacon buffer.
2984 * - The current ssid was not found somehow in the last scan.
2985 * - The current ssid was the last entry of the scan table and overloaded.
2986 */
2987void
2988mwifiex_save_curr_bcn(struct mwifiex_private *priv)
2989{
2990 struct mwifiex_bssdescriptor *curr_bss =
2991 &priv->curr_bss_params.bss_descriptor;
2992
2993 if (!curr_bss->beacon_buf_size)
2994 return;
2995
2996 /* allocate beacon buffer at 1st time; or if it's size has changed */
2997 if (!priv->curr_bcn_buf ||
2998 priv->curr_bcn_size != curr_bss->beacon_buf_size) {
2999 priv->curr_bcn_size = curr_bss->beacon_buf_size;
3000
3001 kfree(priv->curr_bcn_buf);
3002 priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
3003 GFP_KERNEL);
3004 if (!priv->curr_bcn_buf) {
3005 dev_err(priv->adapter->dev,
3006 "failed to alloc curr_bcn_buf\n");
3007 return;
3008 }
3009 }
3010
3011 memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
3012 curr_bss->beacon_buf_size);
3013 dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
3014 priv->curr_bcn_size);
3015}
3016
3017/*
3018 * This function frees the current BSS descriptor beacon buffer.
3019 */
3020void
3021mwifiex_free_curr_bcn(struct mwifiex_private *priv)
3022{
3023 kfree(priv->curr_bcn_buf);
3024 priv->curr_bcn_buf = NULL;
3025}
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
new file mode 100644
index 000000000000..d425dbd91d19
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -0,0 +1,1754 @@
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;
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 kfree(card);
72 return -EIO;
73 }
74
75 if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
76 pr_err("%s: add card failed\n", __func__);
77 kfree(card);
78 sdio_claim_host(func);
79 ret = sdio_disable_func(func);
80 sdio_release_host(func);
81 ret = -1;
82 }
83
84 return ret;
85}
86
87/*
88 * SDIO remove.
89 *
90 * This function removes the interface and frees up the card structure.
91 */
92static void
93mwifiex_sdio_remove(struct sdio_func *func)
94{
95 struct sdio_mmc_card *card;
96
97 pr_debug("info: SDIO func num=%d\n", func->num);
98
99 if (func) {
100 card = sdio_get_drvdata(func);
101 if (card) {
102 mwifiex_remove_card(card->adapter,
103 &add_remove_card_sem);
104 kfree(card);
105 }
106 }
107}
108
109/*
110 * SDIO suspend.
111 *
112 * Kernel needs to suspend all functions separately. Therefore all
113 * registered functions must have drivers with suspend and resume
114 * methods. Failing that the kernel simply removes the whole card.
115 *
116 * If already not suspended, this function allocates and sends a host
117 * sleep activate request to the firmware and turns off the traffic.
118 */
119static int mwifiex_sdio_suspend(struct device *dev)
120{
121 struct sdio_func *func = dev_to_sdio_func(dev);
122 struct sdio_mmc_card *card;
123 struct mwifiex_adapter *adapter;
124 mmc_pm_flag_t pm_flag = 0;
125 int hs_actived = 0;
126 int i;
127 int ret = 0;
128
129 if (func) {
130 pm_flag = sdio_get_host_pm_caps(func);
131 pr_debug("cmd: %s: suspend: PM flag = 0x%x\n",
132 sdio_func_id(func), pm_flag);
133 if (!(pm_flag & MMC_PM_KEEP_POWER)) {
134 pr_err("%s: cannot remain alive while host is"
135 " suspended\n", sdio_func_id(func));
136 return -ENOSYS;
137 }
138
139 card = sdio_get_drvdata(func);
140 if (!card || !card->adapter) {
141 pr_err("suspend: invalid card or adapter\n");
142 return 0;
143 }
144 } else {
145 pr_err("suspend: sdio_func is not specified\n");
146 return 0;
147 }
148
149 adapter = card->adapter;
150
151 /* Enable the Host Sleep */
152 hs_actived = mwifiex_enable_hs(adapter);
153 if (hs_actived) {
154 pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n");
155 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
156 }
157
158 /* Indicate device suspended */
159 adapter->is_suspended = true;
160
161 for (i = 0; i < adapter->priv_num; i++)
162 netif_carrier_off(adapter->priv[i]->netdev);
163
164 return ret;
165}
166
167/*
168 * SDIO resume.
169 *
170 * Kernel needs to suspend all functions separately. Therefore all
171 * registered functions must have drivers with suspend and resume
172 * methods. Failing that the kernel simply removes the whole card.
173 *
174 * If already not resumed, this function turns on the traffic and
175 * sends a host sleep cancel request to the firmware.
176 */
177static int mwifiex_sdio_resume(struct device *dev)
178{
179 struct sdio_func *func = dev_to_sdio_func(dev);
180 struct sdio_mmc_card *card;
181 struct mwifiex_adapter *adapter;
182 mmc_pm_flag_t pm_flag = 0;
183 int i;
184
185 if (func) {
186 pm_flag = sdio_get_host_pm_caps(func);
187 card = sdio_get_drvdata(func);
188 if (!card || !card->adapter) {
189 pr_err("resume: invalid card or adapter\n");
190 return 0;
191 }
192 } else {
193 pr_err("resume: sdio_func is not specified\n");
194 return 0;
195 }
196
197 adapter = card->adapter;
198
199 if (!adapter->is_suspended) {
200 dev_warn(adapter->dev, "device already resumed\n");
201 return 0;
202 }
203
204 adapter->is_suspended = false;
205
206 for (i = 0; i < adapter->priv_num; i++)
207 if (adapter->priv[i]->media_connected)
208 netif_carrier_on(adapter->priv[i]->netdev);
209
210 /* Disable Host Sleep */
211 mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
212 MWIFIEX_ASYNC_CMD);
213
214 return 0;
215}
216
217/* Device ID for SD8787 */
218#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
219
220/* WLAN IDs */
221static const struct sdio_device_id mwifiex_ids[] = {
222 {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
223 {},
224};
225
226MODULE_DEVICE_TABLE(sdio, mwifiex_ids);
227
228static const struct dev_pm_ops mwifiex_sdio_pm_ops = {
229 .suspend = mwifiex_sdio_suspend,
230 .resume = mwifiex_sdio_resume,
231};
232
233static struct sdio_driver mwifiex_sdio = {
234 .name = "mwifiex_sdio",
235 .id_table = mwifiex_ids,
236 .probe = mwifiex_sdio_probe,
237 .remove = mwifiex_sdio_remove,
238 .drv = {
239 .owner = THIS_MODULE,
240 .pm = &mwifiex_sdio_pm_ops,
241 }
242};
243
244/*
245 * This function writes data into SDIO card register.
246 */
247static int
248mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data)
249{
250 struct sdio_mmc_card *card = adapter->card;
251 int ret = -1;
252
253 sdio_claim_host(card->func);
254 sdio_writeb(card->func, (u8) data, reg, &ret);
255 sdio_release_host(card->func);
256
257 return ret;
258}
259
260/*
261 * This function reads data from SDIO card register.
262 */
263static int
264mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data)
265{
266 struct sdio_mmc_card *card = adapter->card;
267 int ret = -1;
268 u8 val;
269
270 sdio_claim_host(card->func);
271 val = sdio_readb(card->func, reg, &ret);
272 sdio_release_host(card->func);
273
274 *data = val;
275
276 return ret;
277}
278
279/*
280 * This function writes multiple data into SDIO card memory.
281 *
282 * This does not work in suspended mode.
283 */
284static int
285mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
286 u8 *buffer, u32 pkt_len, u32 port)
287{
288 struct sdio_mmc_card *card = adapter->card;
289 int ret = -1;
290 u8 blk_mode =
291 (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
292 u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
293 u32 blk_cnt =
294 (blk_mode ==
295 BLOCK_MODE) ? (pkt_len /
296 MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len;
297 u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
298
299 if (adapter->is_suspended) {
300 dev_err(adapter->dev,
301 "%s: not allowed while suspended\n", __func__);
302 return -1;
303 }
304
305 sdio_claim_host(card->func);
306
307 if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size))
308 ret = 0;
309
310 sdio_release_host(card->func);
311
312 return ret;
313}
314
315/*
316 * This function reads multiple data from SDIO card memory.
317 */
318static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer,
319 u32 len, u32 port, 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 dev_dbg(adapter->dev, "event: wakeup device...\n");
352
353 return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
354}
355
356/*
357 * This function is called after the card has woken up.
358 *
359 * The card configuration register is reset.
360 */
361static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
362{
363 dev_dbg(adapter->dev, "cmd: wakeup device completed\n");
364
365 return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
366}
367
368/*
369 * This function initializes the IO ports.
370 *
371 * The following operations are performed -
372 * - Read the IO ports (0, 1 and 2)
373 * - Set host interrupt Reset-To-Read to clear
374 * - Set auto re-enable interrupt
375 */
376static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
377{
378 u32 reg;
379
380 adapter->ioport = 0;
381
382 /* Read the IO port */
383 if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, &reg))
384 adapter->ioport |= (reg & 0xff);
385 else
386 return -1;
387
388 if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, &reg))
389 adapter->ioport |= ((reg & 0xff) << 8);
390 else
391 return -1;
392
393 if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, &reg))
394 adapter->ioport |= ((reg & 0xff) << 16);
395 else
396 return -1;
397
398 pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
399
400 /* Set Host interrupt reset to read to clear */
401 if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, &reg))
402 mwifiex_write_reg(adapter, HOST_INT_RSR_REG,
403 reg | SDIO_INT_MASK);
404 else
405 return -1;
406
407 /* Dnld/Upld ready set to auto reset */
408 if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, &reg))
409 mwifiex_write_reg(adapter, CARD_MISC_CFG_REG,
410 reg | AUTO_RE_ENABLE_INT);
411 else
412 return -1;
413
414 return 0;
415}
416
417/*
418 * This function sends data to the card.
419 */
420static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
421 u8 *payload, u32 pkt_len, u32 port)
422{
423 u32 i = 0;
424 int ret;
425
426 do {
427 ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
428 if (ret) {
429 i++;
430 dev_err(adapter->dev, "host_to_card, write iomem"
431 " (%d) failed: %d\n", i, ret);
432 if (mwifiex_write_reg(adapter,
433 CONFIGURATION_REG, 0x04))
434 dev_err(adapter->dev, "write CFG reg failed\n");
435
436 ret = -1;
437 if (i > MAX_WRITE_IOMEM_RETRY)
438 return ret;
439 }
440 } while (ret == -1);
441
442 return ret;
443}
444
445/*
446 * This function gets the read port.
447 *
448 * If control port bit is set in MP read bitmap, the control port
449 * is returned, otherwise the current read port is returned and
450 * the value is increased (provided it does not reach the maximum
451 * limit, in which case it is reset to 1)
452 */
453static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
454{
455 struct sdio_mmc_card *card = adapter->card;
456 u16 rd_bitmap = card->mp_rd_bitmap;
457
458 dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap);
459
460 if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK)))
461 return -1;
462
463 if (card->mp_rd_bitmap & CTRL_PORT_MASK) {
464 card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK);
465 *port = CTRL_PORT;
466 dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n",
467 *port, card->mp_rd_bitmap);
468 } else {
469 if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) {
470 card->mp_rd_bitmap &=
471 (u16) (~(1 << card->curr_rd_port));
472 *port = card->curr_rd_port;
473
474 if (++card->curr_rd_port == MAX_PORT)
475 card->curr_rd_port = 1;
476 } else {
477 return -1;
478 }
479
480 dev_dbg(adapter->dev,
481 "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n",
482 *port, rd_bitmap, card->mp_rd_bitmap);
483 }
484 return 0;
485}
486
487/*
488 * This function gets the write port for data.
489 *
490 * The current write port is returned if available and the value is
491 * increased (provided it does not reach the maximum limit, in which
492 * case it is reset to 1)
493 */
494static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
495{
496 struct sdio_mmc_card *card = adapter->card;
497 u16 wr_bitmap = card->mp_wr_bitmap;
498
499 dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap);
500
501 if (!(wr_bitmap & card->mp_data_port_mask))
502 return -1;
503
504 if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
505 card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port));
506 *port = card->curr_wr_port;
507 if (++card->curr_wr_port == card->mp_end_port)
508 card->curr_wr_port = 1;
509 } else {
510 adapter->data_sent = true;
511 return -EBUSY;
512 }
513
514 if (*port == CTRL_PORT) {
515 dev_err(adapter->dev, "invalid data port=%d cur port=%d"
516 " mp_wr_bitmap=0x%04x -> 0x%04x\n",
517 *port, card->curr_wr_port, wr_bitmap,
518 card->mp_wr_bitmap);
519 return -1;
520 }
521
522 dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n",
523 *port, wr_bitmap, card->mp_wr_bitmap);
524
525 return 0;
526}
527
528/*
529 * This function polls the card status.
530 */
531static int
532mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
533{
534 u32 tries;
535 u32 cs;
536
537 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
538 if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs))
539 break;
540 else if ((cs & bits) == bits)
541 return 0;
542
543 udelay(10);
544 }
545
546 dev_err(adapter->dev, "poll card status failed, tries = %d\n",
547 tries);
548 return -1;
549}
550
551/*
552 * This function reads the firmware status.
553 */
554static int
555mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
556{
557 u32 fws0, fws1;
558
559 if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0))
560 return -1;
561
562 if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1))
563 return -1;
564
565 *dat = (u16) ((fws1 << 8) | fws0);
566
567 return 0;
568}
569
570/*
571 * This function disables the host interrupt.
572 *
573 * The host interrupt mask is read, the disable bit is reset and
574 * written back to the card host interrupt mask register.
575 */
576static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
577{
578 u32 host_int_mask;
579
580 /* Read back the host_int_mask register */
581 if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
582 return -1;
583
584 /* Update with the mask and write back to the register */
585 host_int_mask &= ~HOST_INT_DISABLE;
586
587 if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
588 dev_err(adapter->dev, "disable host interrupt failed\n");
589 return -1;
590 }
591
592 return 0;
593}
594
595/*
596 * This function enables the host interrupt.
597 *
598 * The host interrupt enable mask is written to the card
599 * host interrupt mask register.
600 */
601static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
602{
603 /* Simply write the mask to the register */
604 if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) {
605 dev_err(adapter->dev, "enable host interrupt failed\n");
606 return -1;
607 }
608 return 0;
609}
610
611/*
612 * This function sends a data buffer to the card.
613 */
614static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
615 u32 *type, u8 *buffer,
616 u32 npayload, u32 ioport)
617{
618 int ret;
619 u32 nb;
620
621 if (!buffer) {
622 dev_err(adapter->dev, "%s: buffer is NULL\n", __func__);
623 return -1;
624 }
625
626 ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1);
627
628 if (ret) {
629 dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
630 ret);
631 return -1;
632 }
633
634 nb = le16_to_cpu(*(__le16 *) (buffer));
635 if (nb > npayload) {
636 dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n",
637 __func__, nb, npayload);
638 return -1;
639 }
640
641 *type = le16_to_cpu(*(__le16 *) (buffer + 2));
642
643 return ret;
644}
645
646/*
647 * This function downloads the firmware to the card.
648 *
649 * Firmware is downloaded to the card in blocks. Every block download
650 * is tested for CRC errors, and retried a number of times before
651 * returning failure.
652 */
653static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
654 struct mwifiex_fw_image *fw)
655{
656 int ret;
657 u8 *firmware = fw->fw_buf;
658 u32 firmware_len = fw->fw_len;
659 u32 offset = 0;
660 u32 base0, base1;
661 u8 *fwbuf;
662 u16 len = 0;
663 u32 txlen, tx_blocks = 0, tries;
664 u32 i = 0;
665
666 if (!firmware_len) {
667 dev_err(adapter->dev, "firmware image not found!"
668 " Terminating download\n");
669 return -1;
670 }
671
672 dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n",
673 firmware_len);
674
675 /* Assume that the allocated buffer is 8-byte aligned */
676 fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
677 if (!fwbuf) {
678 dev_err(adapter->dev, "unable to alloc buffer for firmware."
679 " Terminating download\n");
680 return -ENOMEM;
681 }
682
683 /* Perform firmware data transfer */
684 do {
685 /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY
686 bits */
687 ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY |
688 DN_LD_CARD_RDY);
689 if (ret) {
690 dev_err(adapter->dev, "FW download with helper:"
691 " poll status timeout @ %d\n", offset);
692 goto done;
693 }
694
695 /* More data? */
696 if (offset >= firmware_len)
697 break;
698
699 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
700 ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0,
701 &base0);
702 if (ret) {
703 dev_err(adapter->dev, "dev BASE0 register read"
704 " failed: base0=0x%04X(%d). Terminating "
705 "download\n", base0, base0);
706 goto done;
707 }
708 ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1,
709 &base1);
710 if (ret) {
711 dev_err(adapter->dev, "dev BASE1 register read"
712 " failed: base1=0x%04X(%d). Terminating "
713 "download\n", base1, base1);
714 goto done;
715 }
716 len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
717
718 if (len)
719 break;
720
721 udelay(10);
722 }
723
724 if (!len) {
725 break;
726 } else if (len > MWIFIEX_UPLD_SIZE) {
727 dev_err(adapter->dev, "FW download failed @ %d,"
728 " invalid length %d\n", offset, len);
729 ret = -1;
730 goto done;
731 }
732
733 txlen = len;
734
735 if (len & BIT(0)) {
736 i++;
737 if (i > MAX_WRITE_IOMEM_RETRY) {
738 dev_err(adapter->dev, "FW download failed @"
739 " %d, over max retry count\n", offset);
740 ret = -1;
741 goto done;
742 }
743 dev_err(adapter->dev, "CRC indicated by the helper:"
744 " len = 0x%04X, txlen = %d\n", len, txlen);
745 len &= ~BIT(0);
746 /* Setting this to 0 to resend from same offset */
747 txlen = 0;
748 } else {
749 i = 0;
750
751 /* Set blocksize to transfer - checking for last
752 block */
753 if (firmware_len - offset < txlen)
754 txlen = firmware_len - offset;
755
756 tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE -
757 1) / MWIFIEX_SDIO_BLOCK_SIZE;
758
759 /* Copy payload to buffer */
760 memmove(fwbuf, &firmware[offset], txlen);
761 }
762
763 ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks *
764 MWIFIEX_SDIO_BLOCK_SIZE,
765 adapter->ioport);
766 if (ret) {
767 dev_err(adapter->dev, "FW download, write iomem (%d)"
768 " failed @ %d\n", i, offset);
769 if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
770 dev_err(adapter->dev, "write CFG reg failed\n");
771
772 ret = -1;
773 goto done;
774 }
775
776 offset += txlen;
777 } while (true);
778
779 dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n",
780 offset);
781
782 ret = 0;
783done:
784 kfree(fwbuf);
785 return ret;
786}
787
788/*
789 * This function checks the firmware status in card.
790 *
791 * The winner interface is also determined by this function.
792 */
793static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
794 u32 poll_num, int *winner)
795{
796 int ret = 0;
797 u16 firmware_stat;
798 u32 tries;
799 u32 winner_status;
800
801 /* Wait for firmware initialization event */
802 for (tries = 0; tries < poll_num; tries++) {
803 ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
804 if (ret)
805 continue;
806 if (firmware_stat == FIRMWARE_READY) {
807 ret = 0;
808 break;
809 } else {
810 mdelay(100);
811 ret = -1;
812 }
813 }
814
815 if (winner && ret) {
816 if (mwifiex_read_reg
817 (adapter, CARD_FW_STATUS0_REG, &winner_status))
818 winner_status = 0;
819
820 if (winner_status)
821 *winner = 0;
822 else
823 *winner = 1;
824 }
825 return ret;
826}
827
828/*
829 * This function reads the interrupt status from card.
830 */
831static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
832{
833 struct sdio_mmc_card *card = adapter->card;
834 u32 sdio_ireg;
835 unsigned long flags;
836
837 if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
838 REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK,
839 0)) {
840 dev_err(adapter->dev, "read mp_regs failed\n");
841 return;
842 }
843
844 sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
845 if (sdio_ireg) {
846 /*
847 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
848 * Clear the interrupt status register
849 */
850 dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
851 spin_lock_irqsave(&adapter->int_lock, flags);
852 adapter->int_status |= sdio_ireg;
853 spin_unlock_irqrestore(&adapter->int_lock, flags);
854 }
855}
856
857/*
858 * SDIO interrupt handler.
859 *
860 * This function reads the interrupt status from firmware and assigns
861 * the main process in workqueue which will handle the interrupt.
862 */
863static void
864mwifiex_sdio_interrupt(struct sdio_func *func)
865{
866 struct mwifiex_adapter *adapter;
867 struct sdio_mmc_card *card;
868
869 card = sdio_get_drvdata(func);
870 if (!card || !card->adapter) {
871 pr_debug("int: func=%p card=%p adapter=%p\n",
872 func, card, card ? card->adapter : NULL);
873 return;
874 }
875 adapter = card->adapter;
876
877 if (adapter->surprise_removed)
878 return;
879
880 if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
881 adapter->ps_state = PS_STATE_AWAKE;
882
883 mwifiex_interrupt_status(adapter);
884 queue_work(adapter->workqueue, &adapter->main_work);
885}
886
887/*
888 * This function decodes a received packet.
889 *
890 * Based on the type, the packet is treated as either a data, or
891 * a command response, or an event, and the correct handler
892 * function is invoked.
893 */
894static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
895 struct sk_buff *skb, u32 upld_typ)
896{
897 u8 *cmd_buf;
898
899 skb_pull(skb, INTF_HEADER_LEN);
900
901 switch (upld_typ) {
902 case MWIFIEX_TYPE_DATA:
903 dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
904 mwifiex_handle_rx_packet(adapter, skb);
905 break;
906
907 case MWIFIEX_TYPE_CMD:
908 dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n");
909 /* take care of curr_cmd = NULL case */
910 if (!adapter->curr_cmd) {
911 cmd_buf = adapter->upld_buf;
912
913 if (adapter->ps_state == PS_STATE_SLEEP_CFM)
914 mwifiex_process_sleep_confirm_resp(adapter,
915 skb->data, skb->len);
916
917 memcpy(cmd_buf, skb->data, min_t(u32,
918 MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
919
920 dev_kfree_skb_any(skb);
921 } else {
922 adapter->cmd_resp_received = true;
923 adapter->curr_cmd->resp_skb = skb;
924 }
925 break;
926
927 case MWIFIEX_TYPE_EVENT:
928 dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
929 adapter->event_cause = *(u32 *) skb->data;
930
931 skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
932
933 if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE))
934 memcpy(adapter->event_body, skb->data, skb->len);
935
936 /* event cause has been saved to adapter->event_cause */
937 adapter->event_received = true;
938 adapter->event_skb = skb;
939
940 break;
941
942 default:
943 dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ);
944 dev_kfree_skb_any(skb);
945 break;
946 }
947
948 return 0;
949}
950
951/*
952 * This function transfers received packets from card to driver, performing
953 * aggregation if required.
954 *
955 * For data received on control port, or if aggregation is disabled, the
956 * received buffers are uploaded as separate packets. However, if aggregation
957 * is enabled and required, the buffers are copied onto an aggregation buffer,
958 * provided there is space left, processed and finally uploaded.
959 */
960static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
961 struct sk_buff *skb, u8 port)
962{
963 struct sdio_mmc_card *card = adapter->card;
964 s32 f_do_rx_aggr = 0;
965 s32 f_do_rx_cur = 0;
966 s32 f_aggr_cur = 0;
967 struct sk_buff *skb_deaggr;
968 u32 pind;
969 u32 pkt_len, pkt_type = 0;
970 u8 *curr_ptr;
971 u32 rx_len = skb->len;
972
973 if (port == CTRL_PORT) {
974 /* Read the command Resp without aggr */
975 dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
976 "response\n", __func__);
977
978 f_do_rx_cur = 1;
979 goto rx_curr_single;
980 }
981
982 if (!card->mpa_rx.enabled) {
983 dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n",
984 __func__);
985
986 f_do_rx_cur = 1;
987 goto rx_curr_single;
988 }
989
990 if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) {
991 /* Some more data RX pending */
992 dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
993
994 if (MP_RX_AGGR_IN_PROGRESS(card)) {
995 if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) {
996 f_aggr_cur = 1;
997 } else {
998 /* No room in Aggr buf, do rx aggr now */
999 f_do_rx_aggr = 1;
1000 f_do_rx_cur = 1;
1001 }
1002 } else {
1003 /* Rx aggr not in progress */
1004 f_aggr_cur = 1;
1005 }
1006
1007 } else {
1008 /* No more data RX pending */
1009 dev_dbg(adapter->dev, "info: %s: last packet\n", __func__);
1010
1011 if (MP_RX_AGGR_IN_PROGRESS(card)) {
1012 f_do_rx_aggr = 1;
1013 if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len))
1014 f_aggr_cur = 1;
1015 else
1016 /* No room in Aggr buf, do rx aggr now */
1017 f_do_rx_cur = 1;
1018 } else {
1019 f_do_rx_cur = 1;
1020 }
1021 }
1022
1023 if (f_aggr_cur) {
1024 dev_dbg(adapter->dev, "info: current packet aggregation\n");
1025 /* Curr pkt can be aggregated */
1026 MP_RX_AGGR_SETUP(card, skb, port);
1027
1028 if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
1029 MP_RX_AGGR_PORT_LIMIT_REACHED(card)) {
1030 dev_dbg(adapter->dev, "info: %s: aggregated packet "
1031 "limit reached\n", __func__);
1032 /* No more pkts allowed in Aggr buf, rx it */
1033 f_do_rx_aggr = 1;
1034 }
1035 }
1036
1037 if (f_do_rx_aggr) {
1038 /* do aggr RX now */
1039 dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
1040 card->mpa_rx.pkt_cnt);
1041
1042 if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
1043 card->mpa_rx.buf_len,
1044 (adapter->ioport | 0x1000 |
1045 (card->mpa_rx.ports << 4)) +
1046 card->mpa_rx.start_port, 1))
1047 return -1;
1048
1049 curr_ptr = card->mpa_rx.buf;
1050
1051 for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) {
1052
1053 /* get curr PKT len & type */
1054 pkt_len = *(u16 *) &curr_ptr[0];
1055 pkt_type = *(u16 *) &curr_ptr[2];
1056
1057 /* copy pkt to deaggr buf */
1058 skb_deaggr = card->mpa_rx.skb_arr[pind];
1059
1060 if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <=
1061 card->mpa_rx.len_arr[pind])) {
1062
1063 memcpy(skb_deaggr->data, curr_ptr, pkt_len);
1064
1065 skb_trim(skb_deaggr, pkt_len);
1066
1067 /* Process de-aggr packet */
1068 mwifiex_decode_rx_packet(adapter, skb_deaggr,
1069 pkt_type);
1070 } else {
1071 dev_err(adapter->dev, "wrong aggr pkt:"
1072 " type=%d len=%d max_len=%d\n",
1073 pkt_type, pkt_len,
1074 card->mpa_rx.len_arr[pind]);
1075 dev_kfree_skb_any(skb_deaggr);
1076 }
1077 curr_ptr += card->mpa_rx.len_arr[pind];
1078 }
1079 MP_RX_AGGR_BUF_RESET(card);
1080 }
1081
1082rx_curr_single:
1083 if (f_do_rx_cur) {
1084 dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n",
1085 port, rx_len);
1086
1087 if (mwifiex_sdio_card_to_host(adapter, &pkt_type,
1088 skb->data, skb->len,
1089 adapter->ioport + port))
1090 return -1;
1091
1092 mwifiex_decode_rx_packet(adapter, skb, pkt_type);
1093 }
1094
1095 return 0;
1096}
1097
1098/*
1099 * This function checks the current interrupt status.
1100 *
1101 * The following interrupts are checked and handled by this function -
1102 * - Data sent
1103 * - Command sent
1104 * - Packets received
1105 *
1106 * Since the firmware does not generate download ready interrupt if the
1107 * port updated is command port only, command sent interrupt checking
1108 * should be done manually, and for every SDIO interrupt.
1109 *
1110 * In case of Rx packets received, the packets are uploaded from card to
1111 * host and processed accordingly.
1112 */
1113static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
1114{
1115 struct sdio_mmc_card *card = adapter->card;
1116 int ret = 0;
1117 u8 sdio_ireg;
1118 struct sk_buff *skb;
1119 u8 port = CTRL_PORT;
1120 u32 len_reg_l, len_reg_u;
1121 u32 rx_blocks;
1122 u16 rx_len;
1123 unsigned long flags;
1124
1125 spin_lock_irqsave(&adapter->int_lock, flags);
1126 sdio_ireg = adapter->int_status;
1127 adapter->int_status = 0;
1128 spin_unlock_irqrestore(&adapter->int_lock, flags);
1129
1130 if (!sdio_ireg)
1131 return ret;
1132
1133 if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
1134 card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8;
1135 card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L];
1136 dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n",
1137 card->mp_wr_bitmap);
1138 if (adapter->data_sent &&
1139 (card->mp_wr_bitmap & card->mp_data_port_mask)) {
1140 dev_dbg(adapter->dev,
1141 "info: <--- Tx DONE Interrupt --->\n");
1142 adapter->data_sent = false;
1143 }
1144 }
1145
1146 /* As firmware will not generate download ready interrupt if the port
1147 updated is command port only, cmd_sent should be done for any SDIO
1148 interrupt. */
1149 if (adapter->cmd_sent) {
1150 /* Check if firmware has attach buffer at command port and
1151 update just that in wr_bit_map. */
1152 card->mp_wr_bitmap |=
1153 (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
1154 if (card->mp_wr_bitmap & CTRL_PORT_MASK)
1155 adapter->cmd_sent = false;
1156 }
1157
1158 dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
1159 adapter->cmd_sent, adapter->data_sent);
1160 if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
1161 card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8;
1162 card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L];
1163 dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n",
1164 card->mp_rd_bitmap);
1165
1166 while (true) {
1167 ret = mwifiex_get_rd_port(adapter, &port);
1168 if (ret) {
1169 dev_dbg(adapter->dev,
1170 "info: no more rd_port available\n");
1171 break;
1172 }
1173 len_reg_l = RD_LEN_P0_L + (port << 1);
1174 len_reg_u = RD_LEN_P0_U + (port << 1);
1175 rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
1176 rx_len |= (u16) card->mp_regs[len_reg_l];
1177 dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
1178 port, rx_len);
1179 rx_blocks =
1180 (rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
1181 1) / MWIFIEX_SDIO_BLOCK_SIZE;
1182 if (rx_len <= INTF_HEADER_LEN
1183 || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
1184 MWIFIEX_RX_DATA_BUF_SIZE) {
1185 dev_err(adapter->dev, "invalid rx_len=%d\n",
1186 rx_len);
1187 return -1;
1188 }
1189 rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
1190
1191 skb = dev_alloc_skb(rx_len);
1192
1193 if (!skb) {
1194 dev_err(adapter->dev, "%s: failed to alloc skb",
1195 __func__);
1196 return -1;
1197 }
1198
1199 skb_put(skb, rx_len);
1200
1201 dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n",
1202 rx_len, skb->len);
1203
1204 if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb,
1205 port)) {
1206 u32 cr = 0;
1207
1208 dev_err(adapter->dev, "card_to_host_mpa failed:"
1209 " int status=%#x\n", sdio_ireg);
1210 if (mwifiex_read_reg(adapter,
1211 CONFIGURATION_REG, &cr))
1212 dev_err(adapter->dev,
1213 "read CFG reg failed\n");
1214
1215 dev_dbg(adapter->dev,
1216 "info: CFG reg val = %d\n", cr);
1217 if (mwifiex_write_reg(adapter,
1218 CONFIGURATION_REG,
1219 (cr | 0x04)))
1220 dev_err(adapter->dev,
1221 "write CFG reg failed\n");
1222
1223 dev_dbg(adapter->dev, "info: write success\n");
1224 if (mwifiex_read_reg(adapter,
1225 CONFIGURATION_REG, &cr))
1226 dev_err(adapter->dev,
1227 "read CFG reg failed\n");
1228
1229 dev_dbg(adapter->dev,
1230 "info: CFG reg val =%x\n", cr);
1231 dev_kfree_skb_any(skb);
1232 return -1;
1233 }
1234 }
1235 }
1236
1237 return 0;
1238}
1239
1240/*
1241 * This function aggregates transmission buffers in driver and downloads
1242 * the aggregated packet to card.
1243 *
1244 * The individual packets are aggregated by copying into an aggregation
1245 * buffer and then downloaded to the card. Previous unsent packets in the
1246 * aggregation buffer are pre-copied first before new packets are added.
1247 * Aggregation is done till there is space left in the aggregation buffer,
1248 * or till new packets are available.
1249 *
1250 * The function will only download the packet to the card when aggregation
1251 * stops, otherwise it will just aggregate the packet in aggregation buffer
1252 * and return.
1253 */
1254static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
1255 u8 *payload, u32 pkt_len, u8 port,
1256 u32 next_pkt_len)
1257{
1258 struct sdio_mmc_card *card = adapter->card;
1259 int ret = 0;
1260 s32 f_send_aggr_buf = 0;
1261 s32 f_send_cur_buf = 0;
1262 s32 f_precopy_cur_buf = 0;
1263 s32 f_postcopy_cur_buf = 0;
1264
1265 if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) {
1266 dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
1267 __func__);
1268
1269 f_send_cur_buf = 1;
1270 goto tx_curr_single;
1271 }
1272
1273 if (next_pkt_len) {
1274 /* More pkt in TX queue */
1275 dev_dbg(adapter->dev, "info: %s: more packets in queue.\n",
1276 __func__);
1277
1278 if (MP_TX_AGGR_IN_PROGRESS(card)) {
1279 if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) &&
1280 MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
1281 f_precopy_cur_buf = 1;
1282
1283 if (!(card->mp_wr_bitmap &
1284 (1 << card->curr_wr_port))
1285 || !MP_TX_AGGR_BUF_HAS_ROOM(
1286 card, next_pkt_len))
1287 f_send_aggr_buf = 1;
1288 } else {
1289 /* No room in Aggr buf, send it */
1290 f_send_aggr_buf = 1;
1291
1292 if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) ||
1293 !(card->mp_wr_bitmap &
1294 (1 << card->curr_wr_port)))
1295 f_send_cur_buf = 1;
1296 else
1297 f_postcopy_cur_buf = 1;
1298 }
1299 } else {
1300 if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)
1301 && (card->mp_wr_bitmap & (1 << card->curr_wr_port)))
1302 f_precopy_cur_buf = 1;
1303 else
1304 f_send_cur_buf = 1;
1305 }
1306 } else {
1307 /* Last pkt in TX queue */
1308 dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n",
1309 __func__);
1310
1311 if (MP_TX_AGGR_IN_PROGRESS(card)) {
1312 /* some packs in Aggr buf already */
1313 f_send_aggr_buf = 1;
1314
1315 if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len))
1316 f_precopy_cur_buf = 1;
1317 else
1318 /* No room in Aggr buf, send it */
1319 f_send_cur_buf = 1;
1320 } else {
1321 f_send_cur_buf = 1;
1322 }
1323 }
1324
1325 if (f_precopy_cur_buf) {
1326 dev_dbg(adapter->dev, "data: %s: precopy current buffer\n",
1327 __func__);
1328 MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
1329
1330 if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
1331 MP_TX_AGGR_PORT_LIMIT_REACHED(card))
1332 /* No more pkts allowed in Aggr buf, send it */
1333 f_send_aggr_buf = 1;
1334 }
1335
1336 if (f_send_aggr_buf) {
1337 dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
1338 __func__,
1339 card->mpa_tx.start_port, card->mpa_tx.ports);
1340 ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
1341 card->mpa_tx.buf_len,
1342 (adapter->ioport | 0x1000 |
1343 (card->mpa_tx.ports << 4)) +
1344 card->mpa_tx.start_port);
1345
1346 MP_TX_AGGR_BUF_RESET(card);
1347 }
1348
1349tx_curr_single:
1350 if (f_send_cur_buf) {
1351 dev_dbg(adapter->dev, "data: %s: send current buffer %d\n",
1352 __func__, port);
1353 ret = mwifiex_write_data_to_card(adapter, payload, pkt_len,
1354 adapter->ioport + port);
1355 }
1356
1357 if (f_postcopy_cur_buf) {
1358 dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n",
1359 __func__);
1360 MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
1361 }
1362
1363 return ret;
1364}
1365
1366/*
1367 * This function downloads data from driver to card.
1368 *
1369 * Both commands and data packets are transferred to the card by this
1370 * function.
1371 *
1372 * This function adds the SDIO specific header to the front of the buffer
1373 * before transferring. The header contains the length of the packet and
1374 * the type. The firmware handles the packets based upon this set type.
1375 */
1376static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
1377 u8 type, u8 *payload, u32 pkt_len,
1378 struct mwifiex_tx_param *tx_param)
1379{
1380 struct sdio_mmc_card *card = adapter->card;
1381 int ret;
1382 u32 buf_block_len;
1383 u32 blk_size;
1384 u8 port = CTRL_PORT;
1385
1386 /* Allocate buffer and copy payload */
1387 blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
1388 buf_block_len = (pkt_len + blk_size - 1) / blk_size;
1389 *(u16 *) &payload[0] = (u16) pkt_len;
1390 *(u16 *) &payload[2] = type;
1391
1392 /*
1393 * This is SDIO specific header
1394 * u16 length,
1395 * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1,
1396 * MWIFIEX_TYPE_EVENT = 3)
1397 */
1398 if (type == MWIFIEX_TYPE_DATA) {
1399 ret = mwifiex_get_wr_port_data(adapter, &port);
1400 if (ret) {
1401 dev_err(adapter->dev, "%s: no wr_port available\n",
1402 __func__);
1403 return ret;
1404 }
1405 } else {
1406 adapter->cmd_sent = true;
1407 /* Type must be MWIFIEX_TYPE_CMD */
1408
1409 if (pkt_len <= INTF_HEADER_LEN ||
1410 pkt_len > MWIFIEX_UPLD_SIZE)
1411 dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
1412 __func__, payload, pkt_len);
1413 }
1414
1415 /* Transfer data to card */
1416 pkt_len = buf_block_len * blk_size;
1417
1418 if (tx_param)
1419 ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
1420 port, tx_param->next_pkt_len);
1421 else
1422 ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
1423 port, 0);
1424
1425 if (ret) {
1426 if (type == MWIFIEX_TYPE_CMD)
1427 adapter->cmd_sent = false;
1428 if (type == MWIFIEX_TYPE_DATA)
1429 adapter->data_sent = false;
1430 } else {
1431 if (type == MWIFIEX_TYPE_DATA) {
1432 if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port)))
1433 adapter->data_sent = true;
1434 else
1435 adapter->data_sent = false;
1436 }
1437 }
1438
1439 return ret;
1440}
1441
1442/*
1443 * This function allocates the MPA Tx and Rx buffers.
1444 */
1445static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
1446 u32 mpa_tx_buf_size, u32 mpa_rx_buf_size)
1447{
1448 struct sdio_mmc_card *card = adapter->card;
1449 int ret = 0;
1450
1451 card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL);
1452 if (!card->mpa_tx.buf) {
1453 dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n");
1454 ret = -1;
1455 goto error;
1456 }
1457
1458 card->mpa_tx.buf_size = mpa_tx_buf_size;
1459
1460 card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL);
1461 if (!card->mpa_rx.buf) {
1462 dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n");
1463 ret = -1;
1464 goto error;
1465 }
1466
1467 card->mpa_rx.buf_size = mpa_rx_buf_size;
1468
1469error:
1470 if (ret) {
1471 kfree(card->mpa_tx.buf);
1472 kfree(card->mpa_rx.buf);
1473 }
1474
1475 return ret;
1476}
1477
1478/*
1479 * This function unregisters the SDIO device.
1480 *
1481 * The SDIO IRQ is released, the function is disabled and driver
1482 * data is set to null.
1483 */
1484static void
1485mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
1486{
1487 struct sdio_mmc_card *card = adapter->card;
1488
1489 if (adapter->card) {
1490 /* Release the SDIO IRQ */
1491 sdio_claim_host(card->func);
1492 sdio_release_irq(card->func);
1493 sdio_disable_func(card->func);
1494 sdio_release_host(card->func);
1495 sdio_set_drvdata(card->func, NULL);
1496 }
1497}
1498
1499/*
1500 * This function registers the SDIO device.
1501 *
1502 * SDIO IRQ is claimed, block size is set and driver data is initialized.
1503 */
1504static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
1505{
1506 int ret = 0;
1507 struct sdio_mmc_card *card = adapter->card;
1508 struct sdio_func *func = card->func;
1509
1510 /* save adapter pointer in card */
1511 card->adapter = adapter;
1512
1513 sdio_claim_host(func);
1514
1515 /* Request the SDIO IRQ */
1516 ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
1517 if (ret) {
1518 pr_err("claim irq failed: ret=%d\n", ret);
1519 goto disable_func;
1520 }
1521
1522 /* Set block size */
1523 ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
1524 if (ret) {
1525 pr_err("cannot set SDIO block size\n");
1526 ret = -1;
1527 goto release_irq;
1528 }
1529
1530 sdio_release_host(func);
1531 sdio_set_drvdata(func, card);
1532
1533 adapter->dev = &func->dev;
1534
1535 return 0;
1536
1537release_irq:
1538 sdio_release_irq(func);
1539disable_func:
1540 sdio_disable_func(func);
1541 sdio_release_host(func);
1542 adapter->card = NULL;
1543
1544 return -1;
1545}
1546
1547/*
1548 * This function initializes the SDIO driver.
1549 *
1550 * The following initializations steps are followed -
1551 * - Read the Host interrupt status register to acknowledge
1552 * the first interrupt got from bootloader
1553 * - Disable host interrupt mask register
1554 * - Get SDIO port
1555 * - Get revision ID
1556 * - Initialize SDIO variables in card
1557 * - Allocate MP registers
1558 * - Allocate MPA Tx and Rx buffers
1559 */
1560static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
1561{
1562 struct sdio_mmc_card *card = adapter->card;
1563 int ret;
1564 u32 sdio_ireg;
1565
1566 /*
1567 * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
1568 * from the bootloader. If we don't do this we get a interrupt
1569 * as soon as we register the irq.
1570 */
1571 mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
1572
1573 /* Disable host interrupt mask register for SDIO */
1574 mwifiex_sdio_disable_host_int(adapter);
1575
1576 /* Get SDIO ioport */
1577 mwifiex_init_sdio_ioport(adapter);
1578
1579 /* Get revision ID */
1580#define REV_ID_REG 0x5c
1581 mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id);
1582
1583 /* Initialize SDIO variables in card */
1584 card->mp_rd_bitmap = 0;
1585 card->mp_wr_bitmap = 0;
1586 card->curr_rd_port = 1;
1587 card->curr_wr_port = 1;
1588
1589 card->mp_data_port_mask = DATA_PORT_MASK;
1590
1591 card->mpa_tx.buf_len = 0;
1592 card->mpa_tx.pkt_cnt = 0;
1593 card->mpa_tx.start_port = 0;
1594
1595 card->mpa_tx.enabled = 0;
1596 card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
1597
1598 card->mpa_rx.buf_len = 0;
1599 card->mpa_rx.pkt_cnt = 0;
1600 card->mpa_rx.start_port = 0;
1601
1602 card->mpa_rx.enabled = 0;
1603 card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
1604
1605 /* Allocate buffers for SDIO MP-A */
1606 card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
1607 if (!card->mp_regs) {
1608 dev_err(adapter->dev, "failed to alloc mp_regs\n");
1609 return -ENOMEM;
1610 }
1611
1612 ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
1613 SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
1614 SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
1615 if (ret) {
1616 dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
1617 kfree(card->mp_regs);
1618 return -1;
1619 }
1620
1621 return ret;
1622}
1623
1624/*
1625 * This function resets the MPA Tx and Rx buffers.
1626 */
1627static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter)
1628{
1629 struct sdio_mmc_card *card = adapter->card;
1630
1631 MP_TX_AGGR_BUF_RESET(card);
1632 MP_RX_AGGR_BUF_RESET(card);
1633}
1634
1635/*
1636 * This function cleans up the allocated card buffers.
1637 *
1638 * The following are freed by this function -
1639 * - MP registers
1640 * - MPA Tx buffer
1641 * - MPA Rx buffer
1642 */
1643static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter)
1644{
1645 struct sdio_mmc_card *card = adapter->card;
1646
1647 kfree(card->mp_regs);
1648 kfree(card->mpa_tx.buf);
1649 kfree(card->mpa_rx.buf);
1650}
1651
1652/*
1653 * This function updates the MP end port in card.
1654 */
1655static void
1656mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
1657{
1658 struct sdio_mmc_card *card = adapter->card;
1659 int i;
1660
1661 card->mp_end_port = port;
1662
1663 card->mp_data_port_mask = DATA_PORT_MASK;
1664
1665 for (i = 1; i <= MAX_PORT - card->mp_end_port; i++)
1666 card->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
1667
1668 card->curr_wr_port = 1;
1669
1670 dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
1671 port, card->mp_data_port_mask);
1672}
1673
1674static struct mwifiex_if_ops sdio_ops = {
1675 .init_if = mwifiex_init_sdio,
1676 .cleanup_if = mwifiex_cleanup_sdio,
1677 .check_fw_status = mwifiex_check_fw_status,
1678 .prog_fw = mwifiex_prog_fw_w_helper,
1679 .register_dev = mwifiex_register_dev,
1680 .unregister_dev = mwifiex_unregister_dev,
1681 .enable_int = mwifiex_sdio_enable_host_int,
1682 .process_int_status = mwifiex_process_int_status,
1683 .host_to_card = mwifiex_sdio_host_to_card,
1684 .wakeup = mwifiex_pm_wakeup_card,
1685 .wakeup_complete = mwifiex_pm_wakeup_card_complete,
1686
1687 /* SDIO specific */
1688 .update_mp_end_port = mwifiex_update_mp_end_port,
1689 .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
1690};
1691
1692/*
1693 * This function initializes the SDIO driver.
1694 *
1695 * This initiates the semaphore and registers the device with
1696 * SDIO bus.
1697 */
1698static int
1699mwifiex_sdio_init_module(void)
1700{
1701 sema_init(&add_remove_card_sem, 1);
1702
1703 return sdio_register_driver(&mwifiex_sdio);
1704}
1705
1706/*
1707 * This function cleans up the SDIO driver.
1708 *
1709 * The following major steps are followed for cleanup -
1710 * - Resume the device if its suspended
1711 * - Disconnect the device if connected
1712 * - Shutdown the firmware
1713 * - Unregister the device from SDIO bus.
1714 */
1715static void
1716mwifiex_sdio_cleanup_module(void)
1717{
1718 struct mwifiex_adapter *adapter = g_adapter;
1719 int i;
1720
1721 if (down_interruptible(&add_remove_card_sem))
1722 goto exit_sem_err;
1723
1724 if (!adapter || !adapter->priv_num)
1725 goto exit;
1726
1727 if (adapter->is_suspended)
1728 mwifiex_sdio_resume(adapter->dev);
1729
1730 for (i = 0; i < adapter->priv_num; i++)
1731 if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) &&
1732 adapter->priv[i]->media_connected)
1733 mwifiex_deauthenticate(adapter->priv[i], NULL);
1734
1735 if (!adapter->surprise_removed)
1736 mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
1737 MWIFIEX_BSS_ROLE_ANY),
1738 MWIFIEX_FUNC_SHUTDOWN);
1739
1740exit:
1741 up(&add_remove_card_sem);
1742
1743exit_sem_err:
1744 sdio_unregister_driver(&mwifiex_sdio);
1745}
1746
1747module_init(mwifiex_sdio_init_module);
1748module_exit(mwifiex_sdio_cleanup_module);
1749
1750MODULE_AUTHOR("Marvell International Ltd.");
1751MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
1752MODULE_VERSION(SDIO_VERSION);
1753MODULE_LICENSE("GPL v2");
1754MODULE_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..4e97e90aa399
--- /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 w/o 4 bytes of interface header */
171#define MWIFIEX_EVENT_HEADER_LEN 4
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..8af3a78d2723
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -0,0 +1,1219 @@
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 host_cmd_ds_command *cmd)
194{
195 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
196 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
197 S_DS_GEN);
198 return 0;
199}
200
201/*
202 * This function prepares command to set/get Tx data rate configuration.
203 *
204 * Preparation includes -
205 * - Setting command ID, action and proper size
206 * - Setting configuration index, rate scope and rate drop pattern
207 * parameters (as required)
208 * - Ensuring correct endian-ness
209 */
210static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
211 struct host_cmd_ds_command *cmd,
212 u16 cmd_action, void *data_buf)
213{
214 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
215 struct mwifiex_rate_scope *rate_scope;
216 struct mwifiex_rate_drop_pattern *rate_drop;
217 u16 *pbitmap_rates = (u16 *) data_buf;
218
219 u32 i;
220
221 cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
222
223 rate_cfg->action = cpu_to_le16(cmd_action);
224 rate_cfg->cfg_index = 0;
225
226 rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
227 sizeof(struct host_cmd_ds_tx_rate_cfg));
228 rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
229 rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) -
230 sizeof(struct mwifiex_ie_types_header));
231 if (pbitmap_rates != NULL) {
232 rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
233 rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
234 for (i = 0;
235 i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
236 i++)
237 rate_scope->ht_mcs_rate_bitmap[i] =
238 cpu_to_le16(pbitmap_rates[2 + i]);
239 } else {
240 rate_scope->hr_dsss_rate_bitmap =
241 cpu_to_le16(priv->bitmap_rates[0]);
242 rate_scope->ofdm_rate_bitmap =
243 cpu_to_le16(priv->bitmap_rates[1]);
244 for (i = 0;
245 i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
246 i++)
247 rate_scope->ht_mcs_rate_bitmap[i] =
248 cpu_to_le16(priv->bitmap_rates[2 + i]);
249 }
250
251 rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
252 sizeof(struct mwifiex_rate_scope));
253 rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
254 rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
255 rate_drop->rate_drop_mode = 0;
256
257 cmd->size =
258 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
259 sizeof(struct mwifiex_rate_scope) +
260 sizeof(struct mwifiex_rate_drop_pattern));
261
262 return 0;
263}
264
265/*
266 * This function prepares command to set/get Tx power configuration.
267 *
268 * Preparation includes -
269 * - Setting command ID, action and proper size
270 * - Setting Tx power mode, power group TLV
271 * (as required)
272 * - Ensuring correct endian-ness
273 */
274static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
275 u16 cmd_action, void *data_buf)
276{
277 struct mwifiex_types_power_group *pg_tlv;
278 struct host_cmd_ds_txpwr_cfg *txp;
279 struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
280
281 cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
282 cmd->size =
283 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
284 switch (cmd_action) {
285 case HostCmd_ACT_GEN_SET:
286 txp = (struct host_cmd_ds_txpwr_cfg *) data_buf;
287 if (txp->mode) {
288 pg_tlv = (struct mwifiex_types_power_group
289 *) ((unsigned long) data_buf +
290 sizeof(struct host_cmd_ds_txpwr_cfg));
291 memmove(cmd_txp_cfg, data_buf,
292 sizeof(struct host_cmd_ds_txpwr_cfg) +
293 sizeof(struct mwifiex_types_power_group) +
294 pg_tlv->length);
295
296 pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
297 cmd_txp_cfg +
298 sizeof(struct host_cmd_ds_txpwr_cfg));
299 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
300 sizeof(struct mwifiex_types_power_group) +
301 pg_tlv->length);
302 } else {
303 memmove(cmd_txp_cfg, data_buf,
304 sizeof(struct host_cmd_ds_txpwr_cfg));
305 }
306 cmd_txp_cfg->action = cpu_to_le16(cmd_action);
307 break;
308 case HostCmd_ACT_GEN_GET:
309 cmd_txp_cfg->action = cpu_to_le16(cmd_action);
310 break;
311 }
312
313 return 0;
314}
315
316/*
317 * This function prepares command to set Host Sleep configuration.
318 *
319 * Preparation includes -
320 * - Setting command ID and proper size
321 * - Setting Host Sleep action, conditions, ARP filters
322 * (as required)
323 * - Ensuring correct endian-ness
324 */
325static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
326 struct host_cmd_ds_command *cmd,
327 u16 cmd_action,
328 struct mwifiex_hs_config_param *data_buf)
329{
330 struct mwifiex_adapter *adapter = priv->adapter;
331 struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
332 u16 hs_activate = false;
333
334 if (data_buf == NULL)
335 /* New Activate command */
336 hs_activate = true;
337 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
338
339 if (!hs_activate &&
340 (data_buf->conditions
341 != cpu_to_le32(HOST_SLEEP_CFG_CANCEL))
342 && ((adapter->arp_filter_size > 0)
343 && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
344 dev_dbg(adapter->dev,
345 "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
346 adapter->arp_filter_size);
347 memcpy(((u8 *) hs_cfg) +
348 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
349 adapter->arp_filter, adapter->arp_filter_size);
350 cmd->size = cpu_to_le16(adapter->arp_filter_size +
351 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
352 + S_DS_GEN);
353 } else {
354 cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct
355 host_cmd_ds_802_11_hs_cfg_enh));
356 }
357 if (hs_activate) {
358 hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
359 hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
360 } else {
361 hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
362 hs_cfg->params.hs_config.conditions = data_buf->conditions;
363 hs_cfg->params.hs_config.gpio = data_buf->gpio;
364 hs_cfg->params.hs_config.gap = data_buf->gap;
365 dev_dbg(adapter->dev,
366 "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
367 hs_cfg->params.hs_config.conditions,
368 hs_cfg->params.hs_config.gpio,
369 hs_cfg->params.hs_config.gap);
370 }
371
372 return 0;
373}
374
375/*
376 * This function prepares command to set/get MAC address.
377 *
378 * Preparation includes -
379 * - Setting command ID, action and proper size
380 * - Setting MAC address (for SET only)
381 * - Ensuring correct endian-ness
382 */
383static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
384 struct host_cmd_ds_command *cmd,
385 u16 cmd_action)
386{
387 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
388 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
389 S_DS_GEN);
390 cmd->result = 0;
391
392 cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
393
394 if (cmd_action == HostCmd_ACT_GEN_SET)
395 memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
396 ETH_ALEN);
397 return 0;
398}
399
400/*
401 * This function prepares command to set MAC multicast address.
402 *
403 * Preparation includes -
404 * - Setting command ID, action and proper size
405 * - Setting MAC multicast address
406 * - Ensuring correct endian-ness
407 */
408static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd,
409 u16 cmd_action, void *data_buf)
410{
411 struct mwifiex_multicast_list *mcast_list =
412 (struct mwifiex_multicast_list *) data_buf;
413 struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
414
415 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
416 S_DS_GEN);
417 cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
418
419 mcast_addr->action = cpu_to_le16(cmd_action);
420 mcast_addr->num_of_adrs =
421 cpu_to_le16((u16) mcast_list->num_multicast_addr);
422 memcpy(mcast_addr->mac_list, mcast_list->mac_list,
423 mcast_list->num_multicast_addr * ETH_ALEN);
424
425 return 0;
426}
427
428/*
429 * This function prepares command to deauthenticate.
430 *
431 * Preparation includes -
432 * - Setting command ID and proper size
433 * - Setting AP MAC address and reason code
434 * - Ensuring correct endian-ness
435 */
436static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
437 struct host_cmd_ds_command *cmd,
438 void *data_buf)
439{
440 struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
441
442 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
443 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
444 + S_DS_GEN);
445
446 /* Set AP MAC address */
447 memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN);
448
449 dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
450
451 deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
452
453 return 0;
454}
455
456/*
457 * This function prepares command to stop Ad-Hoc network.
458 *
459 * Preparation includes -
460 * - Setting command ID and proper size
461 * - Ensuring correct endian-ness
462 */
463static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd)
464{
465 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
466 cmd->size = cpu_to_le16(S_DS_GEN);
467 return 0;
468}
469
470/*
471 * This function sets WEP key(s) to key parameter TLV(s).
472 *
473 * Multi-key parameter TLVs are supported, so we can send multiple
474 * WEP keys in a single buffer.
475 */
476static int
477mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
478 struct mwifiex_ie_type_key_param_set *key_param_set,
479 u16 *key_param_len)
480{
481 int cur_key_param_len;
482 u8 i;
483
484 /* Multi-key_param_set TLV is supported */
485 for (i = 0; i < NUM_WEP_KEYS; i++) {
486 if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
487 (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
488 key_param_set->type =
489 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
490/* Key_param_set WEP fixed length */
491#define KEYPARAMSET_WEP_FIXED_LEN 8
492 key_param_set->length = cpu_to_le16((u16)
493 (priv->wep_key[i].
494 key_length +
495 KEYPARAMSET_WEP_FIXED_LEN));
496 key_param_set->key_type_id =
497 cpu_to_le16(KEY_TYPE_ID_WEP);
498 key_param_set->key_info =
499 cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
500 KEY_MCAST);
501 key_param_set->key_len =
502 cpu_to_le16(priv->wep_key[i].key_length);
503 /* Set WEP key index */
504 key_param_set->key[0] = i;
505 /* Set default Tx key flag */
506 if (i ==
507 (priv->
508 wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
509 key_param_set->key[1] = 1;
510 else
511 key_param_set->key[1] = 0;
512 memmove(&key_param_set->key[2],
513 priv->wep_key[i].key_material,
514 priv->wep_key[i].key_length);
515
516 cur_key_param_len = priv->wep_key[i].key_length +
517 KEYPARAMSET_WEP_FIXED_LEN +
518 sizeof(struct mwifiex_ie_types_header);
519 *key_param_len += (u16) cur_key_param_len;
520 key_param_set =
521 (struct mwifiex_ie_type_key_param_set *)
522 ((u8 *)key_param_set +
523 cur_key_param_len);
524 } else if (!priv->wep_key[i].key_length) {
525 continue;
526 } else {
527 dev_err(priv->adapter->dev,
528 "key%d Length = %d is incorrect\n",
529 (i + 1), priv->wep_key[i].key_length);
530 return -1;
531 }
532 }
533
534 return 0;
535}
536
537/*
538 * This function prepares command to set/get/reset network key(s).
539 *
540 * Preparation includes -
541 * - Setting command ID, action and proper size
542 * - Setting WEP keys, WAPI keys or WPA keys along with required
543 * encryption (TKIP, AES) (as required)
544 * - Ensuring correct endian-ness
545 */
546static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
547 struct host_cmd_ds_command *cmd,
548 u16 cmd_action,
549 u32 cmd_oid, void *data_buf)
550{
551 struct host_cmd_ds_802_11_key_material *key_material =
552 &cmd->params.key_material;
553 struct mwifiex_ds_encrypt_key *enc_key =
554 (struct mwifiex_ds_encrypt_key *) data_buf;
555 u16 key_param_len = 0;
556 int ret = 0;
557 const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
558
559 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
560 key_material->action = cpu_to_le16(cmd_action);
561
562 if (cmd_action == HostCmd_ACT_GEN_GET) {
563 cmd->size =
564 cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
565 return ret;
566 }
567
568 if (!enc_key) {
569 memset(&key_material->key_param_set, 0,
570 (NUM_WEP_KEYS *
571 sizeof(struct mwifiex_ie_type_key_param_set)));
572 ret = mwifiex_set_keyparamset_wep(priv,
573 &key_material->key_param_set,
574 &key_param_len);
575 cmd->size = cpu_to_le16(key_param_len +
576 sizeof(key_material->action) + S_DS_GEN);
577 return ret;
578 } else
579 memset(&key_material->key_param_set, 0,
580 sizeof(struct mwifiex_ie_type_key_param_set));
581 if (enc_key->is_wapi_key) {
582 dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
583 key_material->key_param_set.key_type_id =
584 cpu_to_le16(KEY_TYPE_ID_WAPI);
585 if (cmd_oid == KEY_INFO_ENABLED)
586 key_material->key_param_set.key_info =
587 cpu_to_le16(KEY_ENABLED);
588 else
589 key_material->key_param_set.key_info =
590 cpu_to_le16(!KEY_ENABLED);
591
592 key_material->key_param_set.key[0] = enc_key->key_index;
593 if (!priv->sec_info.wapi_key_on)
594 key_material->key_param_set.key[1] = 1;
595 else
596 /* set 0 when re-key */
597 key_material->key_param_set.key[1] = 0;
598
599 if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
600 /* WAPI pairwise key: unicast */
601 key_material->key_param_set.key_info |=
602 cpu_to_le16(KEY_UNICAST);
603 } else { /* WAPI group key: multicast */
604 key_material->key_param_set.key_info |=
605 cpu_to_le16(KEY_MCAST);
606 priv->sec_info.wapi_key_on = true;
607 }
608
609 key_material->key_param_set.type =
610 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
611 key_material->key_param_set.key_len =
612 cpu_to_le16(WAPI_KEY_LEN);
613 memcpy(&key_material->key_param_set.key[2],
614 enc_key->key_material, enc_key->key_len);
615 memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
616 enc_key->wapi_rxpn, WAPI_RXPN_LEN);
617 key_material->key_param_set.length =
618 cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
619
620 key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
621 sizeof(struct mwifiex_ie_types_header);
622 cmd->size = cpu_to_le16(key_param_len +
623 sizeof(key_material->action) + S_DS_GEN);
624 return ret;
625 }
626 if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
627 dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
628 key_material->key_param_set.key_type_id =
629 cpu_to_le16(KEY_TYPE_ID_AES);
630 if (cmd_oid == KEY_INFO_ENABLED)
631 key_material->key_param_set.key_info =
632 cpu_to_le16(KEY_ENABLED);
633 else
634 key_material->key_param_set.key_info =
635 cpu_to_le16(!KEY_ENABLED);
636
637 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
638 /* AES pairwise key: unicast */
639 key_material->key_param_set.key_info |=
640 cpu_to_le16(KEY_UNICAST);
641 else /* AES group key: multicast */
642 key_material->key_param_set.key_info |=
643 cpu_to_le16(KEY_MCAST);
644 } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
645 dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
646 key_material->key_param_set.key_type_id =
647 cpu_to_le16(KEY_TYPE_ID_TKIP);
648 key_material->key_param_set.key_info =
649 cpu_to_le16(KEY_ENABLED);
650
651 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
652 /* TKIP pairwise key: unicast */
653 key_material->key_param_set.key_info |=
654 cpu_to_le16(KEY_UNICAST);
655 else /* TKIP group key: multicast */
656 key_material->key_param_set.key_info |=
657 cpu_to_le16(KEY_MCAST);
658 }
659
660 if (key_material->key_param_set.key_type_id) {
661 key_material->key_param_set.type =
662 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
663 key_material->key_param_set.key_len =
664 cpu_to_le16((u16) enc_key->key_len);
665 memcpy(key_material->key_param_set.key, enc_key->key_material,
666 enc_key->key_len);
667 key_material->key_param_set.length =
668 cpu_to_le16((u16) enc_key->key_len +
669 KEYPARAMSET_FIXED_LEN);
670
671 key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
672 + sizeof(struct mwifiex_ie_types_header);
673
674 cmd->size = cpu_to_le16(key_param_len +
675 sizeof(key_material->action) + S_DS_GEN);
676 }
677
678 return ret;
679}
680
681/*
682 * This function prepares command to set/get 11d domain information.
683 *
684 * Preparation includes -
685 * - Setting command ID, action and proper size
686 * - Setting domain information fields (for SET only)
687 * - Ensuring correct endian-ness
688 */
689static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
690 struct host_cmd_ds_command *cmd,
691 u16 cmd_action)
692{
693 struct mwifiex_adapter *adapter = priv->adapter;
694 struct host_cmd_ds_802_11d_domain_info *domain_info =
695 &cmd->params.domain_info;
696 struct mwifiex_ietypes_domain_param_set *domain =
697 &domain_info->domain;
698 u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
699
700 dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
701
702 cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
703 domain_info->action = cpu_to_le16(cmd_action);
704 if (cmd_action == HostCmd_ACT_GEN_GET) {
705 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
706 return 0;
707 }
708
709 /* Set domain info fields */
710 domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
711 memcpy(domain->country_code, adapter->domain_reg.country_code,
712 sizeof(domain->country_code));
713
714 domain->header.len = cpu_to_le16((no_of_triplet *
715 sizeof(struct ieee80211_country_ie_triplet)) +
716 sizeof(domain->country_code));
717
718 if (no_of_triplet) {
719 memcpy(domain->triplet, adapter->domain_reg.triplet,
720 no_of_triplet *
721 sizeof(struct ieee80211_country_ie_triplet));
722
723 cmd->size = cpu_to_le16(sizeof(domain_info->action) +
724 le16_to_cpu(domain->header.len) +
725 sizeof(struct mwifiex_ie_types_header)
726 + S_DS_GEN);
727 } else {
728 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
729 }
730
731 return 0;
732}
733
734/*
735 * This function prepares command to set/get RF channel.
736 *
737 * Preparation includes -
738 * - Setting command ID, action and proper size
739 * - Setting RF type and current RF channel (for SET only)
740 * - Ensuring correct endian-ness
741 */
742static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv,
743 struct host_cmd_ds_command *cmd,
744 u16 cmd_action, void *data_buf)
745{
746 struct host_cmd_ds_802_11_rf_channel *rf_chan =
747 &cmd->params.rf_channel;
748 uint16_t rf_type = le16_to_cpu(rf_chan->rf_type);
749
750 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
751 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel)
752 + S_DS_GEN);
753
754 if (cmd_action == HostCmd_ACT_GEN_SET) {
755 if ((priv->adapter->adhoc_start_band & BAND_A)
756 || (priv->adapter->adhoc_start_band & BAND_AN))
757 rf_chan->rf_type =
758 cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A);
759
760 rf_type = le16_to_cpu(rf_chan->rf_type);
761 SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset);
762 rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf));
763 }
764 rf_chan->action = cpu_to_le16(cmd_action);
765 return 0;
766}
767
768/*
769 * This function prepares command to set/get IBSS coalescing status.
770 *
771 * Preparation includes -
772 * - Setting command ID, action and proper size
773 * - Setting status to enable or disable (for SET only)
774 * - Ensuring correct endian-ness
775 */
776static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
777 u16 cmd_action, void *data_buf)
778{
779 struct host_cmd_ds_802_11_ibss_status *ibss_coal =
780 &(cmd->params.ibss_coalescing);
781 u16 enable = 0;
782
783 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
784 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
785 S_DS_GEN);
786 cmd->result = 0;
787 ibss_coal->action = cpu_to_le16(cmd_action);
788
789 switch (cmd_action) {
790 case HostCmd_ACT_GEN_SET:
791 if (data_buf != NULL)
792 enable = *(u16 *) data_buf;
793 ibss_coal->enable = cpu_to_le16(enable);
794 break;
795
796 /* In other case.. Nothing to do */
797 case HostCmd_ACT_GEN_GET:
798 default:
799 break;
800 }
801
802 return 0;
803}
804
805/*
806 * This function prepares command to set/get register value.
807 *
808 * Preparation includes -
809 * - Setting command ID, action and proper size
810 * - Setting register offset (for both GET and SET) and
811 * register value (for SET only)
812 * - Ensuring correct endian-ness
813 *
814 * The following type of registers can be accessed with this function -
815 * - MAC register
816 * - BBP register
817 * - RF register
818 * - PMIC register
819 * - CAU register
820 * - EEPROM
821 */
822static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
823 u16 cmd_action, void *data_buf)
824{
825 struct mwifiex_ds_reg_rw *reg_rw;
826
827 reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
828 switch (le16_to_cpu(cmd->command)) {
829 case HostCmd_CMD_MAC_REG_ACCESS:
830 {
831 struct host_cmd_ds_mac_reg_access *mac_reg;
832
833 cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
834 mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
835 params.mac_reg;
836 mac_reg->action = cpu_to_le16(cmd_action);
837 mac_reg->offset =
838 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
839 mac_reg->value = reg_rw->value;
840 break;
841 }
842 case HostCmd_CMD_BBP_REG_ACCESS:
843 {
844 struct host_cmd_ds_bbp_reg_access *bbp_reg;
845
846 cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
847 bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd->
848 params.bbp_reg;
849 bbp_reg->action = cpu_to_le16(cmd_action);
850 bbp_reg->offset =
851 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
852 bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
853 break;
854 }
855 case HostCmd_CMD_RF_REG_ACCESS:
856 {
857 struct host_cmd_ds_rf_reg_access *rf_reg;
858
859 cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
860 rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
861 params.rf_reg;
862 rf_reg->action = cpu_to_le16(cmd_action);
863 rf_reg->offset =
864 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
865 rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
866 break;
867 }
868 case HostCmd_CMD_PMIC_REG_ACCESS:
869 {
870 struct host_cmd_ds_pmic_reg_access *pmic_reg;
871
872 cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
873 pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
874 params.pmic_reg;
875 pmic_reg->action = cpu_to_le16(cmd_action);
876 pmic_reg->offset =
877 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
878 pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
879 break;
880 }
881 case HostCmd_CMD_CAU_REG_ACCESS:
882 {
883 struct host_cmd_ds_rf_reg_access *cau_reg;
884
885 cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
886 cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
887 params.rf_reg;
888 cau_reg->action = cpu_to_le16(cmd_action);
889 cau_reg->offset =
890 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
891 cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
892 break;
893 }
894 case HostCmd_CMD_802_11_EEPROM_ACCESS:
895 {
896 struct mwifiex_ds_read_eeprom *rd_eeprom =
897 (struct mwifiex_ds_read_eeprom *) data_buf;
898 struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
899 (struct host_cmd_ds_802_11_eeprom_access *)
900 &cmd->params.eeprom;
901
902 cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
903 cmd_eeprom->action = cpu_to_le16(cmd_action);
904 cmd_eeprom->offset = rd_eeprom->offset;
905 cmd_eeprom->byte_count = rd_eeprom->byte_count;
906 cmd_eeprom->value = 0;
907 break;
908 }
909 default:
910 return -1;
911 }
912
913 return 0;
914}
915
916/*
917 * This function prepares the commands before sending them to the firmware.
918 *
919 * This is a generic function which calls specific command preparation
920 * routines based upon the command number.
921 */
922int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
923 u16 cmd_action, u32 cmd_oid,
924 void *data_buf, void *cmd_buf)
925{
926 struct host_cmd_ds_command *cmd_ptr =
927 (struct host_cmd_ds_command *) cmd_buf;
928 int ret = 0;
929
930 /* Prepare command */
931 switch (cmd_no) {
932 case HostCmd_CMD_GET_HW_SPEC:
933 ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
934 break;
935 case HostCmd_CMD_MAC_CONTROL:
936 ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
937 data_buf);
938 break;
939 case HostCmd_CMD_802_11_MAC_ADDRESS:
940 ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
941 cmd_action);
942 break;
943 case HostCmd_CMD_MAC_MULTICAST_ADR:
944 ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
945 data_buf);
946 break;
947 case HostCmd_CMD_TX_RATE_CFG:
948 ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
949 data_buf);
950 break;
951 case HostCmd_CMD_TXPWR_CFG:
952 ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
953 data_buf);
954 break;
955 case HostCmd_CMD_802_11_PS_MODE_ENH:
956 ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
957 (uint16_t)cmd_oid, data_buf);
958 break;
959 case HostCmd_CMD_802_11_HS_CFG_ENH:
960 ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
961 (struct mwifiex_hs_config_param *) data_buf);
962 break;
963 case HostCmd_CMD_802_11_SCAN:
964 ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
965 break;
966 case HostCmd_CMD_802_11_BG_SCAN_QUERY:
967 ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
968 break;
969 case HostCmd_CMD_802_11_ASSOCIATE:
970 ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
971 break;
972 case HostCmd_CMD_802_11_DEAUTHENTICATE:
973 ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
974 data_buf);
975 break;
976 case HostCmd_CMD_802_11_AD_HOC_START:
977 ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
978 data_buf);
979 break;
980 case HostCmd_CMD_802_11_GET_LOG:
981 ret = mwifiex_cmd_802_11_get_log(cmd_ptr);
982 break;
983 case HostCmd_CMD_802_11_AD_HOC_JOIN:
984 ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
985 data_buf);
986 break;
987 case HostCmd_CMD_802_11_AD_HOC_STOP:
988 ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr);
989 break;
990 case HostCmd_CMD_RSSI_INFO:
991 ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
992 break;
993 case HostCmd_CMD_802_11_SNMP_MIB:
994 ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
995 cmd_oid, data_buf);
996 break;
997 case HostCmd_CMD_802_11_TX_RATE_QUERY:
998 cmd_ptr->command =
999 cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
1000 cmd_ptr->size =
1001 cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
1002 S_DS_GEN);
1003 priv->tx_rate = 0;
1004 ret = 0;
1005 break;
1006 case HostCmd_CMD_VERSION_EXT:
1007 cmd_ptr->command = cpu_to_le16(cmd_no);
1008 cmd_ptr->params.verext.version_str_sel =
1009 (u8) (*((u32 *) data_buf));
1010 memcpy(&cmd_ptr->params, data_buf,
1011 sizeof(struct host_cmd_ds_version_ext));
1012 cmd_ptr->size =
1013 cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
1014 S_DS_GEN);
1015 ret = 0;
1016 break;
1017 case HostCmd_CMD_802_11_RF_CHANNEL:
1018 ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action,
1019 data_buf);
1020 break;
1021 case HostCmd_CMD_FUNC_INIT:
1022 if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
1023 priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
1024 cmd_ptr->command = cpu_to_le16(cmd_no);
1025 cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1026 break;
1027 case HostCmd_CMD_FUNC_SHUTDOWN:
1028 priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
1029 cmd_ptr->command = cpu_to_le16(cmd_no);
1030 cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1031 break;
1032 case HostCmd_CMD_11N_ADDBA_REQ:
1033 ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf);
1034 break;
1035 case HostCmd_CMD_11N_DELBA:
1036 ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf);
1037 break;
1038 case HostCmd_CMD_11N_ADDBA_RSP:
1039 ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
1040 break;
1041 case HostCmd_CMD_802_11_KEY_MATERIAL:
1042 ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
1043 cmd_action, cmd_oid,
1044 data_buf);
1045 break;
1046 case HostCmd_CMD_802_11D_DOMAIN_INFO:
1047 ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
1048 cmd_action);
1049 break;
1050 case HostCmd_CMD_RECONFIGURE_TX_BUFF:
1051 ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
1052 data_buf);
1053 break;
1054 case HostCmd_CMD_AMSDU_AGGR_CTRL:
1055 ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
1056 data_buf);
1057 break;
1058 case HostCmd_CMD_11N_CFG:
1059 ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action,
1060 data_buf);
1061 break;
1062 case HostCmd_CMD_WMM_GET_STATUS:
1063 dev_dbg(priv->adapter->dev,
1064 "cmd: WMM: WMM_GET_STATUS cmd sent\n");
1065 cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
1066 cmd_ptr->size =
1067 cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
1068 S_DS_GEN);
1069 ret = 0;
1070 break;
1071 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
1072 ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
1073 data_buf);
1074 break;
1075 case HostCmd_CMD_MAC_REG_ACCESS:
1076 case HostCmd_CMD_BBP_REG_ACCESS:
1077 case HostCmd_CMD_RF_REG_ACCESS:
1078 case HostCmd_CMD_PMIC_REG_ACCESS:
1079 case HostCmd_CMD_CAU_REG_ACCESS:
1080 case HostCmd_CMD_802_11_EEPROM_ACCESS:
1081 ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
1082 break;
1083 case HostCmd_CMD_SET_BSS_MODE:
1084 cmd_ptr->command = cpu_to_le16(cmd_no);
1085 if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
1086 cmd_ptr->params.bss_mode.con_type =
1087 CONNECTION_TYPE_ADHOC;
1088 else if (priv->bss_mode == NL80211_IFTYPE_STATION)
1089 cmd_ptr->params.bss_mode.con_type =
1090 CONNECTION_TYPE_INFRA;
1091 cmd_ptr->size = cpu_to_le16(sizeof(struct
1092 host_cmd_ds_set_bss_mode) + S_DS_GEN);
1093 ret = 0;
1094 break;
1095 default:
1096 dev_err(priv->adapter->dev,
1097 "PREP_CMD: unknown cmd- %#x\n", cmd_no);
1098 ret = -1;
1099 break;
1100 }
1101 return ret;
1102}
1103
1104/*
1105 * This function issues commands to initialize firmware.
1106 *
1107 * This is called after firmware download to bring the card to
1108 * working state.
1109 *
1110 * The following commands are issued sequentially -
1111 * - Function init (for first interface only)
1112 * - Read MAC address (for first interface only)
1113 * - Reconfigure Tx buffer size (for first interface only)
1114 * - Enable auto deep sleep (for first interface only)
1115 * - Get Tx rate
1116 * - Get Tx power
1117 * - Set IBSS coalescing status
1118 * - Set AMSDU aggregation control
1119 * - Set 11d control
1120 * - Set MAC control (this must be the last command to initialize firmware)
1121 */
1122int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
1123{
1124 int ret;
1125 u16 enable = true;
1126 struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
1127 struct mwifiex_ds_auto_ds auto_ds;
1128 enum state_11d_t state_11d;
1129
1130 if (first_sta) {
1131
1132 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
1133 HostCmd_ACT_GEN_SET, 0, NULL);
1134 if (ret)
1135 return -1;
1136 /* Read MAC address from HW */
1137 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC,
1138 HostCmd_ACT_GEN_GET, 0, NULL);
1139 if (ret)
1140 return -1;
1141
1142 /* Reconfigure tx buf size */
1143 ret = mwifiex_send_cmd_async(priv,
1144 HostCmd_CMD_RECONFIGURE_TX_BUFF,
1145 HostCmd_ACT_GEN_SET, 0,
1146 &priv->adapter->tx_buf_size);
1147 if (ret)
1148 return -1;
1149
1150 /* Enable IEEE PS by default */
1151 priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1152 ret = mwifiex_send_cmd_async(priv,
1153 HostCmd_CMD_802_11_PS_MODE_ENH,
1154 EN_AUTO_PS, BITMAP_STA_PS, NULL);
1155 if (ret)
1156 return -1;
1157 }
1158
1159 /* get tx rate */
1160 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG,
1161 HostCmd_ACT_GEN_GET, 0, NULL);
1162 if (ret)
1163 return -1;
1164 priv->data_rate = 0;
1165
1166 /* get tx power */
1167 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG,
1168 HostCmd_ACT_GEN_GET, 0, NULL);
1169 if (ret)
1170 return -1;
1171
1172 /* set ibss coalescing_status */
1173 ret = mwifiex_send_cmd_async(priv,
1174 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
1175 HostCmd_ACT_GEN_SET, 0, &enable);
1176 if (ret)
1177 return -1;
1178
1179 memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
1180 amsdu_aggr_ctrl.enable = true;
1181 /* Send request to firmware */
1182 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
1183 HostCmd_ACT_GEN_SET, 0,
1184 (void *) &amsdu_aggr_ctrl);
1185 if (ret)
1186 return -1;
1187 /* MAC Control must be the last command in init_fw */
1188 /* set MAC Control */
1189 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
1190 HostCmd_ACT_GEN_SET, 0,
1191 &priv->curr_pkt_filter);
1192 if (ret)
1193 return -1;
1194
1195 if (first_sta) {
1196 /* Enable auto deep sleep */
1197 auto_ds.auto_ds = DEEP_SLEEP_ON;
1198 auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
1199 ret = mwifiex_send_cmd_async(priv,
1200 HostCmd_CMD_802_11_PS_MODE_ENH,
1201 EN_AUTO_PS, BITMAP_AUTO_DS,
1202 &auto_ds);
1203 if (ret)
1204 return -1;
1205 }
1206
1207 /* Send cmd to FW to enable/disable 11D function */
1208 state_11d = ENABLE_11D;
1209 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
1210 HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
1211 if (ret)
1212 dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
1213
1214 /* set last_init_cmd */
1215 priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB;
1216 ret = -EINPROGRESS;
1217
1218 return ret;
1219}
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
new file mode 100644
index 000000000000..d08f76429a0a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -0,0 +1,972 @@
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{
46 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
47 struct mwifiex_adapter *adapter = priv->adapter;
48 struct host_cmd_ds_802_11_ps_mode_enh *pm;
49 unsigned long flags;
50
51 dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
52 resp->command, resp->result);
53
54 if (adapter->curr_cmd->wait_q_enabled)
55 adapter->cmd_wait_q.status = -1;
56
57 switch (le16_to_cpu(resp->command)) {
58 case HostCmd_CMD_802_11_PS_MODE_ENH:
59 pm = &resp->params.psmode_enh;
60 dev_err(adapter->dev, "PS_MODE_ENH cmd failed: "
61 "result=0x%x action=0x%X\n",
62 resp->result, le16_to_cpu(pm->action));
63 /* We do not re-try enter-ps command in ad-hoc mode. */
64 if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
65 (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
66 priv->bss_mode == NL80211_IFTYPE_ADHOC)
67 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
68
69 break;
70 case HostCmd_CMD_802_11_SCAN:
71 /* Cancel all pending scan command */
72 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
73 list_for_each_entry_safe(cmd_node, tmp_node,
74 &adapter->scan_pending_q, list) {
75 list_del(&cmd_node->list);
76 spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
77 flags);
78 mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
79 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
80 }
81 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
82
83 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
84 adapter->scan_processing = false;
85 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
86 if (priv->report_scan_result)
87 priv->report_scan_result = false;
88 if (priv->scan_pending_on_block) {
89 priv->scan_pending_on_block = false;
90 up(&priv->async_sem);
91 }
92 break;
93
94 case HostCmd_CMD_MAC_CONTROL:
95 break;
96
97 default:
98 break;
99 }
100 /* Handling errors here */
101 mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
102
103 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
104 adapter->curr_cmd = NULL;
105 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
106}
107
108/*
109 * This function handles the command response of get RSSI info.
110 *
111 * Handling includes changing the header fields into CPU format
112 * and saving the following parameters in driver -
113 * - Last data and beacon RSSI value
114 * - Average data and beacon RSSI value
115 * - Last data and beacon NF value
116 * - Average data and beacon NF value
117 *
118 * The parameters are send to the application as well, along with
119 * calculated SNR values.
120 */
121static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
122 struct host_cmd_ds_command *resp,
123 void *data_buf)
124{
125 struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
126 &resp->params.rssi_info_rsp;
127 struct mwifiex_ds_get_signal *signal;
128
129 priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
130 priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
131
132 priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
133 priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
134
135 priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
136 priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
137
138 priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
139 priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
140
141 /* Need to indicate IOCTL complete */
142 if (data_buf) {
143 signal = (struct mwifiex_ds_get_signal *) data_buf;
144 memset(signal, 0, sizeof(struct mwifiex_ds_get_signal));
145
146 signal->selector = ALL_RSSI_INFO_MASK;
147
148 /* RSSI */
149 signal->bcn_rssi_last = priv->bcn_rssi_last;
150 signal->bcn_rssi_avg = priv->bcn_rssi_avg;
151 signal->data_rssi_last = priv->data_rssi_last;
152 signal->data_rssi_avg = priv->data_rssi_avg;
153
154 /* SNR */
155 signal->bcn_snr_last =
156 CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
157 signal->bcn_snr_avg =
158 CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
159 signal->data_snr_last =
160 CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
161 signal->data_snr_avg =
162 CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
163
164 /* NF */
165 signal->bcn_nf_last = priv->bcn_nf_last;
166 signal->bcn_nf_avg = priv->bcn_nf_avg;
167 signal->data_nf_last = priv->data_nf_last;
168 signal->data_nf_avg = priv->data_nf_avg;
169 }
170
171 return 0;
172}
173
174/*
175 * This function handles the command response of set/get SNMP
176 * MIB parameters.
177 *
178 * Handling includes changing the header fields into CPU format
179 * and saving the parameter in driver.
180 *
181 * The following parameters are supported -
182 * - Fragmentation threshold
183 * - RTS threshold
184 * - Short retry limit
185 */
186static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
187 struct host_cmd_ds_command *resp,
188 void *data_buf)
189{
190 struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
191 u16 oid = le16_to_cpu(smib->oid);
192 u16 query_type = le16_to_cpu(smib->query_type);
193 u32 ul_temp;
194
195 dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
196 " query_type = %#x, buf size = %#x\n",
197 oid, query_type, le16_to_cpu(smib->buf_size));
198 if (query_type == HostCmd_ACT_GEN_GET) {
199 ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
200 if (data_buf)
201 *(u32 *)data_buf = ul_temp;
202 switch (oid) {
203 case FRAG_THRESH_I:
204 dev_dbg(priv->adapter->dev,
205 "info: SNMP_RESP: FragThsd =%u\n", ul_temp);
206 break;
207 case RTS_THRESH_I:
208 dev_dbg(priv->adapter->dev,
209 "info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
210 break;
211 case SHORT_RETRY_LIM_I:
212 dev_dbg(priv->adapter->dev,
213 "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
214 break;
215 default:
216 break;
217 }
218 }
219
220 return 0;
221}
222
223/*
224 * This function handles the command response of get log request
225 *
226 * Handling includes changing the header fields into CPU format
227 * and sending the received parameters to application.
228 */
229static int mwifiex_ret_get_log(struct mwifiex_private *priv,
230 struct host_cmd_ds_command *resp,
231 void *data_buf)
232{
233 struct host_cmd_ds_802_11_get_log *get_log =
234 (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
235 struct mwifiex_ds_get_stats *stats;
236
237 if (data_buf) {
238 stats = (struct mwifiex_ds_get_stats *) data_buf;
239 stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
240 stats->failed = le32_to_cpu(get_log->failed);
241 stats->retry = le32_to_cpu(get_log->retry);
242 stats->multi_retry = le32_to_cpu(get_log->multi_retry);
243 stats->frame_dup = le32_to_cpu(get_log->frame_dup);
244 stats->rts_success = le32_to_cpu(get_log->rts_success);
245 stats->rts_failure = le32_to_cpu(get_log->rts_failure);
246 stats->ack_failure = le32_to_cpu(get_log->ack_failure);
247 stats->rx_frag = le32_to_cpu(get_log->rx_frag);
248 stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
249 stats->fcs_error = le32_to_cpu(get_log->fcs_error);
250 stats->tx_frame = le32_to_cpu(get_log->tx_frame);
251 stats->wep_icv_error[0] =
252 le32_to_cpu(get_log->wep_icv_err_cnt[0]);
253 stats->wep_icv_error[1] =
254 le32_to_cpu(get_log->wep_icv_err_cnt[1]);
255 stats->wep_icv_error[2] =
256 le32_to_cpu(get_log->wep_icv_err_cnt[2]);
257 stats->wep_icv_error[3] =
258 le32_to_cpu(get_log->wep_icv_err_cnt[3]);
259 }
260
261 return 0;
262}
263
264/*
265 * This function handles the command response of set/get Tx rate
266 * configurations.
267 *
268 * Handling includes changing the header fields into CPU format
269 * and saving the following parameters in driver -
270 * - DSSS rate bitmap
271 * - OFDM rate bitmap
272 * - HT MCS rate bitmaps
273 *
274 * Based on the new rate bitmaps, the function re-evaluates if
275 * auto data rate has been activated. If not, it sends another
276 * query to the firmware to get the current Tx data rate and updates
277 * the driver value.
278 */
279static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
280 struct host_cmd_ds_command *resp,
281 void *data_buf)
282{
283 struct mwifiex_rate_cfg *ds_rate;
284 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
285 struct mwifiex_rate_scope *rate_scope;
286 struct mwifiex_ie_types_header *head;
287 u16 tlv, tlv_buf_len;
288 u8 *tlv_buf;
289 u32 i;
290 int ret = 0;
291
292 tlv_buf = (u8 *) ((u8 *) rate_cfg) +
293 sizeof(struct host_cmd_ds_tx_rate_cfg);
294 tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
295
296 while (tlv_buf && tlv_buf_len > 0) {
297 tlv = (*tlv_buf);
298 tlv = tlv | (*(tlv_buf + 1) << 8);
299
300 switch (tlv) {
301 case TLV_TYPE_RATE_SCOPE:
302 rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
303 priv->bitmap_rates[0] =
304 le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
305 priv->bitmap_rates[1] =
306 le16_to_cpu(rate_scope->ofdm_rate_bitmap);
307 for (i = 0;
308 i <
309 sizeof(rate_scope->ht_mcs_rate_bitmap) /
310 sizeof(u16); i++)
311 priv->bitmap_rates[2 + i] =
312 le16_to_cpu(rate_scope->
313 ht_mcs_rate_bitmap[i]);
314 break;
315 /* Add RATE_DROP tlv here */
316 }
317
318 head = (struct mwifiex_ie_types_header *) tlv_buf;
319 tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
320 tlv_buf_len -= le16_to_cpu(head->len);
321 }
322
323 priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
324
325 if (priv->is_data_rate_auto)
326 priv->data_rate = 0;
327 else
328 ret = mwifiex_send_cmd_async(priv,
329 HostCmd_CMD_802_11_TX_RATE_QUERY,
330 HostCmd_ACT_GEN_GET, 0, NULL);
331
332 if (data_buf) {
333 ds_rate = (struct mwifiex_rate_cfg *) data_buf;
334 if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) {
335 if (priv->is_data_rate_auto) {
336 ds_rate->is_rate_auto = 1;
337 } else {
338 ds_rate->rate = mwifiex_get_rate_index(priv->
339 bitmap_rates,
340 sizeof(priv->
341 bitmap_rates));
342 if (ds_rate->rate >=
343 MWIFIEX_RATE_BITMAP_OFDM0
344 && ds_rate->rate <=
345 MWIFIEX_RATE_BITMAP_OFDM7)
346 ds_rate->rate -=
347 (MWIFIEX_RATE_BITMAP_OFDM0 -
348 MWIFIEX_RATE_INDEX_OFDM0);
349 if (ds_rate->rate >=
350 MWIFIEX_RATE_BITMAP_MCS0
351 && ds_rate->rate <=
352 MWIFIEX_RATE_BITMAP_MCS127)
353 ds_rate->rate -=
354 (MWIFIEX_RATE_BITMAP_MCS0 -
355 MWIFIEX_RATE_INDEX_MCS0);
356 }
357 }
358 }
359
360 return ret;
361}
362
363/*
364 * This function handles the command response of get Tx power level.
365 *
366 * Handling includes saving the maximum and minimum Tx power levels
367 * in driver, as well as sending the values to user.
368 */
369static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
370{
371 int length, max_power = -1, min_power = -1;
372 struct mwifiex_types_power_group *pg_tlv_hdr;
373 struct mwifiex_power_group *pg;
374
375 if (data_buf) {
376 pg_tlv_hdr =
377 (struct mwifiex_types_power_group *) ((u8 *) data_buf
378 + sizeof(struct host_cmd_ds_txpwr_cfg));
379 pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr +
380 sizeof(struct mwifiex_types_power_group));
381 length = pg_tlv_hdr->length;
382 if (length > 0) {
383 max_power = pg->power_max;
384 min_power = pg->power_min;
385 length -= sizeof(struct mwifiex_power_group);
386 }
387 while (length) {
388 pg++;
389 if (max_power < pg->power_max)
390 max_power = pg->power_max;
391
392 if (min_power > pg->power_min)
393 min_power = pg->power_min;
394
395 length -= sizeof(struct mwifiex_power_group);
396 }
397 if (pg_tlv_hdr->length > 0) {
398 priv->min_tx_power_level = (u8) min_power;
399 priv->max_tx_power_level = (u8) max_power;
400 }
401 } else {
402 return -1;
403 }
404
405 return 0;
406}
407
408/*
409 * This function handles the command response of set/get Tx power
410 * configurations.
411 *
412 * Handling includes changing the header fields into CPU format
413 * and saving the current Tx power level in driver.
414 */
415static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
416 struct host_cmd_ds_command *resp,
417 void *data_buf)
418{
419 struct mwifiex_adapter *adapter = priv->adapter;
420 struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
421 struct mwifiex_types_power_group *pg_tlv_hdr;
422 struct mwifiex_power_group *pg;
423 u16 action = le16_to_cpu(txp_cfg->action);
424
425 switch (action) {
426 case HostCmd_ACT_GEN_GET:
427 {
428 pg_tlv_hdr =
429 (struct mwifiex_types_power_group *) ((u8 *)
430 txp_cfg +
431 sizeof
432 (struct
433 host_cmd_ds_txpwr_cfg));
434 pg = (struct mwifiex_power_group *) ((u8 *)
435 pg_tlv_hdr +
436 sizeof(struct
437 mwifiex_types_power_group));
438 if (adapter->hw_status ==
439 MWIFIEX_HW_STATUS_INITIALIZING)
440 mwifiex_get_power_level(priv, txp_cfg);
441 priv->tx_power_level = (u16) pg->power_min;
442 break;
443 }
444 case HostCmd_ACT_GEN_SET:
445 if (le32_to_cpu(txp_cfg->mode)) {
446 pg_tlv_hdr =
447 (struct mwifiex_types_power_group *) ((u8 *)
448 txp_cfg +
449 sizeof
450 (struct
451 host_cmd_ds_txpwr_cfg));
452 pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr
453 +
454 sizeof(struct
455 mwifiex_types_power_group));
456 if (pg->power_max == pg->power_min)
457 priv->tx_power_level = (u16) pg->power_min;
458 }
459 break;
460 default:
461 dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
462 action);
463 return 0;
464 }
465 dev_dbg(adapter->dev,
466 "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
467 priv->tx_power_level, priv->max_tx_power_level,
468 priv->min_tx_power_level);
469
470 return 0;
471}
472
473/*
474 * This function handles the command response of set/get MAC address.
475 *
476 * Handling includes saving the MAC address in driver.
477 */
478static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
479 struct host_cmd_ds_command *resp)
480{
481 struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
482 &resp->params.mac_addr;
483
484 memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
485
486 dev_dbg(priv->adapter->dev,
487 "info: set mac address: %pM\n", priv->curr_addr);
488
489 return 0;
490}
491
492/*
493 * This function handles the command response of set/get MAC multicast
494 * address.
495 */
496static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
497 struct host_cmd_ds_command *resp)
498{
499 return 0;
500}
501
502/*
503 * This function handles the command response of get Tx rate query.
504 *
505 * Handling includes changing the header fields into CPU format
506 * and saving the Tx rate and HT information parameters in driver.
507 *
508 * Both rate configuration and current data rate can be retrieved
509 * with this request.
510 */
511static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
512 struct host_cmd_ds_command *resp)
513{
514 priv->tx_rate = resp->params.tx_rate.tx_rate;
515 priv->tx_htinfo = resp->params.tx_rate.ht_info;
516 if (!priv->is_data_rate_auto)
517 priv->data_rate =
518 mwifiex_index_to_data_rate(priv->tx_rate,
519 priv->tx_htinfo);
520
521 return 0;
522}
523
524/*
525 * This function handles the command response of a deauthenticate
526 * command.
527 *
528 * If the deauthenticated MAC matches the current BSS MAC, the connection
529 * state is reset.
530 */
531static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
532 struct host_cmd_ds_command *resp)
533{
534 struct mwifiex_adapter *adapter = priv->adapter;
535
536 adapter->dbg.num_cmd_deauth++;
537 if (!memcmp(resp->params.deauth.mac_addr,
538 &priv->curr_bss_params.bss_descriptor.mac_address,
539 sizeof(resp->params.deauth.mac_addr)))
540 mwifiex_reset_connect_state(priv);
541
542 return 0;
543}
544
545/*
546 * This function handles the command response of ad-hoc stop.
547 *
548 * The function resets the connection state in driver.
549 */
550static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
551 struct host_cmd_ds_command *resp)
552{
553 mwifiex_reset_connect_state(priv);
554 return 0;
555}
556
557/*
558 * This function handles the command response of set/get key material.
559 *
560 * Handling includes updating the driver parameters to reflect the
561 * changes.
562 */
563static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
564 struct host_cmd_ds_command *resp)
565{
566 struct host_cmd_ds_802_11_key_material *key =
567 &resp->params.key_material;
568
569 if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
570 if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
571 dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
572 priv->wpa_is_gtk_set = true;
573 priv->scan_block = false;
574 }
575 }
576
577 memset(priv->aes_key.key_param_set.key, 0,
578 sizeof(key->key_param_set.key));
579 priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
580 memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
581 le16_to_cpu(priv->aes_key.key_param_set.key_len));
582
583 return 0;
584}
585
586/*
587 * This function handles the command response of get 11d domain information.
588 */
589static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
590 struct host_cmd_ds_command *resp)
591{
592 struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
593 &resp->params.domain_info_resp;
594 struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
595 u16 action = le16_to_cpu(domain_info->action);
596 u8 no_of_triplet;
597
598 no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
599 IEEE80211_COUNTRY_STRING_LEN) /
600 sizeof(struct ieee80211_country_ie_triplet));
601
602 dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
603 " no_of_triplet=%d\n", no_of_triplet);
604
605 if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
606 dev_warn(priv->adapter->dev,
607 "11D: invalid number of triplets %d "
608 "returned!!\n", no_of_triplet);
609 return -1;
610 }
611
612 switch (action) {
613 case HostCmd_ACT_GEN_SET: /* Proc Set Action */
614 break;
615 case HostCmd_ACT_GEN_GET:
616 break;
617 default:
618 dev_err(priv->adapter->dev,
619 "11D: invalid action:%d\n", domain_info->action);
620 return -1;
621 }
622
623 return 0;
624}
625
626/*
627 * This function handles the command response of get RF channel.
628 *
629 * Handling includes changing the header fields into CPU format
630 * and saving the new channel in driver.
631 */
632static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
633 struct host_cmd_ds_command *resp,
634 void *data_buf)
635{
636 struct host_cmd_ds_802_11_rf_channel *rf_channel =
637 &resp->params.rf_channel;
638 u16 new_channel = le16_to_cpu(rf_channel->current_channel);
639
640 if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
641 dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
642 priv->curr_bss_params.bss_descriptor.channel,
643 new_channel);
644 /* Update the channel again */
645 priv->curr_bss_params.bss_descriptor.channel = new_channel;
646 }
647 if (data_buf)
648 *((u16 *)data_buf) = new_channel;
649
650 return 0;
651}
652
653/*
654 * This function handles the command response of get extended version.
655 *
656 * Handling includes forming the extended version string and sending it
657 * to application.
658 */
659static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
660 struct host_cmd_ds_command *resp,
661 void *data_buf)
662{
663 struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
664 struct host_cmd_ds_version_ext *version_ext;
665
666 if (data_buf) {
667 version_ext = (struct host_cmd_ds_version_ext *)data_buf;
668 version_ext->version_str_sel = ver_ext->version_str_sel;
669 memcpy(version_ext->version_str, ver_ext->version_str,
670 sizeof(char) * 128);
671 memcpy(priv->version_str, ver_ext->version_str, 128);
672 }
673 return 0;
674}
675
676/*
677 * This function handles the command response of register access.
678 *
679 * The register value and offset are returned to the user. For EEPROM
680 * access, the byte count is also returned.
681 */
682static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
683 void *data_buf)
684{
685 struct mwifiex_ds_reg_rw *reg_rw;
686 struct mwifiex_ds_read_eeprom *eeprom;
687
688 if (data_buf) {
689 reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
690 eeprom = (struct mwifiex_ds_read_eeprom *) data_buf;
691 switch (type) {
692 case HostCmd_CMD_MAC_REG_ACCESS:
693 {
694 struct host_cmd_ds_mac_reg_access *reg;
695 reg = (struct host_cmd_ds_mac_reg_access *)
696 &resp->params.mac_reg;
697 reg_rw->offset = cpu_to_le32(
698 (u32) le16_to_cpu(reg->offset));
699 reg_rw->value = reg->value;
700 break;
701 }
702 case HostCmd_CMD_BBP_REG_ACCESS:
703 {
704 struct host_cmd_ds_bbp_reg_access *reg;
705 reg = (struct host_cmd_ds_bbp_reg_access *)
706 &resp->params.bbp_reg;
707 reg_rw->offset = cpu_to_le32(
708 (u32) le16_to_cpu(reg->offset));
709 reg_rw->value = cpu_to_le32((u32) reg->value);
710 break;
711 }
712
713 case HostCmd_CMD_RF_REG_ACCESS:
714 {
715 struct host_cmd_ds_rf_reg_access *reg;
716 reg = (struct host_cmd_ds_rf_reg_access *)
717 &resp->params.rf_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 case HostCmd_CMD_PMIC_REG_ACCESS:
724 {
725 struct host_cmd_ds_pmic_reg_access *reg;
726 reg = (struct host_cmd_ds_pmic_reg_access *)
727 &resp->params.pmic_reg;
728 reg_rw->offset = cpu_to_le32(
729 (u32) le16_to_cpu(reg->offset));
730 reg_rw->value = cpu_to_le32((u32) reg->value);
731 break;
732 }
733 case HostCmd_CMD_CAU_REG_ACCESS:
734 {
735 struct host_cmd_ds_rf_reg_access *reg;
736 reg = (struct host_cmd_ds_rf_reg_access *)
737 &resp->params.rf_reg;
738 reg_rw->offset = cpu_to_le32(
739 (u32) le16_to_cpu(reg->offset));
740 reg_rw->value = cpu_to_le32((u32) reg->value);
741 break;
742 }
743 case HostCmd_CMD_802_11_EEPROM_ACCESS:
744 {
745 struct host_cmd_ds_802_11_eeprom_access
746 *cmd_eeprom =
747 (struct host_cmd_ds_802_11_eeprom_access
748 *) &resp->params.eeprom;
749 pr_debug("info: EEPROM read len=%x\n",
750 cmd_eeprom->byte_count);
751 if (le16_to_cpu(eeprom->byte_count) <
752 le16_to_cpu(
753 cmd_eeprom->byte_count)) {
754 eeprom->byte_count = cpu_to_le16(0);
755 pr_debug("info: EEPROM read "
756 "length is too big\n");
757 return -1;
758 }
759 eeprom->offset = cmd_eeprom->offset;
760 eeprom->byte_count = cmd_eeprom->byte_count;
761 if (le16_to_cpu(eeprom->byte_count) > 0)
762 memcpy(&eeprom->value,
763 &cmd_eeprom->value,
764 le16_to_cpu(eeprom->byte_count));
765
766 break;
767 }
768 default:
769 return -1;
770 }
771 }
772 return 0;
773}
774
775/*
776 * This function handles the command response of get IBSS coalescing status.
777 *
778 * If the received BSSID is different than the current one, the current BSSID,
779 * beacon interval, ATIM window and ERP information are updated, along with
780 * changing the ad-hoc state accordingly.
781 */
782static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
783 struct host_cmd_ds_command *resp)
784{
785 struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
786 &(resp->params.ibss_coalescing);
787 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
788
789 if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
790 return 0;
791
792 dev_dbg(priv->adapter->dev,
793 "info: new BSSID %pM\n", ibss_coal_resp->bssid);
794
795 /* If rsp has NULL BSSID, Just return..... No Action */
796 if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
797 dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
798 return 0;
799 }
800
801 /* If BSSID is diff, modify current BSS parameters */
802 if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
803 ibss_coal_resp->bssid, ETH_ALEN)) {
804 /* BSSID */
805 memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
806 ibss_coal_resp->bssid, ETH_ALEN);
807
808 /* Beacon Interval */
809 priv->curr_bss_params.bss_descriptor.beacon_period
810 = le16_to_cpu(ibss_coal_resp->beacon_interval);
811
812 /* ERP Information */
813 priv->curr_bss_params.bss_descriptor.erp_flags =
814 (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
815
816 priv->adhoc_state = ADHOC_COALESCED;
817 }
818
819 return 0;
820}
821
822/*
823 * This function handles the command responses.
824 *
825 * This is a generic function, which calls command specific
826 * response handlers based on the command ID.
827 */
828int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv,
829 u16 cmdresp_no, void *cmd_buf)
830{
831 int ret = 0;
832 struct mwifiex_adapter *adapter = priv->adapter;
833 struct host_cmd_ds_command *resp =
834 (struct host_cmd_ds_command *) cmd_buf;
835 void *data_buf = adapter->curr_cmd->data_buf;
836
837 /* If the command is not successful, cleanup and return failure */
838 if (resp->result != HostCmd_RESULT_OK) {
839 mwifiex_process_cmdresp_error(priv, resp);
840 return -1;
841 }
842 /* Command successful, handle response */
843 switch (cmdresp_no) {
844 case HostCmd_CMD_GET_HW_SPEC:
845 ret = mwifiex_ret_get_hw_spec(priv, resp);
846 break;
847 case HostCmd_CMD_MAC_CONTROL:
848 break;
849 case HostCmd_CMD_802_11_MAC_ADDRESS:
850 ret = mwifiex_ret_802_11_mac_address(priv, resp);
851 break;
852 case HostCmd_CMD_MAC_MULTICAST_ADR:
853 ret = mwifiex_ret_mac_multicast_adr(priv, resp);
854 break;
855 case HostCmd_CMD_TX_RATE_CFG:
856 ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
857 break;
858 case HostCmd_CMD_802_11_SCAN:
859 ret = mwifiex_ret_802_11_scan(priv, resp);
860 adapter->curr_cmd->wait_q_enabled = false;
861 break;
862 case HostCmd_CMD_802_11_BG_SCAN_QUERY:
863 ret = mwifiex_ret_802_11_scan(priv, resp);
864 dev_dbg(adapter->dev,
865 "info: CMD_RESP: BG_SCAN result is ready!\n");
866 break;
867 case HostCmd_CMD_TXPWR_CFG:
868 ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf);
869 break;
870 case HostCmd_CMD_802_11_PS_MODE_ENH:
871 ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
872 break;
873 case HostCmd_CMD_802_11_HS_CFG_ENH:
874 ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
875 break;
876 case HostCmd_CMD_802_11_ASSOCIATE:
877 ret = mwifiex_ret_802_11_associate(priv, resp);
878 break;
879 case HostCmd_CMD_802_11_DEAUTHENTICATE:
880 ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
881 break;
882 case HostCmd_CMD_802_11_AD_HOC_START:
883 case HostCmd_CMD_802_11_AD_HOC_JOIN:
884 ret = mwifiex_ret_802_11_ad_hoc(priv, resp);
885 break;
886 case HostCmd_CMD_802_11_AD_HOC_STOP:
887 ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
888 break;
889 case HostCmd_CMD_802_11_GET_LOG:
890 ret = mwifiex_ret_get_log(priv, resp, data_buf);
891 break;
892 case HostCmd_CMD_RSSI_INFO:
893 ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
894 break;
895 case HostCmd_CMD_802_11_SNMP_MIB:
896 ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
897 break;
898 case HostCmd_CMD_802_11_TX_RATE_QUERY:
899 ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
900 break;
901 case HostCmd_CMD_802_11_RF_CHANNEL:
902 ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
903 break;
904 case HostCmd_CMD_VERSION_EXT:
905 ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
906 break;
907 case HostCmd_CMD_FUNC_INIT:
908 case HostCmd_CMD_FUNC_SHUTDOWN:
909 break;
910 case HostCmd_CMD_802_11_KEY_MATERIAL:
911 ret = mwifiex_ret_802_11_key_material(priv, resp);
912 break;
913 case HostCmd_CMD_802_11D_DOMAIN_INFO:
914 ret = mwifiex_ret_802_11d_domain_info(priv, resp);
915 break;
916 case HostCmd_CMD_11N_ADDBA_REQ:
917 ret = mwifiex_ret_11n_addba_req(priv, resp);
918 break;
919 case HostCmd_CMD_11N_DELBA:
920 ret = mwifiex_ret_11n_delba(priv, resp);
921 break;
922 case HostCmd_CMD_11N_ADDBA_RSP:
923 ret = mwifiex_ret_11n_addba_resp(priv, resp);
924 break;
925 case HostCmd_CMD_RECONFIGURE_TX_BUFF:
926 adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
927 tx_buf.buff_size);
928 adapter->tx_buf_size = (adapter->tx_buf_size /
929 MWIFIEX_SDIO_BLOCK_SIZE) *
930 MWIFIEX_SDIO_BLOCK_SIZE;
931 adapter->curr_tx_buf_size = adapter->tx_buf_size;
932 dev_dbg(adapter->dev,
933 "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
934 adapter->max_tx_buf_size, adapter->tx_buf_size);
935
936 if (adapter->if_ops.update_mp_end_port)
937 adapter->if_ops.update_mp_end_port(adapter,
938 le16_to_cpu(resp->
939 params.
940 tx_buf.
941 mp_end_port));
942 break;
943 case HostCmd_CMD_AMSDU_AGGR_CTRL:
944 ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf);
945 break;
946 case HostCmd_CMD_WMM_GET_STATUS:
947 ret = mwifiex_ret_wmm_get_status(priv, resp);
948 break;
949 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
950 ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
951 break;
952 case HostCmd_CMD_MAC_REG_ACCESS:
953 case HostCmd_CMD_BBP_REG_ACCESS:
954 case HostCmd_CMD_RF_REG_ACCESS:
955 case HostCmd_CMD_PMIC_REG_ACCESS:
956 case HostCmd_CMD_CAU_REG_ACCESS:
957 case HostCmd_CMD_802_11_EEPROM_ACCESS:
958 ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
959 break;
960 case HostCmd_CMD_SET_BSS_MODE:
961 break;
962 case HostCmd_CMD_11N_CFG:
963 ret = mwifiex_ret_11n_cfg(resp, data_buf);
964 break;
965 default:
966 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
967 resp->command);
968 break;
969 }
970
971 return ret;
972}
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
new file mode 100644
index 000000000000..fc265cab0907
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -0,0 +1,406 @@
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 = 0;
80
81 /* Enable auto data rate */
82 priv->is_data_rate_auto = true;
83 priv->data_rate = 0;
84
85 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
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_send_cmd_async(priv,
275 HostCmd_CMD_802_11_HS_CFG_ENH,
276 0, 0, NULL);
277 break;
278
279 case EVENT_MIC_ERR_UNICAST:
280 dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
281 break;
282
283 case EVENT_MIC_ERR_MULTICAST:
284 dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
285 break;
286 case EVENT_MIB_CHANGED:
287 case EVENT_INIT_DONE:
288 break;
289
290 case EVENT_ADHOC_BCN_LOST:
291 dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
292 priv->adhoc_is_link_sensed = false;
293 mwifiex_clean_txrx(priv);
294 if (!netif_queue_stopped(priv->netdev))
295 netif_stop_queue(priv->netdev);
296 if (netif_carrier_ok(priv->netdev))
297 netif_carrier_off(priv->netdev);
298 break;
299
300 case EVENT_BG_SCAN_REPORT:
301 dev_dbg(adapter->dev, "event: BGS_REPORT\n");
302 /* Clear the previous scan result */
303 memset(adapter->scan_table, 0x00,
304 sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
305 adapter->num_in_scan_table = 0;
306 adapter->bcn_buf_end = adapter->bcn_buf;
307 ret = mwifiex_send_cmd_async(priv,
308 HostCmd_CMD_802_11_BG_SCAN_QUERY,
309 HostCmd_ACT_GEN_GET, 0, NULL);
310 break;
311
312 case EVENT_PORT_RELEASE:
313 dev_dbg(adapter->dev, "event: PORT RELEASE\n");
314 break;
315
316 case EVENT_WMM_STATUS_CHANGE:
317 dev_dbg(adapter->dev, "event: WMM status changed\n");
318 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS,
319 0, 0, NULL);
320 break;
321
322 case EVENT_RSSI_LOW:
323 dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
324 break;
325 case EVENT_SNR_LOW:
326 dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n");
327 break;
328 case EVENT_MAX_FAIL:
329 dev_dbg(adapter->dev, "event: MAX_FAIL\n");
330 break;
331 case EVENT_RSSI_HIGH:
332 dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
333 break;
334 case EVENT_SNR_HIGH:
335 dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n");
336 break;
337 case EVENT_DATA_RSSI_LOW:
338 dev_dbg(adapter->dev, "event: Data RSSI_LOW\n");
339 break;
340 case EVENT_DATA_SNR_LOW:
341 dev_dbg(adapter->dev, "event: Data SNR_LOW\n");
342 break;
343 case EVENT_DATA_RSSI_HIGH:
344 dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n");
345 break;
346 case EVENT_DATA_SNR_HIGH:
347 dev_dbg(adapter->dev, "event: Data SNR_HIGH\n");
348 break;
349 case EVENT_LINK_QUALITY:
350 dev_dbg(adapter->dev, "event: Link Quality\n");
351 break;
352 case EVENT_PRE_BEACON_LOST:
353 dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n");
354 break;
355 case EVENT_IBSS_COALESCED:
356 dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
357 ret = mwifiex_send_cmd_async(priv,
358 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
359 HostCmd_ACT_GEN_GET, 0, NULL);
360 break;
361 case EVENT_ADDBA:
362 dev_dbg(adapter->dev, "event: ADDBA Request\n");
363 mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
364 HostCmd_ACT_GEN_SET, 0,
365 adapter->event_body);
366 break;
367 case EVENT_DELBA:
368 dev_dbg(adapter->dev, "event: DELBA Request\n");
369 mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
370 break;
371 case EVENT_BA_STREAM_TIEMOUT:
372 dev_dbg(adapter->dev, "event: BA Stream timeout\n");
373 mwifiex_11n_ba_stream_timeout(priv,
374 (struct host_cmd_ds_11n_batimeout
375 *)
376 adapter->event_body);
377 break;
378 case EVENT_AMSDU_AGGR_CTRL:
379 dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n",
380 *(u16 *) adapter->event_body);
381 adapter->tx_buf_size =
382 min(adapter->curr_tx_buf_size,
383 le16_to_cpu(*(__le16 *) adapter->event_body));
384 dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
385 adapter->tx_buf_size);
386 break;
387
388 case EVENT_WEP_ICV_ERR:
389 dev_dbg(adapter->dev, "event: WEP ICV error\n");
390 break;
391
392 case EVENT_BW_CHANGE:
393 dev_dbg(adapter->dev, "event: BW Change\n");
394 break;
395
396 case EVENT_HOSTWAKE_STAIE:
397 dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
398 break;
399 default:
400 dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
401 eventcause);
402 break;
403 }
404
405 return ret;
406}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
new file mode 100644
index 000000000000..d05907d05039
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -0,0 +1,1593 @@
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 */
36int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
37 struct net_device *dev)
38{
39 int i = 0;
40 struct netdev_hw_addr *ha;
41
42 netdev_for_each_mc_addr(ha, dev)
43 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
44
45 return i;
46}
47
48/*
49 * Wait queue completion handler.
50 *
51 * This function waits on a cmd wait queue. It also cancels the pending
52 * request after waking up, in case of errors.
53 */
54int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
55{
56 bool cancel_flag = false;
57 int status = adapter->cmd_wait_q.status;
58
59 dev_dbg(adapter->dev, "cmd pending\n");
60 atomic_inc(&adapter->cmd_pending);
61
62 /* Status pending, wake up main process */
63 queue_work(adapter->workqueue, &adapter->main_work);
64
65 /* Wait for completion */
66 wait_event_interruptible(adapter->cmd_wait_q.wait,
67 adapter->cmd_wait_q.condition);
68 if (!adapter->cmd_wait_q.condition)
69 cancel_flag = true;
70
71 if (cancel_flag) {
72 mwifiex_cancel_pending_ioctl(adapter);
73 dev_dbg(adapter->dev, "cmd cancel\n");
74 }
75 adapter->cmd_wait_q.status = 0;
76
77 return status;
78}
79
80/*
81 * This function prepares the correct firmware command and
82 * issues it to set the multicast list.
83 *
84 * This function can be used to enable promiscuous mode, or enable all
85 * multicast packets, or to enable selective multicast.
86 */
87int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
88 struct mwifiex_multicast_list *mcast_list)
89{
90 int ret = 0;
91 u16 old_pkt_filter;
92
93 old_pkt_filter = priv->curr_pkt_filter;
94
95 if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
96 dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
97 priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
98 priv->curr_pkt_filter &=
99 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
100 } else {
101 /* Multicast */
102 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
103 if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) {
104 dev_dbg(priv->adapter->dev,
105 "info: Enabling All Multicast!\n");
106 priv->curr_pkt_filter |=
107 HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
108 } else {
109 priv->curr_pkt_filter &=
110 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
111 if (mcast_list->num_multicast_addr) {
112 dev_dbg(priv->adapter->dev,
113 "info: Set multicast list=%d\n",
114 mcast_list->num_multicast_addr);
115 /* Set multicast addresses to firmware */
116 if (old_pkt_filter == priv->curr_pkt_filter) {
117 /* Send request to firmware */
118 ret = mwifiex_send_cmd_async(priv,
119 HostCmd_CMD_MAC_MULTICAST_ADR,
120 HostCmd_ACT_GEN_SET, 0,
121 mcast_list);
122 } else {
123 /* Send request to firmware */
124 ret = mwifiex_send_cmd_async(priv,
125 HostCmd_CMD_MAC_MULTICAST_ADR,
126 HostCmd_ACT_GEN_SET, 0,
127 mcast_list);
128 }
129 }
130 }
131 }
132 dev_dbg(priv->adapter->dev,
133 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
134 old_pkt_filter, priv->curr_pkt_filter);
135 if (old_pkt_filter != priv->curr_pkt_filter) {
136 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
137 HostCmd_ACT_GEN_SET,
138 0, &priv->curr_pkt_filter);
139 }
140
141 return ret;
142}
143
144/*
145 * In Ad-Hoc mode, the IBSS is created if not found in scan list.
146 * In both Ad-Hoc and infra mode, an deauthentication is performed
147 * first.
148 */
149int mwifiex_bss_start(struct mwifiex_private *priv,
150 struct mwifiex_ssid_bssid *ssid_bssid)
151{
152 int ret;
153 struct mwifiex_adapter *adapter = priv->adapter;
154 s32 i = -1;
155
156 priv->scan_block = false;
157 if (!ssid_bssid)
158 return -1;
159
160 if (priv->bss_mode == NL80211_IFTYPE_STATION) {
161 /* Infra mode */
162 ret = mwifiex_deauthenticate(priv, NULL);
163 if (ret)
164 return ret;
165
166 /* Search for the requested SSID in the scan table */
167 if (ssid_bssid->ssid.ssid_len)
168 i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid,
169 NULL, NL80211_IFTYPE_STATION);
170 else
171 i = mwifiex_find_bssid_in_list(priv,
172 (u8 *) &ssid_bssid->bssid,
173 NL80211_IFTYPE_STATION);
174 if (i < 0)
175 return -1;
176
177 dev_dbg(adapter->dev,
178 "info: SSID found in scan list ... associating...\n");
179
180 /* Clear any past association response stored for
181 * application retrieval */
182 priv->assoc_rsp_size = 0;
183 ret = mwifiex_associate(priv, &adapter->scan_table[i]);
184 if (ret)
185 return ret;
186 } else {
187 /* Adhoc mode */
188 /* If the requested SSID matches current SSID, return */
189 if (ssid_bssid->ssid.ssid_len &&
190 (!mwifiex_ssid_cmp
191 (&priv->curr_bss_params.bss_descriptor.ssid,
192 &ssid_bssid->ssid)))
193 return 0;
194
195 /* Exit Adhoc mode first */
196 dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
197 ret = mwifiex_deauthenticate(priv, NULL);
198 if (ret)
199 return ret;
200
201 priv->adhoc_is_link_sensed = false;
202
203 /* Search for the requested network in the scan table */
204 if (ssid_bssid->ssid.ssid_len)
205 i = mwifiex_find_ssid_in_list(priv,
206 &ssid_bssid->ssid, NULL,
207 NL80211_IFTYPE_ADHOC);
208 else
209 i = mwifiex_find_bssid_in_list(priv,
210 (u8 *)&ssid_bssid->bssid,
211 NL80211_IFTYPE_ADHOC);
212
213 if (i >= 0) {
214 dev_dbg(adapter->dev, "info: network found in scan"
215 " list. Joining...\n");
216 ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]);
217 if (ret)
218 return ret;
219 } else {
220 dev_dbg(adapter->dev, "info: Network not found in "
221 "the list, creating adhoc with ssid = %s\n",
222 ssid_bssid->ssid.ssid);
223 ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid);
224 if (ret)
225 return ret;
226 }
227 }
228
229 return ret;
230}
231
232/*
233 * IOCTL request handler to set host sleep configuration.
234 *
235 * This function prepares the correct firmware command and
236 * issues it.
237 */
238int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
239 int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
240
241{
242 struct mwifiex_adapter *adapter = priv->adapter;
243 int status = 0;
244 u32 prev_cond = 0;
245
246 if (!hs_cfg)
247 return -ENOMEM;
248
249 switch (action) {
250 case HostCmd_ACT_GEN_SET:
251 if (adapter->pps_uapsd_mode) {
252 dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
253 " is blocked in UAPSD/PPS mode\n");
254 status = -1;
255 break;
256 }
257 if (hs_cfg->is_invoke_hostcmd) {
258 if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
259 if (!adapter->is_hs_configured)
260 /* Already cancelled */
261 break;
262 /* Save previous condition */
263 prev_cond = le32_to_cpu(adapter->hs_cfg
264 .conditions);
265 adapter->hs_cfg.conditions =
266 cpu_to_le32(hs_cfg->conditions);
267 } else if (hs_cfg->conditions) {
268 adapter->hs_cfg.conditions =
269 cpu_to_le32(hs_cfg->conditions);
270 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
271 if (hs_cfg->gap)
272 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
273 } else if (adapter->hs_cfg.conditions ==
274 cpu_to_le32(
275 HOST_SLEEP_CFG_CANCEL)) {
276 /* Return failure if no parameters for HS
277 enable */
278 status = -1;
279 break;
280 }
281 if (cmd_type == MWIFIEX_SYNC_CMD)
282 status = mwifiex_send_cmd_sync(priv,
283 HostCmd_CMD_802_11_HS_CFG_ENH,
284 HostCmd_ACT_GEN_SET, 0,
285 &adapter->hs_cfg);
286 else
287 status = mwifiex_send_cmd_async(priv,
288 HostCmd_CMD_802_11_HS_CFG_ENH,
289 HostCmd_ACT_GEN_SET, 0,
290 &adapter->hs_cfg);
291 if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
292 /* Restore previous condition */
293 adapter->hs_cfg.conditions =
294 cpu_to_le32(prev_cond);
295 } else {
296 adapter->hs_cfg.conditions =
297 cpu_to_le32(hs_cfg->conditions);
298 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
299 adapter->hs_cfg.gap = (u8)hs_cfg->gap;
300 }
301 break;
302 case HostCmd_ACT_GEN_GET:
303 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
304 hs_cfg->gpio = adapter->hs_cfg.gpio;
305 hs_cfg->gap = adapter->hs_cfg.gap;
306 break;
307 default:
308 status = -1;
309 break;
310 }
311
312 return status;
313}
314
315/*
316 * Sends IOCTL request to cancel the existing Host Sleep configuration.
317 *
318 * This function allocates the IOCTL request buffer, fills it
319 * with requisite parameters and calls the IOCTL handler.
320 */
321int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
322{
323 struct mwifiex_ds_hs_cfg hscfg;
324
325 hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
326 hscfg.is_invoke_hostcmd = true;
327
328 return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
329 cmd_type, &hscfg);
330}
331EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
332
333/*
334 * Sends IOCTL request to cancel the existing Host Sleep configuration.
335 *
336 * This function allocates the IOCTL request buffer, fills it
337 * with requisite parameters and calls the IOCTL handler.
338 */
339int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
340{
341 struct mwifiex_ds_hs_cfg hscfg;
342
343 if (adapter->hs_activated) {
344 dev_dbg(adapter->dev, "cmd: HS Already actived\n");
345 return true;
346 }
347
348 adapter->hs_activate_wait_q_woken = false;
349
350 memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param));
351 hscfg.is_invoke_hostcmd = true;
352
353 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
354 MWIFIEX_BSS_ROLE_STA),
355 HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
356 &hscfg)) {
357 dev_err(adapter->dev, "IOCTL request HS enable failed\n");
358 return false;
359 }
360
361 wait_event_interruptible(adapter->hs_activate_wait_q,
362 adapter->hs_activate_wait_q_woken);
363
364 return true;
365}
366EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
367
368/*
369 * IOCTL request handler to get BSS information.
370 *
371 * This function collates the information from different driver structures
372 * to send to the user.
373 */
374int mwifiex_get_bss_info(struct mwifiex_private *priv,
375 struct mwifiex_bss_info *info)
376{
377 struct mwifiex_adapter *adapter = priv->adapter;
378 struct mwifiex_bssdescriptor *bss_desc;
379 s32 tbl_idx;
380
381 if (!info)
382 return -1;
383
384 bss_desc = &priv->curr_bss_params.bss_descriptor;
385
386 info->bss_mode = priv->bss_mode;
387
388 memcpy(&info->ssid, &bss_desc->ssid,
389 sizeof(struct mwifiex_802_11_ssid));
390
391 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
392
393 info->bss_chan = bss_desc->channel;
394
395 info->region_code = adapter->region_code;
396
397 /* Scan table index if connected */
398 info->scan_table_idx = 0;
399 if (priv->media_connected) {
400 tbl_idx =
401 mwifiex_find_ssid_in_list(priv, &bss_desc->ssid,
402 bss_desc->mac_address,
403 priv->bss_mode);
404 if (tbl_idx >= 0)
405 info->scan_table_idx = tbl_idx;
406 }
407
408 info->media_connected = priv->media_connected;
409
410 info->max_power_level = priv->max_tx_power_level;
411 info->min_power_level = priv->min_tx_power_level;
412
413 info->adhoc_state = priv->adhoc_state;
414
415 info->bcn_nf_last = priv->bcn_nf_last;
416
417 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
418 info->wep_status = true;
419 else
420 info->wep_status = false;
421
422 info->is_hs_configured = adapter->is_hs_configured;
423 info->is_deep_sleep = adapter->is_deep_sleep;
424
425 return 0;
426}
427
428/*
429 * The function sets band configurations.
430 *
431 * it performs extra checks to make sure the Ad-Hoc
432 * band and channel are compatible. Otherwise it returns an error.
433 *
434 */
435int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv,
436 struct mwifiex_ds_band_cfg *radio_cfg)
437{
438 struct mwifiex_adapter *adapter = priv->adapter;
439 u8 infra_band, adhoc_band;
440 u32 adhoc_channel;
441
442 infra_band = (u8) radio_cfg->config_bands;
443 adhoc_band = (u8) radio_cfg->adhoc_start_band;
444 adhoc_channel = radio_cfg->adhoc_channel;
445
446 /* SET Infra band */
447 if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands)
448 return -1;
449
450 adapter->config_bands = infra_band;
451
452 /* SET Ad-hoc Band */
453 if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands)
454 return -1;
455
456 if (adhoc_band)
457 adapter->adhoc_start_band = adhoc_band;
458 adapter->chan_offset = (u8) radio_cfg->sec_chan_offset;
459 /*
460 * If no adhoc_channel is supplied verify if the existing adhoc
461 * channel compiles with new adhoc_band
462 */
463 if (!adhoc_channel) {
464 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
465 (priv, adapter->adhoc_start_band,
466 priv->adhoc_channel)) {
467 /* Pass back the default channel */
468 radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
469 if ((adapter->adhoc_start_band & BAND_A)
470 || (adapter->adhoc_start_band & BAND_AN))
471 radio_cfg->adhoc_channel =
472 DEFAULT_AD_HOC_CHANNEL_A;
473 }
474 } else { /* Retrurn error if adhoc_band and
475 adhoc_channel combination is invalid */
476 if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
477 (priv, adapter->adhoc_start_band, (u16) adhoc_channel))
478 return -1;
479 priv->adhoc_channel = (u8) adhoc_channel;
480 }
481 if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN))
482 adapter->adhoc_11n_enabled = true;
483 else
484 adapter->adhoc_11n_enabled = false;
485
486 return 0;
487}
488
489/*
490 * IOCTL request handler to set/get active channel.
491 *
492 * This function performs validity checking on channel/frequency
493 * compatibility and returns failure if not valid.
494 */
495int mwifiex_bss_set_channel(struct mwifiex_private *priv,
496 struct mwifiex_chan_freq_power *chan)
497{
498 struct mwifiex_adapter *adapter = priv->adapter;
499 struct mwifiex_chan_freq_power *cfp = NULL;
500
501 if (!chan)
502 return -1;
503
504 if (!chan->channel && !chan->freq)
505 return -1;
506 if (adapter->adhoc_start_band & BAND_AN)
507 adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
508 else if (adapter->adhoc_start_band & BAND_A)
509 adapter->adhoc_start_band = BAND_G | BAND_B;
510 if (chan->channel) {
511 if (chan->channel <= MAX_CHANNEL_BAND_BG)
512 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
513 (priv, 0, (u16) chan->channel);
514 if (!cfp) {
515 cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
516 (priv, BAND_A, (u16) chan->channel);
517 if (cfp) {
518 if (adapter->adhoc_11n_enabled)
519 adapter->adhoc_start_band = BAND_A
520 | BAND_AN;
521 else
522 adapter->adhoc_start_band = BAND_A;
523 }
524 }
525 } else {
526 if (chan->freq <= MAX_FREQUENCY_BAND_BG)
527 cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
528 priv, 0, chan->freq);
529 if (!cfp) {
530 cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211
531 (priv, BAND_A, chan->freq);
532 if (cfp) {
533 if (adapter->adhoc_11n_enabled)
534 adapter->adhoc_start_band = BAND_A
535 | BAND_AN;
536 else
537 adapter->adhoc_start_band = BAND_A;
538 }
539 }
540 }
541 if (!cfp || !cfp->channel) {
542 dev_err(adapter->dev, "invalid channel/freq\n");
543 return -1;
544 }
545 priv->adhoc_channel = (u8) cfp->channel;
546 chan->channel = cfp->channel;
547 chan->freq = cfp->freq;
548
549 return 0;
550}
551
552/*
553 * IOCTL request handler to set/get Ad-Hoc channel.
554 *
555 * This function prepares the correct firmware command and
556 * issues it to set or get the ad-hoc channel.
557 */
558static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
559 u16 action, u16 *channel)
560{
561 if (action == HostCmd_ACT_GEN_GET) {
562 if (!priv->media_connected) {
563 *channel = priv->adhoc_channel;
564 return 0;
565 }
566 } else {
567 priv->adhoc_channel = (u8) *channel;
568 }
569
570 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL,
571 action, 0, channel);
572}
573
574/*
575 * IOCTL request handler to find a particular BSS.
576 *
577 * The BSS can be searched with either a BSSID or a SSID. If none of
578 * these are provided, just the best BSS (best RSSI) is returned.
579 */
580int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv,
581 struct mwifiex_ssid_bssid *ssid_bssid)
582{
583 struct mwifiex_adapter *adapter = priv->adapter;
584 struct mwifiex_bssdescriptor *bss_desc;
585 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
586 u8 mac[ETH_ALEN];
587 int i = 0;
588
589 if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
590 i = mwifiex_find_bssid_in_list(priv,
591 (u8 *) ssid_bssid->bssid,
592 priv->bss_mode);
593 if (i < 0) {
594 memcpy(mac, ssid_bssid->bssid, sizeof(mac));
595 dev_err(adapter->dev, "cannot find bssid %pM\n", mac);
596 return -1;
597 }
598 bss_desc = &adapter->scan_table[i];
599 memcpy(&ssid_bssid->ssid, &bss_desc->ssid,
600 sizeof(struct mwifiex_802_11_ssid));
601 } else if (ssid_bssid->ssid.ssid_len) {
602 i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL,
603 priv->bss_mode);
604 if (i < 0) {
605 dev_err(adapter->dev, "cannot find ssid %s\n",
606 ssid_bssid->ssid.ssid);
607 return -1;
608 }
609 bss_desc = &adapter->scan_table[i];
610 memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN);
611 } else {
612 return mwifiex_find_best_network(priv, ssid_bssid);
613 }
614
615 return 0;
616}
617
618/*
619 * IOCTL request handler to change Ad-Hoc channel.
620 *
621 * This function allocates the IOCTL request buffer, fills it
622 * with requisite parameters and calls the IOCTL handler.
623 *
624 * The function follows the following steps to perform the change -
625 * - Get current IBSS information
626 * - Get current channel
627 * - If no change is required, return
628 * - If not connected, change channel and return
629 * - If connected,
630 * - Disconnect
631 * - Change channel
632 * - Perform specific SSID scan with same SSID
633 * - Start/Join the IBSS
634 */
635int
636mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
637{
638 int ret;
639 struct mwifiex_bss_info bss_info;
640 struct mwifiex_ssid_bssid ssid_bssid;
641 u16 curr_chan = 0;
642
643 memset(&bss_info, 0, sizeof(bss_info));
644
645 /* Get BSS information */
646 if (mwifiex_get_bss_info(priv, &bss_info))
647 return -1;
648
649 /* Get current channel */
650 ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET,
651 &curr_chan);
652
653 if (curr_chan == channel) {
654 ret = 0;
655 goto done;
656 }
657 dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
658 curr_chan, channel);
659
660 if (!bss_info.media_connected) {
661 ret = 0;
662 goto done;
663 }
664
665 /* Do disonnect */
666 memset(&ssid_bssid, 0, ETH_ALEN);
667 ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid);
668
669 ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET,
670 (u16 *) &channel);
671
672 /* Do specific SSID scanning */
673 if (mwifiex_request_scan(priv, &bss_info.ssid)) {
674 ret = -1;
675 goto done;
676 }
677 /* Start/Join Adhoc network */
678 memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
679 memcpy(&ssid_bssid.ssid, &bss_info.ssid,
680 sizeof(struct mwifiex_802_11_ssid));
681
682 ret = mwifiex_bss_start(priv, &ssid_bssid);
683done:
684 return ret;
685}
686
687/*
688 * IOCTL request handler to get rate.
689 *
690 * This function prepares the correct firmware command and
691 * issues it to get the current rate if it is connected,
692 * otherwise, the function returns the lowest supported rate
693 * for the band.
694 */
695static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
696 struct mwifiex_rate_cfg *rate_cfg)
697{
698 struct mwifiex_adapter *adapter = priv->adapter;
699
700 rate_cfg->is_rate_auto = priv->is_data_rate_auto;
701 if (!priv->media_connected) {
702 switch (adapter->config_bands) {
703 case BAND_B:
704 /* Return the lowest supported rate for B band */
705 rate_cfg->rate = supported_rates_b[0] & 0x7f;
706 break;
707 case BAND_G:
708 case BAND_G | BAND_GN:
709 /* Return the lowest supported rate for G band */
710 rate_cfg->rate = supported_rates_g[0] & 0x7f;
711 break;
712 case BAND_B | BAND_G:
713 case BAND_A | BAND_B | BAND_G:
714 case BAND_A | BAND_B:
715 case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
716 case BAND_B | BAND_G | BAND_GN:
717 /* Return the lowest supported rate for BG band */
718 rate_cfg->rate = supported_rates_bg[0] & 0x7f;
719 break;
720 case BAND_A:
721 case BAND_A | BAND_G:
722 case BAND_A | BAND_G | BAND_AN | BAND_GN:
723 case BAND_A | BAND_AN:
724 /* Return the lowest supported rate for A band */
725 rate_cfg->rate = supported_rates_a[0] & 0x7f;
726 break;
727 case BAND_GN:
728 /* Return the lowest supported rate for N band */
729 rate_cfg->rate = supported_rates_n[0] & 0x7f;
730 break;
731 default:
732 dev_warn(adapter->dev, "invalid band %#x\n",
733 adapter->config_bands);
734 break;
735 }
736 } else {
737 return mwifiex_send_cmd_sync(priv,
738 HostCmd_CMD_802_11_TX_RATE_QUERY,
739 HostCmd_ACT_GEN_GET, 0, NULL);
740 }
741
742 return 0;
743}
744
745/*
746 * IOCTL request handler to set rate.
747 *
748 * This function prepares the correct firmware command and
749 * issues it to set the current rate.
750 *
751 * The function also performs validation checking on the supplied value.
752 */
753static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv,
754 struct mwifiex_rate_cfg *rate_cfg)
755{
756 u8 rates[MWIFIEX_SUPPORTED_RATES];
757 u8 *rate;
758 int rate_index, ret;
759 u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
760 u32 i;
761 struct mwifiex_adapter *adapter = priv->adapter;
762
763 if (rate_cfg->is_rate_auto) {
764 memset(bitmap_rates, 0, sizeof(bitmap_rates));
765 /* Support all HR/DSSS rates */
766 bitmap_rates[0] = 0x000F;
767 /* Support all OFDM rates */
768 bitmap_rates[1] = 0x00FF;
769 /* Support all HT-MCSs rate */
770 for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++)
771 bitmap_rates[i + 2] = 0xFFFF;
772 bitmap_rates[9] = 0x3FFF;
773 } else {
774 memset(rates, 0, sizeof(rates));
775 mwifiex_get_active_data_rates(priv, rates);
776 rate = rates;
777 for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) {
778 dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n",
779 rate[i], rate_cfg->rate);
780 if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f))
781 break;
782 }
783 if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) {
784 dev_err(adapter->dev, "fixed data rate %#x is out "
785 "of range\n", rate_cfg->rate);
786 return -1;
787 }
788 memset(bitmap_rates, 0, sizeof(bitmap_rates));
789
790 rate_index = mwifiex_data_rate_to_index(rate_cfg->rate);
791
792 /* Only allow b/g rates to be set */
793 if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 &&
794 rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) {
795 bitmap_rates[0] = 1 << rate_index;
796 } else {
797 rate_index -= 1; /* There is a 0x00 in the table */
798 if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 &&
799 rate_index <= MWIFIEX_RATE_INDEX_OFDM7)
800 bitmap_rates[1] = 1 << (rate_index -
801 MWIFIEX_RATE_INDEX_OFDM0);
802 }
803 }
804
805 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
806 HostCmd_ACT_GEN_SET, 0, bitmap_rates);
807
808 return ret;
809}
810
811/*
812 * IOCTL request handler to set/get rate.
813 *
814 * This function can be used to set/get either the rate value or the
815 * rate index.
816 */
817static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv,
818 struct mwifiex_rate_cfg *rate_cfg)
819{
820 int status;
821
822 if (!rate_cfg)
823 return -1;
824
825 if (rate_cfg->action == HostCmd_ACT_GEN_GET)
826 status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg);
827 else
828 status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg);
829
830 return status;
831}
832
833/*
834 * Sends IOCTL request to get the data rate.
835 *
836 * This function allocates the IOCTL request buffer, fills it
837 * with requisite parameters and calls the IOCTL handler.
838 */
839int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
840 struct mwifiex_rate_cfg *rate)
841{
842 int ret;
843
844 memset(rate, 0, sizeof(struct mwifiex_rate_cfg));
845 rate->action = HostCmd_ACT_GEN_GET;
846 ret = mwifiex_rate_ioctl_cfg(priv, rate);
847
848 if (!ret) {
849 if (rate && rate->is_rate_auto)
850 rate->rate = mwifiex_index_to_data_rate(priv->tx_rate,
851 priv->tx_htinfo);
852 else if (rate)
853 rate->rate = priv->data_rate;
854 } else {
855 ret = -1;
856 }
857
858 return ret;
859}
860
861/*
862 * IOCTL request handler to set tx power configuration.
863 *
864 * This function prepares the correct firmware command and
865 * issues it.
866 *
867 * For non-auto power mode, all the following power groups are set -
868 * - Modulation class HR/DSSS
869 * - Modulation class OFDM
870 * - Modulation class HTBW20
871 * - Modulation class HTBW40
872 */
873int mwifiex_set_tx_power(struct mwifiex_private *priv,
874 struct mwifiex_power_cfg *power_cfg)
875{
876 int ret;
877 struct host_cmd_ds_txpwr_cfg *txp_cfg;
878 struct mwifiex_types_power_group *pg_tlv;
879 struct mwifiex_power_group *pg;
880 u8 *buf;
881 u16 dbm = 0;
882
883 if (!power_cfg->is_power_auto) {
884 dbm = (u16) power_cfg->power_level;
885 if ((dbm < priv->min_tx_power_level) ||
886 (dbm > priv->max_tx_power_level)) {
887 dev_err(priv->adapter->dev, "txpower value %d dBm"
888 " is out of range (%d dBm-%d dBm)\n",
889 dbm, priv->min_tx_power_level,
890 priv->max_tx_power_level);
891 return -1;
892 }
893 }
894 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
895 if (!buf) {
896 dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
897 __func__);
898 return -ENOMEM;
899 }
900
901 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
902 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
903 if (!power_cfg->is_power_auto) {
904 txp_cfg->mode = cpu_to_le32(1);
905 pg_tlv = (struct mwifiex_types_power_group *) (buf +
906 sizeof(struct host_cmd_ds_txpwr_cfg));
907 pg_tlv->type = TLV_TYPE_POWER_GROUP;
908 pg_tlv->length = 4 * sizeof(struct mwifiex_power_group);
909 pg = (struct mwifiex_power_group *) (buf +
910 sizeof(struct host_cmd_ds_txpwr_cfg) +
911 sizeof(struct mwifiex_types_power_group));
912 /* Power group for modulation class HR/DSSS */
913 pg->first_rate_code = 0x00;
914 pg->last_rate_code = 0x03;
915 pg->modulation_class = MOD_CLASS_HR_DSSS;
916 pg->power_step = 0;
917 pg->power_min = (s8) dbm;
918 pg->power_max = (s8) dbm;
919 pg++;
920 /* Power group for modulation class OFDM */
921 pg->first_rate_code = 0x00;
922 pg->last_rate_code = 0x07;
923 pg->modulation_class = MOD_CLASS_OFDM;
924 pg->power_step = 0;
925 pg->power_min = (s8) dbm;
926 pg->power_max = (s8) dbm;
927 pg++;
928 /* Power group for modulation class HTBW20 */
929 pg->first_rate_code = 0x00;
930 pg->last_rate_code = 0x20;
931 pg->modulation_class = MOD_CLASS_HT;
932 pg->power_step = 0;
933 pg->power_min = (s8) dbm;
934 pg->power_max = (s8) dbm;
935 pg->ht_bandwidth = HT_BW_20;
936 pg++;
937 /* Power group for modulation class HTBW40 */
938 pg->first_rate_code = 0x00;
939 pg->last_rate_code = 0x20;
940 pg->modulation_class = MOD_CLASS_HT;
941 pg->power_step = 0;
942 pg->power_min = (s8) dbm;
943 pg->power_max = (s8) dbm;
944 pg->ht_bandwidth = HT_BW_40;
945 }
946 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG,
947 HostCmd_ACT_GEN_SET, 0, buf);
948
949 kfree(buf);
950 return ret;
951}
952
953/*
954 * IOCTL request handler to get power save mode.
955 *
956 * This function prepares the correct firmware command and
957 * issues it.
958 */
959int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
960{
961 int ret;
962 struct mwifiex_adapter *adapter = priv->adapter;
963 u16 sub_cmd;
964
965 if (*ps_mode)
966 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
967 else
968 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
969 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
970 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
971 sub_cmd, BITMAP_STA_PS, NULL);
972 if ((!ret) && (sub_cmd == DIS_AUTO_PS))
973 ret = mwifiex_send_cmd_async(priv,
974 HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
975 0, NULL);
976
977 return ret;
978}
979
980/*
981 * IOCTL request handler to set/reset WPA IE.
982 *
983 * The supplied WPA IE is treated as a opaque buffer. Only the first field
984 * is checked to determine WPA version. If buffer length is zero, the existing
985 * WPA IE is reset.
986 */
987static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
988 u8 *ie_data_ptr, u16 ie_len)
989{
990 if (ie_len) {
991 if (ie_len > sizeof(priv->wpa_ie)) {
992 dev_err(priv->adapter->dev,
993 "failed to copy WPA IE, too big\n");
994 return -1;
995 }
996 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
997 priv->wpa_ie_len = (u8) ie_len;
998 dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
999 priv->wpa_ie_len, priv->wpa_ie[0]);
1000
1001 if (priv->wpa_ie[0] == WLAN_EID_WPA) {
1002 priv->sec_info.wpa_enabled = true;
1003 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
1004 priv->sec_info.wpa2_enabled = true;
1005 } else {
1006 priv->sec_info.wpa_enabled = false;
1007 priv->sec_info.wpa2_enabled = false;
1008 }
1009 } else {
1010 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
1011 priv->wpa_ie_len = 0;
1012 dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
1013 priv->wpa_ie_len, priv->wpa_ie[0]);
1014 priv->sec_info.wpa_enabled = false;
1015 priv->sec_info.wpa2_enabled = false;
1016 }
1017
1018 return 0;
1019}
1020
1021/*
1022 * IOCTL request handler to set/reset WAPI IE.
1023 *
1024 * The supplied WAPI IE is treated as a opaque buffer. Only the first field
1025 * is checked to internally enable WAPI. If buffer length is zero, the existing
1026 * WAPI IE is reset.
1027 */
1028static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
1029 u8 *ie_data_ptr, u16 ie_len)
1030{
1031 if (ie_len) {
1032 if (ie_len > sizeof(priv->wapi_ie)) {
1033 dev_dbg(priv->adapter->dev,
1034 "info: failed to copy WAPI IE, too big\n");
1035 return -1;
1036 }
1037 memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
1038 priv->wapi_ie_len = ie_len;
1039 dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
1040 priv->wapi_ie_len, priv->wapi_ie[0]);
1041
1042 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
1043 priv->sec_info.wapi_enabled = true;
1044 } else {
1045 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
1046 priv->wapi_ie_len = ie_len;
1047 dev_dbg(priv->adapter->dev,
1048 "info: Reset wapi_ie_len=%d IE=%#x\n",
1049 priv->wapi_ie_len, priv->wapi_ie[0]);
1050 priv->sec_info.wapi_enabled = false;
1051 }
1052 return 0;
1053}
1054
1055/*
1056 * IOCTL request handler to set WAPI key.
1057 *
1058 * This function prepares the correct firmware command and
1059 * issues it.
1060 */
1061static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
1062 struct mwifiex_ds_encrypt_key *encrypt_key)
1063{
1064
1065 return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
1066 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1067 encrypt_key);
1068}
1069
1070/*
1071 * IOCTL request handler to set WEP network key.
1072 *
1073 * This function prepares the correct firmware command and
1074 * issues it, after validation checks.
1075 */
1076static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
1077 struct mwifiex_ds_encrypt_key *encrypt_key)
1078{
1079 int ret;
1080 struct mwifiex_wep_key *wep_key;
1081 int index;
1082
1083 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
1084 priv->wep_key_curr_index = 0;
1085 wep_key = &priv->wep_key[priv->wep_key_curr_index];
1086 index = encrypt_key->key_index;
1087 if (encrypt_key->key_disable) {
1088 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
1089 } else if (!encrypt_key->key_len) {
1090 /* Copy the required key as the current key */
1091 wep_key = &priv->wep_key[index];
1092 if (!wep_key->key_length) {
1093 dev_err(priv->adapter->dev,
1094 "key not set, so cannot enable it\n");
1095 return -1;
1096 }
1097 priv->wep_key_curr_index = (u16) index;
1098 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
1099 } else {
1100 wep_key = &priv->wep_key[index];
1101 memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
1102 /* Copy the key in the driver */
1103 memcpy(wep_key->key_material,
1104 encrypt_key->key_material,
1105 encrypt_key->key_len);
1106 wep_key->key_index = index;
1107 wep_key->key_length = encrypt_key->key_len;
1108 priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
1109 }
1110 if (wep_key->key_length) {
1111 /* Send request to firmware */
1112 ret = mwifiex_send_cmd_async(priv,
1113 HostCmd_CMD_802_11_KEY_MATERIAL,
1114 HostCmd_ACT_GEN_SET, 0, NULL);
1115 if (ret)
1116 return ret;
1117 }
1118 if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
1119 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
1120 else
1121 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
1122
1123 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
1124 HostCmd_ACT_GEN_SET, 0,
1125 &priv->curr_pkt_filter);
1126
1127 return ret;
1128}
1129
1130/*
1131 * IOCTL request handler to set WPA key.
1132 *
1133 * This function prepares the correct firmware command and
1134 * issues it, after validation checks.
1135 *
1136 * Current driver only supports key length of up to 32 bytes.
1137 *
1138 * This function can also be used to disable a currently set key.
1139 */
1140static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
1141 struct mwifiex_ds_encrypt_key *encrypt_key)
1142{
1143 int ret;
1144 u8 remove_key = false;
1145 struct host_cmd_ds_802_11_key_material *ibss_key;
1146
1147 /* Current driver only supports key length of up to 32 bytes */
1148 if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
1149 dev_err(priv->adapter->dev, "key length too long\n");
1150 return -1;
1151 }
1152
1153 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
1154 /*
1155 * IBSS/WPA-None uses only one key (Group) for both receiving
1156 * and sending unicast and multicast packets.
1157 */
1158 /* Send the key as PTK to firmware */
1159 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1160 ret = mwifiex_send_cmd_async(priv,
1161 HostCmd_CMD_802_11_KEY_MATERIAL,
1162 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1163 encrypt_key);
1164 if (ret)
1165 return ret;
1166
1167 ibss_key = &priv->aes_key;
1168 memset(ibss_key, 0,
1169 sizeof(struct host_cmd_ds_802_11_key_material));
1170 /* Copy the key in the driver */
1171 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
1172 encrypt_key->key_len);
1173 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
1174 sizeof(ibss_key->key_param_set.key_len));
1175 ibss_key->key_param_set.key_type_id
1176 = cpu_to_le16(KEY_TYPE_ID_TKIP);
1177 ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);
1178
1179 /* Send the key as GTK to firmware */
1180 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
1181 }
1182
1183 if (!encrypt_key->key_index)
1184 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
1185
1186 if (remove_key)
1187 ret = mwifiex_send_cmd_sync(priv,
1188 HostCmd_CMD_802_11_KEY_MATERIAL,
1189 HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED),
1190 encrypt_key);
1191 else
1192 ret = mwifiex_send_cmd_sync(priv,
1193 HostCmd_CMD_802_11_KEY_MATERIAL,
1194 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
1195 encrypt_key);
1196
1197 return ret;
1198}
1199
1200/*
1201 * IOCTL request handler to set/get network keys.
1202 *
1203 * This is a generic key handling function which supports WEP, WPA
1204 * and WAPI.
1205 */
1206static int
1207mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
1208 struct mwifiex_ds_encrypt_key *encrypt_key)
1209{
1210 int status;
1211
1212 if (encrypt_key->is_wapi_key)
1213 status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
1214 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
1215 status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);
1216 else
1217 status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);
1218 return status;
1219}
1220
1221/*
1222 * This function returns the driver version.
1223 */
1224int
1225mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
1226 int max_len)
1227{
1228 union {
1229 u32 l;
1230 u8 c[4];
1231 } ver;
1232 char fw_ver[32];
1233
1234 ver.l = adapter->fw_release_number;
1235 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
1236
1237 snprintf(version, max_len, driver_version, fw_ver);
1238
1239 dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
1240
1241 return 0;
1242}
1243
1244/*
1245 * Sends IOCTL request to get signal information.
1246 *
1247 * This function allocates the IOCTL request buffer, fills it
1248 * with requisite parameters and calls the IOCTL handler.
1249 */
1250int mwifiex_get_signal_info(struct mwifiex_private *priv,
1251 struct mwifiex_ds_get_signal *signal)
1252{
1253 int status;
1254
1255 signal->selector = ALL_RSSI_INFO_MASK;
1256
1257 /* Signal info can be obtained only if connected */
1258 if (!priv->media_connected) {
1259 dev_dbg(priv->adapter->dev,
1260 "info: Can not get signal in disconnected state\n");
1261 return -1;
1262 }
1263
1264 status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
1265 HostCmd_ACT_GEN_GET, 0, signal);
1266
1267 if (!status) {
1268 if (signal->selector & BCN_RSSI_AVG_MASK)
1269 priv->w_stats.qual.level = signal->bcn_rssi_avg;
1270 if (signal->selector & BCN_NF_AVG_MASK)
1271 priv->w_stats.qual.noise = signal->bcn_nf_avg;
1272 }
1273
1274 return status;
1275}
1276
1277/*
1278 * Sends IOCTL request to set encoding parameters.
1279 *
1280 * This function allocates the IOCTL request buffer, fills it
1281 * with requisite parameters and calls the IOCTL handler.
1282 */
1283int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
1284 int key_len, u8 key_index, int disable)
1285{
1286 struct mwifiex_ds_encrypt_key encrypt_key;
1287
1288 memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
1289 encrypt_key.key_len = key_len;
1290 if (!disable) {
1291 encrypt_key.key_index = key_index;
1292 if (key_len)
1293 memcpy(encrypt_key.key_material, key, key_len);
1294 } else {
1295 encrypt_key.key_disable = true;
1296 }
1297
1298 return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
1299}
1300
1301/*
1302 * Sends IOCTL request to get extended version.
1303 *
1304 * This function allocates the IOCTL request buffer, fills it
1305 * with requisite parameters and calls the IOCTL handler.
1306 */
1307int
1308mwifiex_get_ver_ext(struct mwifiex_private *priv)
1309{
1310 struct mwifiex_ver_ext ver_ext;
1311
1312 memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
1313 if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT,
1314 HostCmd_ACT_GEN_GET, 0, &ver_ext))
1315 return -1;
1316
1317 return 0;
1318}
1319
1320/*
1321 * Sends IOCTL request to get statistics information.
1322 *
1323 * This function allocates the IOCTL request buffer, fills it
1324 * with requisite parameters and calls the IOCTL handler.
1325 */
1326int
1327mwifiex_get_stats_info(struct mwifiex_private *priv,
1328 struct mwifiex_ds_get_stats *log)
1329{
1330 int ret;
1331
1332 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
1333 HostCmd_ACT_GEN_GET, 0, log);
1334
1335 if (!ret) {
1336 priv->w_stats.discard.fragment = log->fcs_error;
1337 priv->w_stats.discard.retries = log->retry;
1338 priv->w_stats.discard.misc = log->ack_failure;
1339 }
1340
1341 return ret;
1342}
1343
1344/*
1345 * IOCTL request handler to read/write register.
1346 *
1347 * This function prepares the correct firmware command and
1348 * issues it.
1349 *
1350 * Access to the following registers are supported -
1351 * - MAC
1352 * - BBP
1353 * - RF
1354 * - PMIC
1355 * - CAU
1356 */
1357static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
1358 struct mwifiex_ds_reg_rw *reg_rw,
1359 u16 action)
1360{
1361 u16 cmd_no;
1362
1363 switch (le32_to_cpu(reg_rw->type)) {
1364 case MWIFIEX_REG_MAC:
1365 cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
1366 break;
1367 case MWIFIEX_REG_BBP:
1368 cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
1369 break;
1370 case MWIFIEX_REG_RF:
1371 cmd_no = HostCmd_CMD_RF_REG_ACCESS;
1372 break;
1373 case MWIFIEX_REG_PMIC:
1374 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
1375 break;
1376 case MWIFIEX_REG_CAU:
1377 cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
1378 break;
1379 default:
1380 return -1;
1381 }
1382
1383 return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw);
1384
1385}
1386
1387/*
1388 * Sends IOCTL request to write to a register.
1389 *
1390 * This function allocates the IOCTL request buffer, fills it
1391 * with requisite parameters and calls the IOCTL handler.
1392 */
1393int
1394mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
1395 u32 reg_offset, u32 reg_value)
1396{
1397 struct mwifiex_ds_reg_rw reg_rw;
1398
1399 reg_rw.type = cpu_to_le32(reg_type);
1400 reg_rw.offset = cpu_to_le32(reg_offset);
1401 reg_rw.value = cpu_to_le32(reg_value);
1402
1403 return mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_SET);
1404}
1405
1406/*
1407 * Sends IOCTL request to read from a register.
1408 *
1409 * This function allocates the IOCTL request buffer, fills it
1410 * with requisite parameters and calls the IOCTL handler.
1411 */
1412int
1413mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
1414 u32 reg_offset, u32 *value)
1415{
1416 int ret;
1417 struct mwifiex_ds_reg_rw reg_rw;
1418
1419 reg_rw.type = cpu_to_le32(reg_type);
1420 reg_rw.offset = cpu_to_le32(reg_offset);
1421 ret = mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_GET);
1422
1423 if (ret)
1424 goto done;
1425
1426 *value = le32_to_cpu(reg_rw.value);
1427
1428done:
1429 return ret;
1430}
1431
1432/*
1433 * Sends IOCTL request to read from EEPROM.
1434 *
1435 * This function allocates the IOCTL request buffer, fills it
1436 * with requisite parameters and calls the IOCTL handler.
1437 */
1438int
1439mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
1440 u8 *value)
1441{
1442 int ret;
1443 struct mwifiex_ds_read_eeprom rd_eeprom;
1444
1445 rd_eeprom.offset = cpu_to_le16((u16) offset);
1446 rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
1447
1448 /* Send request to firmware */
1449 ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
1450 HostCmd_ACT_GEN_GET, 0, &rd_eeprom);
1451
1452 if (!ret)
1453 memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
1454 return ret;
1455}
1456
1457/*
1458 * This function sets a generic IE. In addition to generic IE, it can
1459 * also handle WPA, WPA2 and WAPI IEs.
1460 */
1461static int
1462mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
1463 u16 ie_len)
1464{
1465 int ret = 0;
1466 struct ieee_types_vendor_header *pvendor_ie;
1467 const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
1468 const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
1469
1470 /* If the passed length is zero, reset the buffer */
1471 if (!ie_len) {
1472 priv->gen_ie_buf_len = 0;
1473 priv->wps.session_enable = false;
1474
1475 return 0;
1476 } else if (!ie_data_ptr) {
1477 return -1;
1478 }
1479 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
1480 /* Test to see if it is a WPA IE, if not, then it is a gen IE */
1481 if (((pvendor_ie->element_id == WLAN_EID_WPA)
1482 && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
1483 || (pvendor_ie->element_id == WLAN_EID_RSN)) {
1484
1485 /* IE is a WPA/WPA2 IE so call set_wpa function */
1486 ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
1487 priv->wps.session_enable = false;
1488
1489 return ret;
1490 } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
1491 /* IE is a WAPI IE so call set_wapi function */
1492 ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len);
1493
1494 return ret;
1495 }
1496 /*
1497 * Verify that the passed length is not larger than the
1498 * available space remaining in the buffer
1499 */
1500 if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
1501
1502 /* Test to see if it is a WPS IE, if so, enable
1503 * wps session flag
1504 */
1505 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
1506 if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC)
1507 && (!memcmp(pvendor_ie->oui, wps_oui,
1508 sizeof(wps_oui)))) {
1509 priv->wps.session_enable = true;
1510 dev_dbg(priv->adapter->dev,
1511 "info: WPS Session Enabled.\n");
1512 }
1513
1514 /* Append the passed data to the end of the
1515 genIeBuffer */
1516 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
1517 ie_len);
1518 /* Increment the stored buffer length by the
1519 size passed */
1520 priv->gen_ie_buf_len += ie_len;
1521 } else {
1522 /* Passed data does not fit in the remaining
1523 buffer space */
1524 ret = -1;
1525 }
1526
1527 /* Return 0, or -1 for error case */
1528 return ret;
1529}
1530
1531/*
1532 * IOCTL request handler to set/get generic IE.
1533 *
1534 * In addition to various generic IEs, this function can also be
1535 * used to set the ARP filter.
1536 */
1537static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
1538 struct mwifiex_ds_misc_gen_ie *gen_ie,
1539 u16 action)
1540{
1541 struct mwifiex_adapter *adapter = priv->adapter;
1542
1543 switch (gen_ie->type) {
1544 case MWIFIEX_IE_TYPE_GEN_IE:
1545 if (action == HostCmd_ACT_GEN_GET) {
1546 gen_ie->len = priv->wpa_ie_len;
1547 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
1548 } else {
1549 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
1550 (u16) gen_ie->len);
1551 }
1552 break;
1553 case MWIFIEX_IE_TYPE_ARP_FILTER:
1554 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
1555 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
1556 adapter->arp_filter_size = 0;
1557 dev_err(adapter->dev, "invalid ARP filter size\n");
1558 return -1;
1559 } else {
1560 memcpy(adapter->arp_filter, gen_ie->ie_data,
1561 gen_ie->len);
1562 adapter->arp_filter_size = gen_ie->len;
1563 }
1564 break;
1565 default:
1566 dev_err(adapter->dev, "invalid IE type\n");
1567 return -1;
1568 }
1569 return 0;
1570}
1571
1572/*
1573 * Sends IOCTL request to set a generic IE.
1574 *
1575 * This function allocates the IOCTL request buffer, fills it
1576 * with requisite parameters and calls the IOCTL handler.
1577 */
1578int
1579mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
1580{
1581 struct mwifiex_ds_misc_gen_ie gen_ie;
1582
1583 if (ie_len > IW_CUSTOM_MAX)
1584 return -EFAULT;
1585
1586 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
1587 gen_ie.len = ie_len;
1588 memcpy(gen_ie.ie_data, ie, ie_len);
1589 if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))
1590 return -EFAULT;
1591
1592 return 0;
1593}
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
new file mode 100644
index 000000000000..1fdddece7479
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -0,0 +1,200 @@
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;
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;
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
145 if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
146 struct sk_buff_head list;
147 struct sk_buff *rx_skb;
148
149 __skb_queue_head_init(&list);
150
151 skb_pull(skb, local_rx_pd->rx_pkt_offset);
152 skb_trim(skb, local_rx_pd->rx_pkt_length);
153
154 ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
155 priv->wdev->iftype, 0, false);
156
157 while (!skb_queue_empty(&list)) {
158 rx_skb = __skb_dequeue(&list);
159 ret = mwifiex_recv_packet(adapter, rx_skb);
160 if (ret == -1)
161 dev_err(adapter->dev, "Rx of A-MSDU failed");
162 }
163 return 0;
164 }
165
166 /*
167 * If the packet is not an unicast packet then send the packet
168 * directly to os. Don't pass thru rx reordering
169 */
170 if (!IS_11N_ENABLED(priv) ||
171 memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) {
172 mwifiex_process_rx_packet(adapter, skb);
173 return ret;
174 }
175
176 if (mwifiex_queuing_ra_based(priv)) {
177 memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
178 } else {
179 if (rx_pkt_type != PKT_TYPE_BAR)
180 priv->rx_seq[local_rx_pd->priority] =
181 local_rx_pd->seq_num;
182 memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
183 ETH_ALEN);
184 }
185
186 /* Reorder and send to OS */
187 ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
188 local_rx_pd->priority, ta,
189 (u8) local_rx_pd->rx_pkt_type,
190 (void *) skb);
191
192 if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
193 if (priv && (ret == -1))
194 priv->stats.rx_dropped++;
195
196 dev_kfree_skb_any(skb);
197 }
198
199 return ret;
200}
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
new file mode 100644
index 000000000000..fa6221bc9104
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -0,0 +1,198 @@
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 = -1;
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;
117 int ret;
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
184 if (!adapter->sleep_period.period)
185 return ret;
186 if (mwifiex_wmm_lists_empty(adapter))
187 ret = true;
188
189 if (ret && !adapter->cmd_sent && !adapter->curr_cmd
190 && !is_command_pending(adapter)) {
191 adapter->delay_null_pkt = false;
192 ret = true;
193 } else {
194 ret = false;
195 adapter->delay_null_pkt = true;
196 }
197 return ret;
198}
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
new file mode 100644
index 000000000000..aaa50c074196
--- /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 struct mwifiex_private *priv =
40 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
41 struct rxpd *local_rx_pd;
42 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
43
44 local_rx_pd = (struct rxpd *) (skb->data);
45 /* Get the BSS number from rxpd, get corresponding priv */
46 priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
47 BSS_NUM_MASK, local_rx_pd->bss_type);
48 if (!priv)
49 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
50
51 rx_info->bss_index = priv->bss_index;
52
53 return mwifiex_process_sta_rx_packet(adapter, skb);
54}
55EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
56
57/*
58 * This function sends a packet to device.
59 *
60 * It processes the packet to add the TxPD, checks condition and
61 * sends the processed packet to firmware for transmission.
62 *
63 * On successful completion, the function calls the completion callback
64 * and logs the time.
65 */
66int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
67 struct mwifiex_tx_param *tx_param)
68{
69 int ret = -1;
70 struct mwifiex_adapter *adapter = priv->adapter;
71 u8 *head_ptr;
72 struct txpd *local_tx_pd = NULL;
73
74 head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb);
75 if (head_ptr) {
76 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
77 local_tx_pd =
78 (struct txpd *) (head_ptr + INTF_HEADER_LEN);
79
80 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
81 skb->data, skb->len, tx_param);
82 }
83
84 switch (ret) {
85 case -EBUSY:
86 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
87 (adapter->pps_uapsd_mode) &&
88 (adapter->tx_lock_flag)) {
89 priv->adapter->tx_lock_flag = false;
90 local_tx_pd->flags = 0;
91 }
92 dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
93 break;
94 case -1:
95 adapter->data_sent = false;
96 dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
97 ret);
98 adapter->dbg.num_tx_host_to_card_failure++;
99 mwifiex_write_data_complete(adapter, skb, ret);
100 break;
101 case -EINPROGRESS:
102 adapter->data_sent = false;
103 break;
104 case 0:
105 mwifiex_write_data_complete(adapter, skb, ret);
106 break;
107 default:
108 break;
109 }
110
111 return ret;
112}
113
114/*
115 * Packet send completion callback handler.
116 *
117 * It either frees the buffer directly or forwards it to another
118 * completion callback which checks conditions, updates statistics,
119 * wakes up stalled traffic queue if required, and then frees the buffer.
120 */
121int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
122 struct sk_buff *skb, int status)
123{
124 struct mwifiex_private *priv, *tpriv;
125 struct mwifiex_txinfo *tx_info;
126 int i;
127
128 if (!skb)
129 return 0;
130
131 tx_info = MWIFIEX_SKB_TXCB(skb);
132 priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index);
133 if (!priv)
134 goto done;
135
136 priv->netdev->trans_start = jiffies;
137 if (!status) {
138 priv->stats.tx_packets++;
139 priv->stats.tx_bytes += skb->len;
140 } else {
141 priv->stats.tx_errors++;
142 }
143
144 if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
145 goto done;
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;
175 struct mwifiex_private *priv;
176 struct sk_buff *skb_parent;
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..d41291529bc0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -0,0 +1,202 @@
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 * This function sends init/shutdown command
59 * to firmware.
60 */
61int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
62 u32 func_init_shutdown)
63{
64 u16 cmd;
65
66 if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
67 cmd = HostCmd_CMD_FUNC_INIT;
68 } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
69 cmd = HostCmd_CMD_FUNC_SHUTDOWN;
70 } else {
71 dev_err(priv->adapter->dev, "unsupported parameter\n");
72 return -1;
73 }
74
75 return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL);
76}
77EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
78
79/*
80 * IOCTL request handler to set/get debug information.
81 *
82 * This function collates/sets the information from/to different driver
83 * structures.
84 */
85int mwifiex_get_debug_info(struct mwifiex_private *priv,
86 struct mwifiex_debug_info *info)
87{
88 struct mwifiex_adapter *adapter = priv->adapter;
89
90 if (info) {
91 memcpy(info->packets_out,
92 priv->wmm.packets_out,
93 sizeof(priv->wmm.packets_out));
94 info->max_tx_buf_size = (u32) adapter->max_tx_buf_size;
95 info->tx_buf_size = (u32) adapter->tx_buf_size;
96 info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(
97 priv, info->rx_tbl);
98 info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(
99 priv, info->tx_tbl);
100 info->ps_mode = adapter->ps_mode;
101 info->ps_state = adapter->ps_state;
102 info->is_deep_sleep = adapter->is_deep_sleep;
103 info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
104 info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
105 info->is_hs_configured = adapter->is_hs_configured;
106 info->hs_activated = adapter->hs_activated;
107 info->num_cmd_host_to_card_failure
108 = adapter->dbg.num_cmd_host_to_card_failure;
109 info->num_cmd_sleep_cfm_host_to_card_failure
110 = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
111 info->num_tx_host_to_card_failure
112 = adapter->dbg.num_tx_host_to_card_failure;
113 info->num_event_deauth = adapter->dbg.num_event_deauth;
114 info->num_event_disassoc = adapter->dbg.num_event_disassoc;
115 info->num_event_link_lost = adapter->dbg.num_event_link_lost;
116 info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
117 info->num_cmd_assoc_success =
118 adapter->dbg.num_cmd_assoc_success;
119 info->num_cmd_assoc_failure =
120 adapter->dbg.num_cmd_assoc_failure;
121 info->num_tx_timeout = adapter->dbg.num_tx_timeout;
122 info->num_cmd_timeout = adapter->dbg.num_cmd_timeout;
123 info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
124 info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
125 memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
126 sizeof(adapter->dbg.last_cmd_id));
127 memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
128 sizeof(adapter->dbg.last_cmd_act));
129 info->last_cmd_index = adapter->dbg.last_cmd_index;
130 memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
131 sizeof(adapter->dbg.last_cmd_resp_id));
132 info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
133 memcpy(info->last_event, adapter->dbg.last_event,
134 sizeof(adapter->dbg.last_event));
135 info->last_event_index = adapter->dbg.last_event_index;
136 info->data_sent = adapter->data_sent;
137 info->cmd_sent = adapter->cmd_sent;
138 info->cmd_resp_received = adapter->cmd_resp_received;
139 }
140
141 return 0;
142}
143
144/*
145 * This function processes the received packet before sending it to the
146 * kernel.
147 *
148 * It extracts the SKB from the received buffer and sends it to kernel.
149 * In case the received buffer does not contain the data in SKB format,
150 * the function creates a blank SKB, fills it with the data from the
151 * received buffer and then sends this new SKB to the kernel.
152 */
153int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
154{
155 struct mwifiex_rxinfo *rx_info;
156 struct mwifiex_private *priv;
157
158 if (!skb)
159 return -1;
160
161 rx_info = MWIFIEX_SKB_RXCB(skb);
162 priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
163 if (!priv)
164 return -1;
165
166 skb->dev = priv->netdev;
167 skb->protocol = eth_type_trans(skb, priv->netdev);
168 skb->ip_summed = CHECKSUM_NONE;
169 priv->stats.rx_bytes += skb->len;
170 priv->stats.rx_packets++;
171 if (in_interrupt())
172 netif_rx(skb);
173 else
174 netif_rx_ni(skb);
175
176 return 0;
177}
178
179/*
180 * IOCTL completion callback handler.
181 *
182 * This function is called when a pending IOCTL is completed.
183 *
184 * If work queue support is enabled, the function wakes up the
185 * corresponding waiting function. Otherwise, it processes the
186 * IOCTL response and frees the response buffer.
187 */
188int mwifiex_complete_cmd(struct mwifiex_adapter *adapter)
189{
190 atomic_dec(&adapter->cmd_pending);
191 dev_dbg(adapter->dev, "cmd completed: status=%d\n",
192 adapter->cmd_wait_q.status);
193
194 adapter->cmd_wait_q.condition = true;
195
196 if (adapter->cmd_wait_q.status == -ETIMEDOUT)
197 dev_err(adapter->dev, "cmd timeout\n");
198 else
199 wake_up_interruptible(&adapter->cmd_wait_q.wait);
200
201 return 0;
202}
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..91634daec306
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -0,0 +1,1264 @@
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_wmm_desc *wmm)
181{
182 u8 *queue_priority = wmm->queue_priority;
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 for (i = 0; i < MAX_NUM_TID; ++i)
191 tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
192
193 atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID);
194}
195
196/*
197 * This function initializes WMM priority queues.
198 */
199void
200mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
201 struct ieee_types_wmm_parameter *wmm_ie)
202{
203 u16 cw_min, avg_back_off, tmp[4];
204 u32 i, j, num_ac;
205 u8 ac_idx;
206
207 if (!wmm_ie || !priv->wmm_enabled) {
208 /* WMM is not enabled, just set the defaults and return */
209 mwifiex_wmm_default_queue_priorities(priv);
210 return;
211 }
212
213 dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, "
214 "qos_info Parameter Set Count=%d, Reserved=%#x\n",
215 wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
216 IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
217 wmm_ie->reserved);
218
219 for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) {
220 cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap &
221 MWIFIEX_ECW_MIN)) - 1;
222 avg_back_off = (cw_min >> 1) +
223 (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap &
224 MWIFIEX_AIFSN);
225
226 ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac].
227 aci_aifsn_bitmap &
228 MWIFIEX_ACI) >> 5];
229 priv->wmm.queue_priority[ac_idx] = ac_idx;
230 tmp[ac_idx] = avg_back_off;
231
232 dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
233 (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap &
234 MWIFIEX_ECW_MAX) >> 4)) - 1,
235 cw_min, avg_back_off);
236 mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]);
237 }
238
239 /* Bubble sort */
240 for (i = 0; i < num_ac; i++) {
241 for (j = 1; j < num_ac - i; j++) {
242 if (tmp[j - 1] > tmp[j]) {
243 swap(tmp[j - 1], tmp[j]);
244 swap(priv->wmm.queue_priority[j - 1],
245 priv->wmm.queue_priority[j]);
246 } else if (tmp[j - 1] == tmp[j]) {
247 if (priv->wmm.queue_priority[j - 1]
248 < priv->wmm.queue_priority[j])
249 swap(priv->wmm.queue_priority[j - 1],
250 priv->wmm.queue_priority[j]);
251 }
252 }
253 }
254
255 mwifiex_wmm_queue_priorities_tid(&priv->wmm);
256}
257
258/*
259 * This function evaluates whether or not an AC is to be downgraded.
260 *
261 * In case the AC is not enabled, the highest AC is returned that is
262 * enabled and does not require admission control.
263 */
264static enum mwifiex_wmm_ac_e
265mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv,
266 enum mwifiex_wmm_ac_e eval_ac)
267{
268 int down_ac;
269 enum mwifiex_wmm_ac_e ret_ac;
270 struct mwifiex_wmm_ac_status *ac_status;
271
272 ac_status = &priv->wmm.ac_status[eval_ac];
273
274 if (!ac_status->disabled)
275 /* Okay to use this AC, its enabled */
276 return eval_ac;
277
278 /* Setup a default return value of the lowest priority */
279 ret_ac = WMM_AC_BK;
280
281 /*
282 * Find the highest AC that is enabled and does not require
283 * admission control. The spec disallows downgrading to an AC,
284 * which is enabled due to a completed admission control.
285 * Unadmitted traffic is not to be sent on an AC with admitted
286 * traffic.
287 */
288 for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
289 ac_status = &priv->wmm.ac_status[down_ac];
290
291 if (!ac_status->disabled && !ac_status->flow_required)
292 /* AC is enabled and does not require admission
293 control */
294 ret_ac = (enum mwifiex_wmm_ac_e) down_ac;
295 }
296
297 return ret_ac;
298}
299
300/*
301 * This function downgrades WMM priority queue.
302 */
303void
304mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
305{
306 int ac_val;
307
308 dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:"
309 "BK(0), BE(1), VI(2), VO(3)\n");
310
311 if (!priv->wmm_enabled) {
312 /* WMM is not enabled, default priorities */
313 for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++)
314 priv->wmm.ac_down_graded_vals[ac_val] =
315 (enum mwifiex_wmm_ac_e) ac_val;
316 } else {
317 for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
318 priv->wmm.ac_down_graded_vals[ac_val]
319 = mwifiex_wmm_eval_downgrade_ac(priv,
320 (enum mwifiex_wmm_ac_e) ac_val);
321 dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n",
322 ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
323 }
324 }
325}
326
327/*
328 * This function converts the IP TOS field to an WMM AC
329 * Queue assignment.
330 */
331static enum mwifiex_wmm_ac_e
332mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
333{
334 /* Map of TOS UP values to WMM AC */
335 const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
336 WMM_AC_BK,
337 WMM_AC_BK,
338 WMM_AC_BE,
339 WMM_AC_VI,
340 WMM_AC_VI,
341 WMM_AC_VO,
342 WMM_AC_VO
343 };
344
345 if (tos >= ARRAY_SIZE(tos_to_ac))
346 return WMM_AC_BE;
347
348 return tos_to_ac[tos];
349}
350
351/*
352 * This function evaluates a given TID and downgrades it to a lower
353 * TID if the WMM Parameter IE received from the AP indicates that the
354 * AP is disabled (due to call admission control (ACM bit). Mapping
355 * of TID to AC is taken care of internally.
356 */
357static u8
358mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
359{
360 enum mwifiex_wmm_ac_e ac, ac_down;
361 u8 new_tid;
362
363 ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid);
364 ac_down = priv->wmm.ac_down_graded_vals[ac];
365
366 /* Send the index to tid array, picking from the array will be
367 * taken care by dequeuing function
368 */
369 new_tid = ac_to_tid[ac_down][tid % 2];
370
371 return new_tid;
372}
373
374/*
375 * This function initializes the WMM state information and the
376 * WMM data path queues.
377 */
378void
379mwifiex_wmm_init(struct mwifiex_adapter *adapter)
380{
381 int i, j;
382 struct mwifiex_private *priv;
383
384 for (j = 0; j < adapter->priv_num; ++j) {
385 priv = adapter->priv[j];
386 if (!priv)
387 continue;
388
389 for (i = 0; i < MAX_NUM_TID; ++i) {
390 priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
391 priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i];
392 priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
393 priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
394 }
395
396 priv->aggr_prio_tbl[6].amsdu
397 = priv->aggr_prio_tbl[6].ampdu_ap
398 = priv->aggr_prio_tbl[6].ampdu_user
399 = BA_STREAM_NOT_ALLOWED;
400
401 priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
402 = priv->aggr_prio_tbl[7].ampdu_user
403 = BA_STREAM_NOT_ALLOWED;
404
405 priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
406 priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
407 priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
408
409 atomic_set(&priv->wmm.tx_pkts_queued, 0);
410 atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
411 }
412}
413
414/*
415 * This function checks if WMM Tx queue is empty.
416 */
417int
418mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
419{
420 int i;
421 struct mwifiex_private *priv;
422
423 for (i = 0; i < adapter->priv_num; ++i) {
424 priv = adapter->priv[i];
425 if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
426 return false;
427 }
428
429 return true;
430}
431
432/*
433 * This function deletes all packets in an RA list node.
434 *
435 * The packet sent completion callback handler are called with
436 * status failure, after they are dequeued to ensure proper
437 * cleanup. The RA list node itself is freed at the end.
438 */
439static void
440mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,
441 struct mwifiex_ra_list_tbl *ra_list)
442{
443 struct mwifiex_adapter *adapter = priv->adapter;
444 struct sk_buff *skb, *tmp;
445
446 skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
447 mwifiex_write_data_complete(adapter, skb, -1);
448}
449
450/*
451 * This function deletes all packets in an RA list.
452 *
453 * Each nodes in the RA list are freed individually first, and then
454 * the RA list itself is freed.
455 */
456static void
457mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv,
458 struct list_head *ra_list_head)
459{
460 struct mwifiex_ra_list_tbl *ra_list;
461
462 list_for_each_entry(ra_list, ra_list_head, list)
463 mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list);
464}
465
466/*
467 * This function deletes all packets in all RA lists.
468 */
469static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
470{
471 int i;
472
473 for (i = 0; i < MAX_NUM_TID; i++)
474 mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
475 ra_list);
476
477 atomic_set(&priv->wmm.tx_pkts_queued, 0);
478 atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
479}
480
481/*
482 * This function deletes all route addresses from all RA lists.
483 */
484static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
485{
486 struct mwifiex_ra_list_tbl *ra_list, *tmp_node;
487 int i;
488
489 for (i = 0; i < MAX_NUM_TID; ++i) {
490 dev_dbg(priv->adapter->dev,
491 "info: ra_list: freeing buf for tid %d\n", i);
492 list_for_each_entry_safe(ra_list, tmp_node,
493 &priv->wmm.tid_tbl_ptr[i].ra_list, list) {
494 list_del(&ra_list->list);
495 kfree(ra_list);
496 }
497
498 INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list);
499
500 priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
501 }
502}
503
504/*
505 * This function cleans up the Tx and Rx queues.
506 *
507 * Cleanup includes -
508 * - All packets in RA lists
509 * - All entries in Rx reorder table
510 * - All entries in Tx BA stream table
511 * - MPA buffer (if required)
512 * - All RA lists
513 */
514void
515mwifiex_clean_txrx(struct mwifiex_private *priv)
516{
517 unsigned long flags;
518
519 mwifiex_11n_cleanup_reorder_tbl(priv);
520 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
521
522 mwifiex_wmm_cleanup_queues(priv);
523 mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
524
525 if (priv->adapter->if_ops.cleanup_mpa_buf)
526 priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter);
527
528 mwifiex_wmm_delete_all_ralist(priv);
529 memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
530
531 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
532}
533
534/*
535 * This function retrieves a particular RA list node, matching with the
536 * given TID and RA address.
537 */
538static struct mwifiex_ra_list_tbl *
539mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
540 u8 *ra_addr)
541{
542 struct mwifiex_ra_list_tbl *ra_list;
543
544 list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list,
545 list) {
546 if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN))
547 return ra_list;
548 }
549
550 return NULL;
551}
552
553/*
554 * This function retrieves an RA list node for a given TID and
555 * RA address pair.
556 *
557 * If no such node is found, a new node is added first and then
558 * retrieved.
559 */
560static struct mwifiex_ra_list_tbl *
561mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
562{
563 struct mwifiex_ra_list_tbl *ra_list;
564
565 ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
566 if (ra_list)
567 return ra_list;
568 mwifiex_ralist_add(priv, ra_addr);
569
570 return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
571}
572
573/*
574 * This function checks if a particular RA list node exists in a given TID
575 * table index.
576 */
577int
578mwifiex_is_ralist_valid(struct mwifiex_private *priv,
579 struct mwifiex_ra_list_tbl *ra_list, int ptr_index)
580{
581 struct mwifiex_ra_list_tbl *rlist;
582
583 list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list,
584 list) {
585 if (rlist == ra_list)
586 return true;
587 }
588
589 return false;
590}
591
592/*
593 * This function adds a packet to WMM queue.
594 *
595 * In disconnected state the packet is immediately dropped and the
596 * packet send completion callback is called with status failure.
597 *
598 * Otherwise, the correct RA list node is located and the packet
599 * is queued at the list tail.
600 */
601void
602mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
603 struct sk_buff *skb)
604{
605 struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
606 struct mwifiex_private *priv = adapter->priv[tx_info->bss_index];
607 u32 tid;
608 struct mwifiex_ra_list_tbl *ra_list;
609 u8 ra[ETH_ALEN], tid_down;
610 unsigned long flags;
611
612 if (!priv->media_connected) {
613 dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
614 mwifiex_write_data_complete(adapter, skb, -1);
615 return;
616 }
617
618 tid = skb->priority;
619
620 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
621
622 tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
623
624 /* In case of infra as we have already created the list during
625 association we just don't have to call get_queue_raptr, we will
626 have only 1 raptr for a tid in case of infra */
627 if (!mwifiex_queuing_ra_based(priv)) {
628 if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
629 ra_list = list_first_entry(
630 &priv->wmm.tid_tbl_ptr[tid_down].ra_list,
631 struct mwifiex_ra_list_tbl, list);
632 else
633 ra_list = NULL;
634 } else {
635 memcpy(ra, skb->data, ETH_ALEN);
636 ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
637 }
638
639 if (!ra_list) {
640 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
641 mwifiex_write_data_complete(adapter, skb, -1);
642 return;
643 }
644
645 skb_queue_tail(&ra_list->skb_head, skb);
646
647 ra_list->total_pkts_size += skb->len;
648
649 atomic_inc(&priv->wmm.tx_pkts_queued);
650
651 if (atomic_read(&priv->wmm.highest_queued_prio) <
652 tos_to_tid_inv[tid_down])
653 atomic_set(&priv->wmm.highest_queued_prio,
654 tos_to_tid_inv[tid_down]);
655
656 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
657}
658
659/*
660 * This function processes the get WMM status command response from firmware.
661 *
662 * The response may contain multiple TLVs -
663 * - AC Queue status TLVs
664 * - Current WMM Parameter IE TLV
665 * - Admission Control action frame TLVs
666 *
667 * This function parses the TLVs and then calls further specific functions
668 * to process any changes in the queue prioritize or state.
669 */
670int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
671 const struct host_cmd_ds_command *resp)
672{
673 u8 *curr = (u8 *) &resp->params.get_wmm_status;
674 uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
675 int valid = true;
676
677 struct mwifiex_ie_types_data *tlv_hdr;
678 struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus;
679 struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
680 struct mwifiex_wmm_ac_status *ac_status;
681
682 dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
683 resp_len);
684
685 while ((resp_len >= sizeof(tlv_hdr->header)) && valid) {
686 tlv_hdr = (struct mwifiex_ie_types_data *) curr;
687 tlv_len = le16_to_cpu(tlv_hdr->header.len);
688
689 switch (le16_to_cpu(tlv_hdr->header.type)) {
690 case TLV_TYPE_WMMQSTATUS:
691 tlv_wmm_qstatus =
692 (struct mwifiex_ie_types_wmm_queue_status *)
693 tlv_hdr;
694 dev_dbg(priv->adapter->dev,
695 "info: CMD_RESP: WMM_GET_STATUS:"
696 " QSTATUS TLV: %d, %d, %d\n",
697 tlv_wmm_qstatus->queue_index,
698 tlv_wmm_qstatus->flow_required,
699 tlv_wmm_qstatus->disabled);
700
701 ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus->
702 queue_index];
703 ac_status->disabled = tlv_wmm_qstatus->disabled;
704 ac_status->flow_required =
705 tlv_wmm_qstatus->flow_required;
706 ac_status->flow_created = tlv_wmm_qstatus->flow_created;
707 break;
708
709 case WLAN_EID_VENDOR_SPECIFIC:
710 /*
711 * Point the regular IEEE IE 2 bytes into the Marvell IE
712 * and setup the IEEE IE type and length byte fields
713 */
714
715 wmm_param_ie =
716 (struct ieee_types_wmm_parameter *) (curr +
717 2);
718 wmm_param_ie->vend_hdr.len = (u8) tlv_len;
719 wmm_param_ie->vend_hdr.element_id =
720 WLAN_EID_VENDOR_SPECIFIC;
721
722 dev_dbg(priv->adapter->dev,
723 "info: CMD_RESP: WMM_GET_STATUS:"
724 " WMM Parameter Set Count: %d\n",
725 wmm_param_ie->qos_info_bitmap &
726 IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
727
728 memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
729 wmm_ie, wmm_param_ie,
730 wmm_param_ie->vend_hdr.len + 2);
731
732 break;
733
734 default:
735 valid = false;
736 break;
737 }
738
739 curr += (tlv_len + sizeof(tlv_hdr->header));
740 resp_len -= (tlv_len + sizeof(tlv_hdr->header));
741 }
742
743 mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
744 mwifiex_wmm_setup_ac_downgrade(priv);
745
746 return 0;
747}
748
749/*
750 * Callback handler from the command module to allow insertion of a WMM TLV.
751 *
752 * If the BSS we are associating to supports WMM, this function adds the
753 * required WMM Information IE to the association request command buffer in
754 * the form of a Marvell extended IEEE IE.
755 */
756u32
757mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
758 u8 **assoc_buf,
759 struct ieee_types_wmm_parameter *wmm_ie,
760 struct ieee80211_ht_cap *ht_cap)
761{
762 struct mwifiex_ie_types_wmm_param_set *wmm_tlv;
763 u32 ret_len = 0;
764
765 /* Null checks */
766 if (!assoc_buf)
767 return 0;
768 if (!(*assoc_buf))
769 return 0;
770
771 if (!wmm_ie)
772 return 0;
773
774 dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:"
775 "bss->wmmIe=0x%x\n",
776 wmm_ie->vend_hdr.element_id);
777
778 if ((priv->wmm_required
779 || (ht_cap && (priv->adapter->config_bands & BAND_GN
780 || priv->adapter->config_bands & BAND_AN))
781 )
782 && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) {
783 wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf;
784 wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]);
785 wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]);
786 memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2],
787 le16_to_cpu(wmm_tlv->header.len));
788 if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD)
789 memcpy((u8 *) (wmm_tlv->wmm_ie
790 + le16_to_cpu(wmm_tlv->header.len)
791 - sizeof(priv->wmm_qosinfo)),
792 &priv->wmm_qosinfo,
793 sizeof(priv->wmm_qosinfo));
794
795 ret_len = sizeof(wmm_tlv->header)
796 + le16_to_cpu(wmm_tlv->header.len);
797
798 *assoc_buf += ret_len;
799 }
800
801 return ret_len;
802}
803
804/*
805 * This function computes the time delay in the driver queues for a
806 * given packet.
807 *
808 * When the packet is received at the OS/Driver interface, the current
809 * time is set in the packet structure. The difference between the present
810 * time and that received time is computed in this function and limited
811 * based on pre-compiled limits in the driver.
812 */
813u8
814mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
815 const struct sk_buff *skb)
816{
817 u8 ret_val;
818 struct timeval out_tstamp, in_tstamp;
819 u32 queue_delay;
820
821 do_gettimeofday(&out_tstamp);
822 in_tstamp = ktime_to_timeval(skb->tstamp);
823
824 queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000;
825 queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000;
826
827 /*
828 * Queue delay is passed as a uint8 in units of 2ms (ms shifted
829 * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
830 *
831 * Pass max value if queue_delay is beyond the uint8 range
832 */
833 ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
834
835 dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms,"
836 " %d ms sent to FW\n", queue_delay, ret_val);
837
838 return ret_val;
839}
840
841/*
842 * This function retrieves the highest priority RA list table pointer.
843 */
844static struct mwifiex_ra_list_tbl *
845mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
846 struct mwifiex_private **priv, int *tid)
847{
848 struct mwifiex_private *priv_tmp;
849 struct mwifiex_ra_list_tbl *ptr, *head;
850 struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head;
851 struct mwifiex_tid_tbl *tid_ptr;
852 int is_list_empty;
853 unsigned long flags;
854 int i, j;
855
856 for (j = adapter->priv_num - 1; j >= 0; --j) {
857 spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock,
858 flags);
859 is_list_empty = list_empty(&adapter->bss_prio_tbl[j]
860 .bss_prio_head);
861 spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
862 flags);
863 if (is_list_empty)
864 continue;
865
866 if (adapter->bss_prio_tbl[j].bss_prio_cur ==
867 (struct mwifiex_bss_prio_node *)
868 &adapter->bss_prio_tbl[j].bss_prio_head) {
869 bssprio_node =
870 list_first_entry(&adapter->bss_prio_tbl[j]
871 .bss_prio_head,
872 struct mwifiex_bss_prio_node,
873 list);
874 bssprio_head = bssprio_node;
875 } else {
876 bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur;
877 bssprio_head = bssprio_node;
878 }
879
880 do {
881 atomic_t *hqp;
882 spinlock_t *lock;
883
884 priv_tmp = bssprio_node->priv;
885 hqp = &priv_tmp->wmm.highest_queued_prio;
886 lock = &priv_tmp->wmm.ra_list_spinlock;
887
888 for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
889
890 tid_ptr = &(priv_tmp)->wmm.
891 tid_tbl_ptr[tos_to_tid[i]];
892
893 spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
894 flags);
895 is_list_empty =
896 list_empty(&adapter->bss_prio_tbl[j]
897 .bss_prio_head);
898 spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock,
899 flags);
900 if (is_list_empty)
901 continue;
902
903 /*
904 * Always choose the next ra we transmitted
905 * last time, this way we pick the ra's in
906 * round robin fashion.
907 */
908 ptr = list_first_entry(
909 &tid_ptr->ra_list_curr->list,
910 struct mwifiex_ra_list_tbl,
911 list);
912
913 head = ptr;
914 if (ptr == (struct mwifiex_ra_list_tbl *)
915 &tid_ptr->ra_list) {
916 /* Get next ra */
917 ptr = list_first_entry(&ptr->list,
918 struct mwifiex_ra_list_tbl, list);
919 head = ptr;
920 }
921
922 do {
923 is_list_empty =
924 skb_queue_empty(&ptr->skb_head);
925 if (!is_list_empty) {
926 spin_lock_irqsave(lock, flags);
927 if (atomic_read(hqp) > i)
928 atomic_set(hqp, i);
929 spin_unlock_irqrestore(lock,
930 flags);
931 *priv = priv_tmp;
932 *tid = tos_to_tid[i];
933 return ptr;
934 }
935 /* Get next ra */
936 ptr = list_first_entry(&ptr->list,
937 struct mwifiex_ra_list_tbl,
938 list);
939 if (ptr ==
940 (struct mwifiex_ra_list_tbl *)
941 &tid_ptr->ra_list)
942 ptr = list_first_entry(
943 &ptr->list,
944 struct mwifiex_ra_list_tbl,
945 list);
946 } while (ptr != head);
947 }
948
949 /* No packet at any TID for this priv. Mark as such
950 * to skip checking TIDs for this priv (until pkt is
951 * added).
952 */
953 atomic_set(hqp, NO_PKT_PRIO_TID);
954
955 /* Get next bss priority node */
956 bssprio_node = list_first_entry(&bssprio_node->list,
957 struct mwifiex_bss_prio_node,
958 list);
959
960 if (bssprio_node ==
961 (struct mwifiex_bss_prio_node *)
962 &adapter->bss_prio_tbl[j].bss_prio_head)
963 /* Get next bss priority node */
964 bssprio_node = list_first_entry(
965 &bssprio_node->list,
966 struct mwifiex_bss_prio_node,
967 list);
968 } while (bssprio_node != bssprio_head);
969 }
970 return NULL;
971}
972
973/*
974 * This function gets the number of packets in the Tx queue of a
975 * particular RA list.
976 */
977static int
978mwifiex_num_pkts_in_txq(struct mwifiex_private *priv,
979 struct mwifiex_ra_list_tbl *ptr, int max_buf_size)
980{
981 int count = 0, total_size = 0;
982 struct sk_buff *skb, *tmp;
983
984 skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
985 total_size += skb->len;
986 if (total_size < max_buf_size)
987 ++count;
988 else
989 break;
990 }
991
992 return count;
993}
994
995/*
996 * This function sends a single packet to firmware for transmission.
997 */
998static void
999mwifiex_send_single_packet(struct mwifiex_private *priv,
1000 struct mwifiex_ra_list_tbl *ptr, int ptr_index,
1001 unsigned long ra_list_flags)
1002 __releases(&priv->wmm.ra_list_spinlock)
1003{
1004 struct sk_buff *skb, *skb_next;
1005 struct mwifiex_tx_param tx_param;
1006 struct mwifiex_adapter *adapter = priv->adapter;
1007 struct mwifiex_txinfo *tx_info;
1008
1009 if (skb_queue_empty(&ptr->skb_head)) {
1010 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1011 ra_list_flags);
1012 dev_dbg(adapter->dev, "data: nothing to send\n");
1013 return;
1014 }
1015
1016 skb = skb_dequeue(&ptr->skb_head);
1017
1018 tx_info = MWIFIEX_SKB_TXCB(skb);
1019 dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
1020
1021 ptr->total_pkts_size -= skb->len;
1022
1023 if (!skb_queue_empty(&ptr->skb_head))
1024 skb_next = skb_peek(&ptr->skb_head);
1025 else
1026 skb_next = NULL;
1027
1028 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
1029
1030 tx_param.next_pkt_len = ((skb_next) ? skb_next->len +
1031 sizeof(struct txpd) : 0);
1032
1033 if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) {
1034 /* Queue the packet back at the head */
1035 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1036
1037 if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1038 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1039 ra_list_flags);
1040 mwifiex_write_data_complete(adapter, skb, -1);
1041 return;
1042 }
1043
1044 skb_queue_tail(&ptr->skb_head, skb);
1045
1046 ptr->total_pkts_size += skb->len;
1047 tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
1048 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1049 ra_list_flags);
1050 } else {
1051 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1052 if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1053 priv->wmm.packets_out[ptr_index]++;
1054 priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
1055 }
1056 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
1057 list_first_entry(
1058 &adapter->bss_prio_tbl[priv->bss_priority]
1059 .bss_prio_cur->list,
1060 struct mwifiex_bss_prio_node,
1061 list);
1062 atomic_dec(&priv->wmm.tx_pkts_queued);
1063 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1064 ra_list_flags);
1065 }
1066}
1067
1068/*
1069 * This function checks if the first packet in the given RA list
1070 * is already processed or not.
1071 */
1072static int
1073mwifiex_is_ptr_processed(struct mwifiex_private *priv,
1074 struct mwifiex_ra_list_tbl *ptr)
1075{
1076 struct sk_buff *skb;
1077 struct mwifiex_txinfo *tx_info;
1078
1079 if (skb_queue_empty(&ptr->skb_head))
1080 return false;
1081
1082 skb = skb_peek(&ptr->skb_head);
1083
1084 tx_info = MWIFIEX_SKB_TXCB(skb);
1085 if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT)
1086 return true;
1087
1088 return false;
1089}
1090
1091/*
1092 * This function sends a single processed packet to firmware for
1093 * transmission.
1094 */
1095static void
1096mwifiex_send_processed_packet(struct mwifiex_private *priv,
1097 struct mwifiex_ra_list_tbl *ptr, int ptr_index,
1098 unsigned long ra_list_flags)
1099 __releases(&priv->wmm.ra_list_spinlock)
1100{
1101 struct mwifiex_tx_param tx_param;
1102 struct mwifiex_adapter *adapter = priv->adapter;
1103 int ret = -1;
1104 struct sk_buff *skb, *skb_next;
1105 struct mwifiex_txinfo *tx_info;
1106
1107 if (skb_queue_empty(&ptr->skb_head)) {
1108 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1109 ra_list_flags);
1110 return;
1111 }
1112
1113 skb = skb_dequeue(&ptr->skb_head);
1114
1115 if (!skb_queue_empty(&ptr->skb_head))
1116 skb_next = skb_peek(&ptr->skb_head);
1117 else
1118 skb_next = NULL;
1119
1120 tx_info = MWIFIEX_SKB_TXCB(skb);
1121
1122 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
1123 tx_param.next_pkt_len =
1124 ((skb_next) ? skb_next->len +
1125 sizeof(struct txpd) : 0);
1126 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
1127 skb->data, skb->len, &tx_param);
1128 switch (ret) {
1129 case -EBUSY:
1130 dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
1131 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1132
1133 if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1134 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1135 ra_list_flags);
1136 mwifiex_write_data_complete(adapter, skb, -1);
1137 return;
1138 }
1139
1140 skb_queue_tail(&ptr->skb_head, skb);
1141
1142 tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
1143 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1144 ra_list_flags);
1145 break;
1146 case -1:
1147 adapter->data_sent = false;
1148 dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
1149 adapter->dbg.num_tx_host_to_card_failure++;
1150 mwifiex_write_data_complete(adapter, skb, ret);
1151 break;
1152 case -EINPROGRESS:
1153 adapter->data_sent = false;
1154 default:
1155 break;
1156 }
1157 if (ret != -EBUSY) {
1158 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
1159 if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1160 priv->wmm.packets_out[ptr_index]++;
1161 priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
1162 }
1163 adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
1164 list_first_entry(
1165 &adapter->bss_prio_tbl[priv->bss_priority]
1166 .bss_prio_cur->list,
1167 struct mwifiex_bss_prio_node,
1168 list);
1169 atomic_dec(&priv->wmm.tx_pkts_queued);
1170 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1171 ra_list_flags);
1172 }
1173}
1174
1175/*
1176 * This function dequeues a packet from the highest priority list
1177 * and transmits it.
1178 */
1179static int
1180mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
1181{
1182 struct mwifiex_ra_list_tbl *ptr;
1183 struct mwifiex_private *priv = NULL;
1184 int ptr_index = 0;
1185 u8 ra[ETH_ALEN];
1186 int tid_del = 0, tid = 0;
1187 unsigned long flags;
1188
1189 ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index);
1190 if (!ptr)
1191 return -1;
1192
1193 tid = mwifiex_get_tid(ptr);
1194
1195 dev_dbg(adapter->dev, "data: tid=%d\n", tid);
1196
1197 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
1198 if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
1199 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
1200 return -1;
1201 }
1202
1203 if (mwifiex_is_ptr_processed(priv, ptr)) {
1204 mwifiex_send_processed_packet(priv, ptr, ptr_index, flags);
1205 /* ra_list_spinlock has been freed in
1206 mwifiex_send_processed_packet() */
1207 return 0;
1208 }
1209
1210 if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid)
1211 || ((priv->sec_info.wpa_enabled
1212 || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set)
1213 ) {
1214 mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
1215 /* ra_list_spinlock has been freed in
1216 mwifiex_send_single_packet() */
1217 } else {
1218 if (mwifiex_is_ampdu_allowed(priv, tid)) {
1219 if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
1220 mwifiex_11n_create_tx_ba_stream_tbl(priv,
1221 ptr->ra, tid,
1222 BA_STREAM_SETUP_INPROGRESS);
1223 mwifiex_send_addba(priv, tid, ptr->ra);
1224 } else if (mwifiex_find_stream_to_delete
1225 (priv, tid, &tid_del, ra)) {
1226 mwifiex_11n_create_tx_ba_stream_tbl(priv,
1227 ptr->ra, tid,
1228 BA_STREAM_SETUP_INPROGRESS);
1229 mwifiex_send_delba(priv, tid_del, ra, 1);
1230 }
1231 }
1232/* Minimum number of AMSDU */
1233#define MIN_NUM_AMSDU 2
1234 if (mwifiex_is_amsdu_allowed(priv, tid) &&
1235 (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >=
1236 MIN_NUM_AMSDU))
1237 mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
1238 ptr_index, flags);
1239 /* ra_list_spinlock has been freed in
1240 mwifiex_11n_aggregate_pkt() */
1241 else
1242 mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
1243 /* ra_list_spinlock has been freed in
1244 mwifiex_send_single_packet() */
1245 }
1246 return 0;
1247}
1248
1249/*
1250 * This function transmits the highest priority packet awaiting in the
1251 * WMM Queues.
1252 */
1253void
1254mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
1255{
1256 do {
1257 /* Check if busy */
1258 if (adapter->data_sent || adapter->tx_lock_flag)
1259 break;
1260
1261 if (mwifiex_dequeue_tx_packet(adapter))
1262 break;
1263 } while (!mwifiex_wmm_lists_empty(adapter));
1264}
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h
new file mode 100644
index 000000000000..fcea1f68792f
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -0,0 +1,110 @@
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_ra_list_tbl *ptr)
39{
40 struct sk_buff *skb;
41
42 if (skb_queue_empty(&ptr->skb_head))
43 return 0;
44
45 skb = skb_peek(&ptr->skb_head);
46
47 return skb->priority;
48}
49
50/*
51 * This function gets the length of a list.
52 */
53static inline int
54mwifiex_wmm_list_len(struct list_head *head)
55{
56 struct list_head *pos;
57 int count = 0;
58
59 list_for_each(pos, head)
60 ++count;
61
62 return count;
63}
64
65/*
66 * This function checks if a RA list is empty or not.
67 */
68static inline u8
69mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead)
70{
71 struct mwifiex_ra_list_tbl *ra_list;
72 int is_list_empty;
73
74 list_for_each_entry(ra_list, ra_list_hhead, list) {
75 is_list_empty = skb_queue_empty(&ra_list->skb_head);
76 if (!is_list_empty)
77 return false;
78 }
79
80 return true;
81}
82
83void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
84 struct sk_buff *skb);
85void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra);
86
87int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter);
88void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter);
89int mwifiex_is_ralist_valid(struct mwifiex_private *priv,
90 struct mwifiex_ra_list_tbl *ra_list, int tid);
91
92u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
93 const struct sk_buff *skb);
94void mwifiex_wmm_init(struct mwifiex_adapter *adapter);
95
96extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
97 u8 **assoc_buf,
98 struct ieee_types_wmm_parameter
99 *wmmie,
100 struct ieee80211_ht_cap
101 *htcap);
102
103void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
104 struct ieee_types_wmm_parameter
105 *wmm_ie);
106void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
107extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
108 const struct host_cmd_ds_command *resp);
109
110#endif /* !_MWIFIEX_WMM_H_ */