blob: 74add45b99b66a70f879530fdaa3e40a8481e041 [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) {
577 if ((le16_to_cpu(key->key_param_set.key_info) &
578 KEY_INFO_TKIP_MCAST)) {
579 dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
580 priv->wpa_is_gtk_set = true;
581 priv->scan_block = false;
582 }
583 }
584
585 memset(priv->aes_key.key_param_set.key, 0,
586 sizeof(key->key_param_set.key));
587 priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
588 memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
589 le16_to_cpu(priv->aes_key.key_param_set.key_len));
590
591 return 0;
592}
593
594/*
595 * This function handles the command response of get 11d domain information.
596 */
597static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
598 struct host_cmd_ds_command *resp)
599{
600 struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
601 &resp->params.domain_info_resp;
602 struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
603 u16 action = le16_to_cpu(domain_info->action);
604 u8 no_of_triplet = 0;
605
606 no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
607 IEEE80211_COUNTRY_STRING_LEN) /
608 sizeof(struct ieee80211_country_ie_triplet));
609
610 dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
611 " no_of_triplet=%d\n", no_of_triplet);
612
613 if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
614 dev_warn(priv->adapter->dev,
615 "11D: invalid number of triplets %d "
616 "returned!!\n", no_of_triplet);
617 return -1;
618 }
619
620 switch (action) {
621 case HostCmd_ACT_GEN_SET: /* Proc Set Action */
622 break;
623 case HostCmd_ACT_GEN_GET:
624 break;
625 default:
626 dev_err(priv->adapter->dev,
627 "11D: invalid action:%d\n", domain_info->action);
628 return -1;
629 }
630
631 return 0;
632}
633
634/*
635 * This function handles the command response of get RF channel.
636 *
637 * Handling includes changing the header fields into CPU format
638 * and saving the new channel in driver.
639 */
640static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
641 struct host_cmd_ds_command *resp,
642 void *data_buf)
643{
644 struct host_cmd_ds_802_11_rf_channel *rf_channel =
645 &resp->params.rf_channel;
646 u16 new_channel = le16_to_cpu(rf_channel->current_channel);
647
648 if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
649 dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
650 priv->curr_bss_params.bss_descriptor.channel,
651 new_channel);
652 /* Update the channel again */
653 priv->curr_bss_params.bss_descriptor.channel = new_channel;
654 }
655 if (data_buf)
656 *((u16 *)data_buf) = new_channel;
657
658 return 0;
659}
660
661/*
662 * This function handles the command response of get extended version.
663 *
664 * Handling includes forming the extended version string and sending it
665 * to application.
666 */
667static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
668 struct host_cmd_ds_command *resp,
669 void *data_buf)
670{
671 struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
672 struct host_cmd_ds_version_ext *version_ext = NULL;
673
674 if (data_buf) {
675 version_ext = (struct host_cmd_ds_version_ext *)data_buf;
676 version_ext->version_str_sel = ver_ext->version_str_sel;
677 memcpy(version_ext->version_str, ver_ext->version_str,
678 sizeof(char) * 128);
679 memcpy(priv->version_str, ver_ext->version_str, 128);
680 }
681 return 0;
682}
683
684/*
685 * This function handles the command response of register access.
686 *
687 * The register value and offset are returned to the user. For EEPROM
688 * access, the byte count is also returned.
689 */
690static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
691 void *data_buf)
692{
693 struct mwifiex_ds_reg_rw *reg_rw = NULL;
694 struct mwifiex_ds_read_eeprom *eeprom = NULL;
695
696 if (data_buf) {
697 reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
698 eeprom = (struct mwifiex_ds_read_eeprom *) data_buf;
699 switch (type) {
700 case HostCmd_CMD_MAC_REG_ACCESS:
701 {
702 struct host_cmd_ds_mac_reg_access *reg;
703 reg = (struct host_cmd_ds_mac_reg_access *)
704 &resp->params.mac_reg;
705 reg_rw->offset = cpu_to_le32(
706 (u32) le16_to_cpu(reg->offset));
707 reg_rw->value = reg->value;
708 break;
709 }
710 case HostCmd_CMD_BBP_REG_ACCESS:
711 {
712 struct host_cmd_ds_bbp_reg_access *reg;
713 reg = (struct host_cmd_ds_bbp_reg_access *)
714 &resp->params.bbp_reg;
715 reg_rw->offset = cpu_to_le32(
716 (u32) le16_to_cpu(reg->offset));
717 reg_rw->value = cpu_to_le32((u32) reg->value);
718 break;
719 }
720
721 case HostCmd_CMD_RF_REG_ACCESS:
722 {
723 struct host_cmd_ds_rf_reg_access *reg;
724 reg = (struct host_cmd_ds_rf_reg_access *)
725 &resp->params.rf_reg;
726 reg_rw->offset = cpu_to_le32(
727 (u32) le16_to_cpu(reg->offset));
728 reg_rw->value = cpu_to_le32((u32) reg->value);
729 break;
730 }
731 case HostCmd_CMD_PMIC_REG_ACCESS:
732 {
733 struct host_cmd_ds_pmic_reg_access *reg;
734 reg = (struct host_cmd_ds_pmic_reg_access *)
735 &resp->params.pmic_reg;
736 reg_rw->offset = cpu_to_le32(
737 (u32) le16_to_cpu(reg->offset));
738 reg_rw->value = cpu_to_le32((u32) reg->value);
739 break;
740 }
741 case HostCmd_CMD_CAU_REG_ACCESS:
742 {
743 struct host_cmd_ds_rf_reg_access *reg;
744 reg = (struct host_cmd_ds_rf_reg_access *)
745 &resp->params.rf_reg;
746 reg_rw->offset = cpu_to_le32(
747 (u32) le16_to_cpu(reg->offset));
748 reg_rw->value = cpu_to_le32((u32) reg->value);
749 break;
750 }
751 case HostCmd_CMD_802_11_EEPROM_ACCESS:
752 {
753 struct host_cmd_ds_802_11_eeprom_access
754 *cmd_eeprom =
755 (struct host_cmd_ds_802_11_eeprom_access
756 *) &resp->params.eeprom;
757 pr_debug("info: EEPROM read len=%x\n",
758 cmd_eeprom->byte_count);
759 if (le16_to_cpu(eeprom->byte_count) <
760 le16_to_cpu(
761 cmd_eeprom->byte_count)) {
762 eeprom->byte_count = cpu_to_le16(0);
763 pr_debug("info: EEPROM read "
764 "length is too big\n");
765 return -1;
766 }
767 eeprom->offset = cmd_eeprom->offset;
768 eeprom->byte_count = cmd_eeprom->byte_count;
769 if (le16_to_cpu(eeprom->byte_count) > 0)
770 memcpy(&eeprom->value,
771 &cmd_eeprom->value,
772 le16_to_cpu(eeprom->byte_count));
773
774 break;
775 }
776 default:
777 return -1;
778 }
779 }
780 return 0;
781}
782
783/*
784 * This function handles the command response of get IBSS coalescing status.
785 *
786 * If the received BSSID is different than the current one, the current BSSID,
787 * beacon interval, ATIM window and ERP information are updated, along with
788 * changing the ad-hoc state accordingly.
789 */
790static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
791 struct host_cmd_ds_command *resp)
792{
793 struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
794 &(resp->params.ibss_coalescing);
795 u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
796
797 if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
798 return 0;
799
800 dev_dbg(priv->adapter->dev,
801 "info: new BSSID %pM\n", ibss_coal_resp->bssid);
802
803 /* If rsp has NULL BSSID, Just return..... No Action */
804 if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
805 dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
806 return 0;
807 }
808
809 /* If BSSID is diff, modify current BSS parameters */
810 if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
811 ibss_coal_resp->bssid, ETH_ALEN)) {
812 /* BSSID */
813 memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
814 ibss_coal_resp->bssid, ETH_ALEN);
815
816 /* Beacon Interval */
817 priv->curr_bss_params.bss_descriptor.beacon_period
818 = le16_to_cpu(ibss_coal_resp->beacon_interval);
819
820 /* ERP Information */
821 priv->curr_bss_params.bss_descriptor.erp_flags =
822 (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
823
824 priv->adhoc_state = ADHOC_COALESCED;
825 }
826
827 return 0;
828}
829
830/*
831 * This function handles the command responses.
832 *
833 * This is a generic function, which calls command specific
834 * response handlers based on the command ID.
835 */
836int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv,
837 u16 cmdresp_no, void *cmd_buf, void *wq_buf)
838{
839 int ret = 0;
840 struct mwifiex_adapter *adapter = priv->adapter;
841 struct host_cmd_ds_command *resp =
842 (struct host_cmd_ds_command *) cmd_buf;
843 struct mwifiex_wait_queue *wait_queue =
844 (struct mwifiex_wait_queue *) wq_buf;
845 void *data_buf = adapter->curr_cmd->data_buf;
846
847 /* If the command is not successful, cleanup and return failure */
848 if (resp->result != HostCmd_RESULT_OK) {
849 mwifiex_process_cmdresp_error(priv, resp, wait_queue);
850 return -1;
851 }
852 /* Command successful, handle response */
853 switch (cmdresp_no) {
854 case HostCmd_CMD_GET_HW_SPEC:
855 ret = mwifiex_ret_get_hw_spec(priv, resp);
856 break;
857 case HostCmd_CMD_MAC_CONTROL:
858 break;
859 case HostCmd_CMD_802_11_MAC_ADDRESS:
860 ret = mwifiex_ret_802_11_mac_address(priv, resp);
861 break;
862 case HostCmd_CMD_MAC_MULTICAST_ADR:
863 ret = mwifiex_ret_mac_multicast_adr(priv, resp);
864 break;
865 case HostCmd_CMD_TX_RATE_CFG:
866 ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
867 break;
868 case HostCmd_CMD_802_11_SCAN:
869 ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
870 wait_queue = NULL;
871 adapter->curr_cmd->wq_buf = NULL;
872 break;
873 case HostCmd_CMD_802_11_BG_SCAN_QUERY:
874 ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue);
875 dev_dbg(adapter->dev,
876 "info: CMD_RESP: BG_SCAN result is ready!\n");
877 break;
878 case HostCmd_CMD_TXPWR_CFG:
879 ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf);
880 break;
881 case HostCmd_CMD_802_11_PS_MODE_ENH:
882 ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
883 break;
884 case HostCmd_CMD_802_11_HS_CFG_ENH:
885 ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
886 break;
887 case HostCmd_CMD_802_11_ASSOCIATE:
888 ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue);
889 break;
890 case HostCmd_CMD_802_11_DEAUTHENTICATE:
891 ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
892 break;
893 case HostCmd_CMD_802_11_AD_HOC_START:
894 case HostCmd_CMD_802_11_AD_HOC_JOIN:
895 ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue);
896 break;
897 case HostCmd_CMD_802_11_AD_HOC_STOP:
898 ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
899 break;
900 case HostCmd_CMD_802_11_GET_LOG:
901 ret = mwifiex_ret_get_log(priv, resp, data_buf);
902 break;
903 case HostCmd_CMD_RSSI_INFO:
904 ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
905 break;
906 case HostCmd_CMD_802_11_SNMP_MIB:
907 ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
908 break;
909 case HostCmd_CMD_802_11_TX_RATE_QUERY:
910 ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
911 break;
912 case HostCmd_CMD_802_11_RF_CHANNEL:
913 ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
914 break;
915 case HostCmd_CMD_VERSION_EXT:
916 ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
917 break;
918 case HostCmd_CMD_FUNC_INIT:
919 case HostCmd_CMD_FUNC_SHUTDOWN:
920 break;
921 case HostCmd_CMD_802_11_KEY_MATERIAL:
922 ret = mwifiex_ret_802_11_key_material(priv, resp);
923 break;
924 case HostCmd_CMD_802_11D_DOMAIN_INFO:
925 ret = mwifiex_ret_802_11d_domain_info(priv, resp);
926 break;
927 case HostCmd_CMD_11N_ADDBA_REQ:
928 ret = mwifiex_ret_11n_addba_req(priv, resp);
929 break;
930 case HostCmd_CMD_11N_DELBA:
931 ret = mwifiex_ret_11n_delba(priv, resp);
932 break;
933 case HostCmd_CMD_11N_ADDBA_RSP:
934 ret = mwifiex_ret_11n_addba_resp(priv, resp);
935 break;
936 case HostCmd_CMD_RECONFIGURE_TX_BUFF:
937 adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
938 tx_buf.buff_size);
939 adapter->tx_buf_size = (adapter->tx_buf_size /
940 MWIFIEX_SDIO_BLOCK_SIZE) *
941 MWIFIEX_SDIO_BLOCK_SIZE;
942 adapter->curr_tx_buf_size = adapter->tx_buf_size;
943 dev_dbg(adapter->dev,
944 "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
945 adapter->max_tx_buf_size, adapter->tx_buf_size);
946
947 if (adapter->if_ops.update_mp_end_port)
948 adapter->if_ops.update_mp_end_port(adapter,
949 le16_to_cpu(resp->
950 params.
951 tx_buf.
952 mp_end_port));
953 break;
954 case HostCmd_CMD_AMSDU_AGGR_CTRL:
955 ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf);
956 break;
957 case HostCmd_CMD_WMM_GET_STATUS:
958 ret = mwifiex_ret_wmm_get_status(priv, resp);
959 break;
960 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
961 ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
962 break;
963 case HostCmd_CMD_MAC_REG_ACCESS:
964 case HostCmd_CMD_BBP_REG_ACCESS:
965 case HostCmd_CMD_RF_REG_ACCESS:
966 case HostCmd_CMD_PMIC_REG_ACCESS:
967 case HostCmd_CMD_CAU_REG_ACCESS:
968 case HostCmd_CMD_802_11_EEPROM_ACCESS:
969 ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
970 break;
971 case HostCmd_CMD_SET_BSS_MODE:
972 break;
973 case HostCmd_CMD_11N_CFG:
974 ret = mwifiex_ret_11n_cfg(priv, resp, data_buf);
975 break;
976 default:
977 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
978 resp->command);
979 break;
980 }
981
982 return ret;
983}