blob: 648df690f5d1ef89ce677bc464c3094ec5a8ed1d [file] [log] [blame]
Bing Zhao5e6e3a92011-03-21 18:00:50 -07001/*
2 * Marvell Wireless LAN device driver: station command response handling
3 *
4 * Copyright (C) 2011, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "util.h"
23#include "fw.h"
24#include "main.h"
25#include "wmm.h"
26#include "11n.h"
27
28
29/*
30 * This function handles the command response error case.
31 *
32 * For scan response error, the function cancels all the pending
33 * scan commands and generates an event to inform the applications
34 * of the scan completion.
35 *
36 * For Power Save command failure, we do not retry enter PS
37 * command in case of Ad-hoc mode.
38 *
39 * For all other response errors, the current command buffer is freed
40 * and returned to the free command queue.
41 */
42static void
43mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
44 struct host_cmd_ds_command *resp,
45 struct mwifiex_wait_queue *wq_buf)
46{
47 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
48 struct mwifiex_adapter *adapter = priv->adapter;
Marc Yang2b06bdb2011-03-30 18:12:44 -070049 struct host_cmd_ds_802_11_ps_mode_enh *pm;
Bing Zhao5e6e3a92011-03-21 18:00:50 -070050 unsigned long flags;
51
52 dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
53 resp->command, resp->result);
54 if (wq_buf)
55 wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP;
56
57 switch (le16_to_cpu(resp->command)) {
58 case HostCmd_CMD_802_11_PS_MODE_ENH:
Marc Yang2b06bdb2011-03-30 18:12:44 -070059 pm = &resp->params.psmode_enh;
60 dev_err(adapter->dev, "PS_MODE_ENH cmd failed: "
61 "result=0x%x action=0x%X\n",
Bing Zhao5e6e3a92011-03-21 18:00:50 -070062 resp->result, le16_to_cpu(pm->action));
Marc Yang2b06bdb2011-03-30 18:12:44 -070063 /* 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
Bing Zhao5e6e3a92011-03-21 18:00:50 -070069 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 return;
108}
109
110/*
111 * This function handles the command response of get RSSI info.
112 *
113 * Handling includes changing the header fields into CPU format
114 * and saving the following parameters in driver -
115 * - Last data and beacon RSSI value
116 * - Average data and beacon RSSI value
117 * - Last data and beacon NF value
118 * - Average data and beacon NF value
119 *
120 * The parameters are send to the application as well, along with
121 * calculated SNR values.
122 */
123static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
124 struct host_cmd_ds_command *resp,
125 void *data_buf)
126{
127 struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
128 &resp->params.rssi_info_rsp;
129 struct mwifiex_ds_get_signal *signal = NULL;
130
131 priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
132 priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
133
134 priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
135 priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
136
137 priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
138 priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
139
140 priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
141 priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
142
143 /* Need to indicate IOCTL complete */
144 if (data_buf) {
145 signal = (struct mwifiex_ds_get_signal *) data_buf;
146 memset(signal, 0, sizeof(struct mwifiex_ds_get_signal));
147
148 signal->selector = ALL_RSSI_INFO_MASK;
149
150 /* RSSI */
151 signal->bcn_rssi_last = priv->bcn_rssi_last;
152 signal->bcn_rssi_avg = priv->bcn_rssi_avg;
153 signal->data_rssi_last = priv->data_rssi_last;
154 signal->data_rssi_avg = priv->data_rssi_avg;
155
156 /* SNR */
157 signal->bcn_snr_last =
158 CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
159 signal->bcn_snr_avg =
160 CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
161 signal->data_snr_last =
162 CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
163 signal->data_snr_avg =
164 CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
165
166 /* NF */
167 signal->bcn_nf_last = priv->bcn_nf_last;
168 signal->bcn_nf_avg = priv->bcn_nf_avg;
169 signal->data_nf_last = priv->data_nf_last;
170 signal->data_nf_avg = priv->data_nf_avg;
171 }
172
173 return 0;
174}
175
176/*
177 * This function handles the command response of set/get SNMP
178 * MIB parameters.
179 *
180 * Handling includes changing the header fields into CPU format
181 * and saving the parameter in driver.
182 *
183 * The following parameters are supported -
184 * - Fragmentation threshold
185 * - RTS threshold
186 * - Short retry limit
187 */
188static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
189 struct host_cmd_ds_command *resp,
190 void *data_buf)
191{
192 struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
193 u16 oid = le16_to_cpu(smib->oid);
194 u16 query_type = le16_to_cpu(smib->query_type);
195 u32 ul_temp;
196
197 dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
198 " query_type = %#x, buf size = %#x\n",
199 oid, query_type, le16_to_cpu(smib->buf_size));
200 if (query_type == HostCmd_ACT_GEN_GET) {
201 ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
202 if (data_buf)
203 *(u32 *)data_buf = ul_temp;
204 switch (oid) {
205 case FRAG_THRESH_I:
206 dev_dbg(priv->adapter->dev,
207 "info: SNMP_RESP: FragThsd =%u\n", ul_temp);
208 break;
209 case RTS_THRESH_I:
210 dev_dbg(priv->adapter->dev,
211 "info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
212 break;
213 case SHORT_RETRY_LIM_I:
214 dev_dbg(priv->adapter->dev,
215 "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
216 break;
217 default:
218 break;
219 }
220 }
221
222 return 0;
223}
224
225/*
226 * This function handles the command response of get log request
227 *
228 * Handling includes changing the header fields into CPU format
229 * and sending the received parameters to application.
230 */
231static int mwifiex_ret_get_log(struct mwifiex_private *priv,
232 struct host_cmd_ds_command *resp,
233 void *data_buf)
234{
235 struct host_cmd_ds_802_11_get_log *get_log =
236 (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
237 struct mwifiex_ds_get_stats *stats = NULL;
238
239 if (data_buf) {
240 stats = (struct mwifiex_ds_get_stats *) data_buf;
241 stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
242 stats->failed = le32_to_cpu(get_log->failed);
243 stats->retry = le32_to_cpu(get_log->retry);
244 stats->multi_retry = le32_to_cpu(get_log->multi_retry);
245 stats->frame_dup = le32_to_cpu(get_log->frame_dup);
246 stats->rts_success = le32_to_cpu(get_log->rts_success);
247 stats->rts_failure = le32_to_cpu(get_log->rts_failure);
248 stats->ack_failure = le32_to_cpu(get_log->ack_failure);
249 stats->rx_frag = le32_to_cpu(get_log->rx_frag);
250 stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
251 stats->fcs_error = le32_to_cpu(get_log->fcs_error);
252 stats->tx_frame = le32_to_cpu(get_log->tx_frame);
253 stats->wep_icv_error[0] =
254 le32_to_cpu(get_log->wep_icv_err_cnt[0]);
255 stats->wep_icv_error[1] =
256 le32_to_cpu(get_log->wep_icv_err_cnt[1]);
257 stats->wep_icv_error[2] =
258 le32_to_cpu(get_log->wep_icv_err_cnt[2]);
259 stats->wep_icv_error[3] =
260 le32_to_cpu(get_log->wep_icv_err_cnt[3]);
261 }
262
263 return 0;
264}
265
266/*
267 * This function handles the command response of set/get Tx rate
268 * configurations.
269 *
270 * Handling includes changing the header fields into CPU format
271 * and saving the following parameters in driver -
272 * - DSSS rate bitmap
273 * - OFDM rate bitmap
274 * - HT MCS rate bitmaps
275 *
276 * Based on the new rate bitmaps, the function re-evaluates if
277 * auto data rate has been activated. If not, it sends another
278 * query to the firmware to get the current Tx data rate and updates
279 * the driver value.
280 */
281static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
282 struct host_cmd_ds_command *resp,
283 void *data_buf)
284{
285 struct mwifiex_adapter *adapter = priv->adapter;
286 struct mwifiex_rate_cfg *ds_rate = NULL;
287 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
288 struct mwifiex_rate_scope *rate_scope;
289 struct mwifiex_ie_types_header *head = NULL;
290 u16 tlv, tlv_buf_len;
291 u8 *tlv_buf;
292 u32 i;
293 int ret = 0;
294
295 tlv_buf = (u8 *) ((u8 *) rate_cfg) +
296 sizeof(struct host_cmd_ds_tx_rate_cfg);
297 tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
298
299 while (tlv_buf && tlv_buf_len > 0) {
300 tlv = (*tlv_buf);
301 tlv = tlv | (*(tlv_buf + 1) << 8);
302
303 switch (tlv) {
304 case TLV_TYPE_RATE_SCOPE:
305 rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
306 priv->bitmap_rates[0] =
307 le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
308 priv->bitmap_rates[1] =
309 le16_to_cpu(rate_scope->ofdm_rate_bitmap);
310 for (i = 0;
311 i <
312 sizeof(rate_scope->ht_mcs_rate_bitmap) /
313 sizeof(u16); i++)
314 priv->bitmap_rates[2 + i] =
315 le16_to_cpu(rate_scope->
316 ht_mcs_rate_bitmap[i]);
317 break;
318 /* Add RATE_DROP tlv here */
319 }
320
321 head = (struct mwifiex_ie_types_header *) tlv_buf;
322 tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
323 tlv_buf_len -= le16_to_cpu(head->len);
324 }
325
326 priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
327
328 if (priv->is_data_rate_auto)
329 priv->data_rate = 0;
330 else
331 ret = mwifiex_prepare_cmd(priv,
332 HostCmd_CMD_802_11_TX_RATE_QUERY,
333 HostCmd_ACT_GEN_GET, 0, NULL, NULL);
334
335 if (data_buf) {
336 ds_rate = (struct mwifiex_rate_cfg *) data_buf;
337 if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) {
338 if (priv->is_data_rate_auto) {
339 ds_rate->is_rate_auto = 1;
340 } else {
341 ds_rate->rate =
342 mwifiex_get_rate_index(adapter,
343 priv->
344 bitmap_rates,
345 sizeof(priv->
346 bitmap_rates));
347 if (ds_rate->rate >=
348 MWIFIEX_RATE_BITMAP_OFDM0
349 && ds_rate->rate <=
350 MWIFIEX_RATE_BITMAP_OFDM7)
351 ds_rate->rate -=
352 (MWIFIEX_RATE_BITMAP_OFDM0 -
353 MWIFIEX_RATE_INDEX_OFDM0);
354 if (ds_rate->rate >=
355 MWIFIEX_RATE_BITMAP_MCS0
356 && ds_rate->rate <=
357 MWIFIEX_RATE_BITMAP_MCS127)
358 ds_rate->rate -=
359 (MWIFIEX_RATE_BITMAP_MCS0 -
360 MWIFIEX_RATE_INDEX_MCS0);
361 }
362 }
363 }
364
365 return ret;
366}
367
368/*
369 * This function handles the command response of get Tx power level.
370 *
371 * Handling includes saving the maximum and minimum Tx power levels
372 * in driver, as well as sending the values to user.
373 */
374static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
375{
376 int length = -1, max_power = -1, min_power = -1;
377 struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
378 struct mwifiex_power_group *pg = NULL;
379
380 if (data_buf) {
381 pg_tlv_hdr =
382 (struct mwifiex_types_power_group *) ((u8 *) data_buf
383 + sizeof(struct host_cmd_ds_txpwr_cfg));
384 pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr +
385 sizeof(struct mwifiex_types_power_group));
386 length = pg_tlv_hdr->length;
387 if (length > 0) {
388 max_power = pg->power_max;
389 min_power = pg->power_min;
390 length -= sizeof(struct mwifiex_power_group);
391 }
392 while (length) {
393 pg++;
394 if (max_power < pg->power_max)
395 max_power = pg->power_max;
396
397 if (min_power > pg->power_min)
398 min_power = pg->power_min;
399
400 length -= sizeof(struct mwifiex_power_group);
401 }
402 if (pg_tlv_hdr->length > 0) {
403 priv->min_tx_power_level = (u8) min_power;
404 priv->max_tx_power_level = (u8) max_power;
405 }
406 } else {
407 return -1;
408 }
409
410 return 0;
411}
412
413/*
414 * This function handles the command response of set/get Tx power
415 * configurations.
416 *
417 * Handling includes changing the header fields into CPU format
418 * and saving the current Tx power level in driver.
419 */
420static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
421 struct host_cmd_ds_command *resp,
422 void *data_buf)
423{
424 struct mwifiex_adapter *adapter = priv->adapter;
425 struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
426 struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
427 struct mwifiex_power_group *pg = NULL;
428 u16 action = le16_to_cpu(txp_cfg->action);
429
430 switch (action) {
431 case HostCmd_ACT_GEN_GET:
432 {
433 pg_tlv_hdr =
434 (struct mwifiex_types_power_group *) ((u8 *)
435 txp_cfg +
436 sizeof
437 (struct
438 host_cmd_ds_txpwr_cfg));
439 pg = (struct mwifiex_power_group *) ((u8 *)
440 pg_tlv_hdr +
441 sizeof(struct
442 mwifiex_types_power_group));
443 if (adapter->hw_status ==
444 MWIFIEX_HW_STATUS_INITIALIZING)
445 mwifiex_get_power_level(priv, txp_cfg);
446 priv->tx_power_level = (u16) pg->power_min;
447 break;
448 }
449 case HostCmd_ACT_GEN_SET:
450 if (le32_to_cpu(txp_cfg->mode)) {
451 pg_tlv_hdr =
452 (struct mwifiex_types_power_group *) ((u8 *)
453 txp_cfg +
454 sizeof
455 (struct
456 host_cmd_ds_txpwr_cfg));
457 pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr
458 +
459 sizeof(struct
460 mwifiex_types_power_group));
461 if (pg->power_max == pg->power_min)
462 priv->tx_power_level = (u16) pg->power_min;
463 }
464 break;
465 default:
466 dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
467 action);
468 return 0;
469 }
470 dev_dbg(adapter->dev,
471 "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
472 priv->tx_power_level, priv->max_tx_power_level,
473 priv->min_tx_power_level);
474
475 return 0;
476}
477
478/*
479 * This function handles the command response of set/get MAC address.
480 *
481 * Handling includes saving the MAC address in driver.
482 */
483static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
484 struct host_cmd_ds_command *resp)
485{
486 struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
487 &resp->params.mac_addr;
488
489 memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
490
491 dev_dbg(priv->adapter->dev,
492 "info: set mac address: %pM\n", priv->curr_addr);
493
494 return 0;
495}
496
497/*
498 * This function handles the command response of set/get MAC multicast
499 * address.
500 */
501static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
502 struct host_cmd_ds_command *resp)
503{
504 return 0;
505}
506
507/*
508 * This function handles the command response of get Tx rate query.
509 *
510 * Handling includes changing the header fields into CPU format
511 * and saving the Tx rate and HT information parameters in driver.
512 *
513 * Both rate configuration and current data rate can be retrieved
514 * with this request.
515 */
516static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
517 struct host_cmd_ds_command *resp)
518{
519 struct mwifiex_adapter *adapter = priv->adapter;
520
521 priv->tx_rate = resp->params.tx_rate.tx_rate;
522 priv->tx_htinfo = resp->params.tx_rate.ht_info;
523 if (!priv->is_data_rate_auto)
524 priv->data_rate =
525 mwifiex_index_to_data_rate(adapter, priv->tx_rate,
526 priv->tx_htinfo);
527
528 return 0;
529}
530
531/*
532 * This function handles the command response of a deauthenticate
533 * command.
534 *
535 * If the deauthenticated MAC matches the current BSS MAC, the connection
536 * state is reset.
537 */
538static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
539 struct host_cmd_ds_command *resp)
540{
541 struct mwifiex_adapter *adapter = priv->adapter;
542
543 adapter->dbg.num_cmd_deauth++;
544 if (!memcmp(resp->params.deauth.mac_addr,
545 &priv->curr_bss_params.bss_descriptor.mac_address,
546 sizeof(resp->params.deauth.mac_addr)))
547 mwifiex_reset_connect_state(priv);
548
549 return 0;
550}
551
552/*
553 * This function handles the command response of ad-hoc stop.
554 *
555 * The function resets the connection state in driver.
556 */
557static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
558 struct host_cmd_ds_command *resp)
559{
560 mwifiex_reset_connect_state(priv);
561 return 0;
562}
563
564/*
565 * This function handles the command response of set/get key material.
566 *
567 * Handling includes updating the driver parameters to reflect the
568 * changes.
569 */
570static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
571 struct host_cmd_ds_command *resp)
572{
573 struct host_cmd_ds_802_11_key_material *key =
574 &resp->params.key_material;
575
576 if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
Yogesh Ashok Powar6a35a0a2011-04-06 16:46:56 -0700577 if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
Bing Zhao5e6e3a92011-03-21 18:00:50 -0700578 dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
579 priv->wpa_is_gtk_set = true;
580 priv->scan_block = false;
581 }
582 }
583
584 memset(priv->aes_key.key_param_set.key, 0,
585 sizeof(key->key_param_set.key));
586 priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
587 memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
588 le16_to_cpu(priv->aes_key.key_param_set.key_len));
589
590 return 0;
591}
592
593/*
594 * This function handles the command response of get 11d domain information.
595 */
596static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
597 struct host_cmd_ds_command *resp)
598{
599 struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
600 &resp->params.domain_info_resp;
601 struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
602 u16 action = le16_to_cpu(domain_info->action);
603 u8 no_of_triplet = 0;
604
605 no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
606 IEEE80211_COUNTRY_STRING_LEN) /
607 sizeof(struct ieee80211_country_ie_triplet));
608
609 dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
610 " no_of_triplet=%d\n", no_of_triplet);
611
612 if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
613 dev_warn(priv->adapter->dev,
614 "11D: invalid number of triplets %d "
615 "returned!!\n", no_of_triplet);
616 return -1;
617 }
618
619 switch (action) {
620 case HostCmd_ACT_GEN_SET: /* Proc Set Action */
621 break;
622 case HostCmd_ACT_GEN_GET:
623 break;
624 default:
625 dev_err(priv->adapter->dev,
626 "11D: invalid action:%d\n", domain_info->action);
627 return -1;
628 }
629
630 return 0;
631}
632
633/*
634 * This function handles the command response of get RF channel.
635 *
636 * Handling includes changing the header fields into CPU format
637 * and saving the new channel in driver.
638 */
639static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
640 struct host_cmd_ds_command *resp,
641 void *data_buf)
642{
643 struct host_cmd_ds_802_11_rf_channel *rf_channel =
644 &resp->params.rf_channel;
645 u16 new_channel = le16_to_cpu(rf_channel->current_channel);
646
647 if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
648 dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
649 priv->curr_bss_params.bss_descriptor.channel,
650 new_channel);
651 /* Update the channel again */
652 priv->curr_bss_params.bss_descriptor.channel = new_channel;
653 }
654 if (data_buf)
655 *((u16 *)data_buf) = new_channel;
656
657 return 0;
658}
659
660/*
661 * This function handles the command response of get extended version.
662 *
663 * Handling includes forming the extended version string and sending it
664 * to application.
665 */
666static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
667 struct host_cmd_ds_command *resp,
668 void *data_buf)
669{
670 struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
671 struct host_cmd_ds_version_ext *version_ext = NULL;
672
673 if (data_buf) {
674 version_ext = (struct host_cmd_ds_version_ext *)data_buf;
675 version_ext->version_str_sel = ver_ext->version_str_sel;
676 memcpy(version_ext->version_str, ver_ext->version_str,
677 sizeof(char) * 128);
678 memcpy(priv->version_str, ver_ext->version_str, 128);
679 }
680 return 0;
681}
682
683/*
684 * This function handles the command response of register access.
685 *
686 * The register value and offset are returned to the user. For EEPROM
687 * access, the byte count is also returned.
688 */
689static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
690 void *data_buf)
691{
692 struct mwifiex_ds_reg_rw *reg_rw = NULL;
693 struct mwifiex_ds_read_eeprom *eeprom = NULL;
694
695 if (data_buf) {
696 reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
697 eeprom = (struct mwifiex_ds_read_eeprom *) data_buf;
698 switch (type) {
699 case HostCmd_CMD_MAC_REG_ACCESS:
700 {
701 struct host_cmd_ds_mac_reg_access *reg;
702 reg = (struct host_cmd_ds_mac_reg_access *)
703 &resp->params.mac_reg;
704 reg_rw->offset = cpu_to_le32(
705 (u32) le16_to_cpu(reg->offset));
706 reg_rw->value = reg->value;
707 break;
708 }
709 case HostCmd_CMD_BBP_REG_ACCESS:
710 {
711 struct host_cmd_ds_bbp_reg_access *reg;
712 reg = (struct host_cmd_ds_bbp_reg_access *)
713 &resp->params.bbp_reg;
714 reg_rw->offset = cpu_to_le32(
715 (u32) le16_to_cpu(reg->offset));
716 reg_rw->value = cpu_to_le32((u32) reg->value);
717 break;
718 }
719
720 case HostCmd_CMD_RF_REG_ACCESS:
721 {
722 struct host_cmd_ds_rf_reg_access *reg;
723 reg = (struct host_cmd_ds_rf_reg_access *)
724 &resp->params.rf_reg;
725 reg_rw->offset = cpu_to_le32(
726 (u32) le16_to_cpu(reg->offset));
727 reg_rw->value = cpu_to_le32((u32) reg->value);
728 break;
729 }
730 case HostCmd_CMD_PMIC_REG_ACCESS:
731 {
732 struct host_cmd_ds_pmic_reg_access *reg;
733 reg = (struct host_cmd_ds_pmic_reg_access *)
734 &resp->params.pmic_reg;
735 reg_rw->offset = cpu_to_le32(
736 (u32) le16_to_cpu(reg->offset));
737 reg_rw->value = cpu_to_le32((u32) reg->value);
738 break;
739 }
740 case HostCmd_CMD_CAU_REG_ACCESS:
741 {
742 struct host_cmd_ds_rf_reg_access *reg;
743 reg = (struct host_cmd_ds_rf_reg_access *)
744 &resp->params.rf_reg;
745 reg_rw->offset = cpu_to_le32(
746 (u32) le16_to_cpu(reg->offset));
747 reg_rw->value = cpu_to_le32((u32) reg->value);
748 break;
749 }
750 case HostCmd_CMD_802_11_EEPROM_ACCESS:
751 {
752 struct host_cmd_ds_802_11_eeprom_access
753 *cmd_eeprom =
754 (struct host_cmd_ds_802_11_eeprom_access
755 *) &resp->params.eeprom;
756 pr_debug("info: EEPROM read len=%x\n",
757 cmd_eeprom->byte_count);
758 if (le16_to_cpu(eeprom->byte_count) <
759 le16_to_cpu(
760 cmd_eeprom->byte_count)) {
761 eeprom->byte_count = cpu_to_le16(0);
762 pr_debug("info: EEPROM read "
763 "length is too big\n");
764 return -1;
765 }
766 eeprom->offset = cmd_eeprom->offset;
767 eeprom->byte_count = cmd_eeprom->byte_count;
768 if (le16_to_cpu(eeprom->byte_count) > 0)
769 memcpy(&eeprom->value,
770 &cmd_eeprom->value,
771 le16_to_cpu(eeprom->byte_count));
772
773 break;
774 }
775 default:
776 return -1;
777 }
778 }
779 return 0;
780}
781
782/*
783 * This function handles the command response of get IBSS coalescing status.
784 *
785 * If the received BSSID is different than the current one, the current BSSID,
786 * beacon interval, ATIM window and ERP information are updated, along with
787 * changing the ad-hoc state accordingly.
788 */
789static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
790 struct host_cmd_ds_command *resp)
791{
792 struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
793 &(resp->params.ibss_coalescing);
794 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
795
796 if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
797 return 0;
798
799 dev_dbg(priv->adapter->dev,
800 "info: new BSSID %pM\n", ibss_coal_resp->bssid);
801
802 /* If rsp has NULL BSSID, Just return..... No Action */
803 if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
804 dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
805 return 0;
806 }
807
808 /* If BSSID is diff, modify current BSS parameters */
809 if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
810 ibss_coal_resp->bssid, ETH_ALEN)) {
811 /* BSSID */
812 memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
813 ibss_coal_resp->bssid, ETH_ALEN);
814
815 /* Beacon Interval */
816 priv->curr_bss_params.bss_descriptor.beacon_period
817 = le16_to_cpu(ibss_coal_resp->beacon_interval);
818
819 /* ERP Information */
820 priv->curr_bss_params.bss_descriptor.erp_flags =
821 (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
822
823 priv->adhoc_state = ADHOC_COALESCED;
824 }
825
826 return 0;
827}
828
829/*
830 * This function handles the command responses.
831 *
832 * This is a generic function, which calls command specific
833 * response handlers based on the command ID.
834 */
835int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv,
836 u16 cmdresp_no, void *cmd_buf, void *wq_buf)
837{
838 int ret = 0;
839 struct mwifiex_adapter *adapter = priv->adapter;
840 struct host_cmd_ds_command *resp =
841 (struct host_cmd_ds_command *) cmd_buf;
842 struct mwifiex_wait_queue *wait_queue =
843 (struct mwifiex_wait_queue *) wq_buf;
844 void *data_buf = adapter->curr_cmd->data_buf;
845
846 /* If the command is not successful, cleanup and return failure */
847 if (resp->result != HostCmd_RESULT_OK) {
848 mwifiex_process_cmdresp_error(priv, resp, wait_queue);
849 return -1;
850 }
851 /* Command successful, handle response */
852 switch (cmdresp_no) {
853 case HostCmd_CMD_GET_HW_SPEC:
854 ret = mwifiex_ret_get_hw_spec(priv, resp);
855 break;
856 case HostCmd_CMD_MAC_CONTROL:
857 break;
858 case HostCmd_CMD_802_11_MAC_ADDRESS:
859 ret = mwifiex_ret_802_11_mac_address(priv, resp);
860 break;
861 case HostCmd_CMD_MAC_MULTICAST_ADR:
862 ret = mwifiex_ret_mac_multicast_adr(priv, resp);
863 break;
864 case HostCmd_CMD_TX_RATE_CFG:
865 ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
866 break;
867 case HostCmd_CMD_802_11_SCAN:
868 ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
869 wait_queue = NULL;
870 adapter->curr_cmd->wq_buf = NULL;
871 break;
872 case HostCmd_CMD_802_11_BG_SCAN_QUERY:
873 ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
874 dev_dbg(adapter->dev,
875 "info: CMD_RESP: BG_SCAN result is ready!\n");
876 break;
877 case HostCmd_CMD_TXPWR_CFG:
878 ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf);
879 break;
880 case HostCmd_CMD_802_11_PS_MODE_ENH:
881 ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
882 break;
883 case HostCmd_CMD_802_11_HS_CFG_ENH:
884 ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
885 break;
886 case HostCmd_CMD_802_11_ASSOCIATE:
887 ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue);
888 break;
889 case HostCmd_CMD_802_11_DEAUTHENTICATE:
890 ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
891 break;
892 case HostCmd_CMD_802_11_AD_HOC_START:
893 case HostCmd_CMD_802_11_AD_HOC_JOIN:
894 ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue);
895 break;
896 case HostCmd_CMD_802_11_AD_HOC_STOP:
897 ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
898 break;
899 case HostCmd_CMD_802_11_GET_LOG:
900 ret = mwifiex_ret_get_log(priv, resp, data_buf);
901 break;
902 case HostCmd_CMD_RSSI_INFO:
903 ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
904 break;
905 case HostCmd_CMD_802_11_SNMP_MIB:
906 ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
907 break;
908 case HostCmd_CMD_802_11_TX_RATE_QUERY:
909 ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
910 break;
911 case HostCmd_CMD_802_11_RF_CHANNEL:
912 ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
913 break;
914 case HostCmd_CMD_VERSION_EXT:
915 ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
916 break;
917 case HostCmd_CMD_FUNC_INIT:
918 case HostCmd_CMD_FUNC_SHUTDOWN:
919 break;
920 case HostCmd_CMD_802_11_KEY_MATERIAL:
921 ret = mwifiex_ret_802_11_key_material(priv, resp);
922 break;
923 case HostCmd_CMD_802_11D_DOMAIN_INFO:
924 ret = mwifiex_ret_802_11d_domain_info(priv, resp);
925 break;
926 case HostCmd_CMD_11N_ADDBA_REQ:
927 ret = mwifiex_ret_11n_addba_req(priv, resp);
928 break;
929 case HostCmd_CMD_11N_DELBA:
930 ret = mwifiex_ret_11n_delba(priv, resp);
931 break;
932 case HostCmd_CMD_11N_ADDBA_RSP:
933 ret = mwifiex_ret_11n_addba_resp(priv, resp);
934 break;
935 case HostCmd_CMD_RECONFIGURE_TX_BUFF:
936 adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
937 tx_buf.buff_size);
938 adapter->tx_buf_size = (adapter->tx_buf_size /
939 MWIFIEX_SDIO_BLOCK_SIZE) *
940 MWIFIEX_SDIO_BLOCK_SIZE;
941 adapter->curr_tx_buf_size = adapter->tx_buf_size;
942 dev_dbg(adapter->dev,
943 "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
944 adapter->max_tx_buf_size, adapter->tx_buf_size);
945
946 if (adapter->if_ops.update_mp_end_port)
947 adapter->if_ops.update_mp_end_port(adapter,
948 le16_to_cpu(resp->
949 params.
950 tx_buf.
951 mp_end_port));
952 break;
953 case HostCmd_CMD_AMSDU_AGGR_CTRL:
954 ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf);
955 break;
956 case HostCmd_CMD_WMM_GET_STATUS:
957 ret = mwifiex_ret_wmm_get_status(priv, resp);
958 break;
959 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
960 ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
961 break;
962 case HostCmd_CMD_MAC_REG_ACCESS:
963 case HostCmd_CMD_BBP_REG_ACCESS:
964 case HostCmd_CMD_RF_REG_ACCESS:
965 case HostCmd_CMD_PMIC_REG_ACCESS:
966 case HostCmd_CMD_CAU_REG_ACCESS:
967 case HostCmd_CMD_802_11_EEPROM_ACCESS:
968 ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
969 break;
970 case HostCmd_CMD_SET_BSS_MODE:
971 break;
972 case HostCmd_CMD_11N_CFG:
973 ret = mwifiex_ret_11n_cfg(priv, resp, data_buf);
974 break;
975 default:
976 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
977 resp->command);
978 break;
979 }
980
981 return ret;
982}