1/* 2 * Marvell Wireless LAN device driver: station command response handling 3 * 4 * Copyright (C) 2011-2014, 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 "11ac.h" 28 29 30/* 31 * This function handles the command response error case. 32 * 33 * For scan response error, the function cancels all the pending 34 * scan commands and generates an event to inform the applications 35 * of the scan completion. 36 * 37 * For Power Save command failure, we do not retry enter PS 38 * command in case of Ad-hoc mode. 39 * 40 * For all other response errors, the current command buffer is freed 41 * and returned to the free command queue. 42 */ 43static void 44mwifiex_process_cmdresp_error(struct mwifiex_private *priv, 45 struct host_cmd_ds_command *resp) 46{ 47 struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; 48 struct mwifiex_adapter *adapter = priv->adapter; 49 struct host_cmd_ds_802_11_ps_mode_enh *pm; 50 unsigned long flags; 51 52 dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", 53 resp->command, resp->result); 54 55 if (adapter->curr_cmd->wait_q_enabled) 56 adapter->cmd_wait_q.status = -1; 57 58 switch (le16_to_cpu(resp->command)) { 59 case HostCmd_CMD_802_11_PS_MODE_ENH: 60 pm = &resp->params.psmode_enh; 61 dev_err(adapter->dev, 62 "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n", 63 resp->result, le16_to_cpu(pm->action)); 64 /* We do not re-try enter-ps command in ad-hoc mode. */ 65 if (le16_to_cpu(pm->action) == EN_AUTO_PS && 66 (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && 67 priv->bss_mode == NL80211_IFTYPE_ADHOC) 68 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; 69 70 break; 71 case HostCmd_CMD_802_11_SCAN: 72 case HostCmd_CMD_802_11_SCAN_EXT: 73 /* Cancel all pending scan command */ 74 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); 75 list_for_each_entry_safe(cmd_node, tmp_node, 76 &adapter->scan_pending_q, list) { 77 list_del(&cmd_node->list); 78 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, 79 flags); 80 mwifiex_insert_cmd_to_free_q(adapter, cmd_node); 81 spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); 82 } 83 spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); 84 85 spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); 86 adapter->scan_processing = false; 87 spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); 88 break; 89 90 case HostCmd_CMD_MAC_CONTROL: 91 break; 92 93 case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: 94 dev_err(priv->adapter->dev, "SDIO RX single-port aggregation Not support\n"); 95 break; 96 97 default: 98 break; 99 } 100 /* Handling errors here */ 101 mwifiex_recycle_cmd_node(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{ 124 struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = 125 &resp->params.rssi_info_rsp; 126 struct mwifiex_ds_misc_subsc_evt *subsc_evt = 127 &priv->async_subsc_evt_storage; 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 if (priv->subsc_evt_rssi_state == EVENT_HANDLED) 142 return 0; 143 144 memset(subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt)); 145 146 /* Resubscribe low and high rssi events with new thresholds */ 147 subsc_evt->events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; 148 subsc_evt->action = HostCmd_ACT_BITWISE_SET; 149 if (priv->subsc_evt_rssi_state == RSSI_LOW_RECVD) { 150 subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg - 151 priv->cqm_rssi_hyst); 152 subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold); 153 } else if (priv->subsc_evt_rssi_state == RSSI_HIGH_RECVD) { 154 subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold); 155 subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg + 156 priv->cqm_rssi_hyst); 157 } 158 subsc_evt->bcn_l_rssi_cfg.evt_freq = 1; 159 subsc_evt->bcn_h_rssi_cfg.evt_freq = 1; 160 161 priv->subsc_evt_rssi_state = EVENT_HANDLED; 162 163 mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 164 0, 0, subsc_evt, false); 165 166 return 0; 167} 168 169/* 170 * This function handles the command response of set/get SNMP 171 * MIB parameters. 172 * 173 * Handling includes changing the header fields into CPU format 174 * and saving the parameter in driver. 175 * 176 * The following parameters are supported - 177 * - Fragmentation threshold 178 * - RTS threshold 179 * - Short retry limit 180 */ 181static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, 182 struct host_cmd_ds_command *resp, 183 u32 *data_buf) 184{ 185 struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; 186 u16 oid = le16_to_cpu(smib->oid); 187 u16 query_type = le16_to_cpu(smib->query_type); 188 u32 ul_temp; 189 190 dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," 191 " query_type = %#x, buf size = %#x\n", 192 oid, query_type, le16_to_cpu(smib->buf_size)); 193 if (query_type == HostCmd_ACT_GEN_GET) { 194 ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); 195 if (data_buf) 196 *data_buf = ul_temp; 197 switch (oid) { 198 case FRAG_THRESH_I: 199 dev_dbg(priv->adapter->dev, 200 "info: SNMP_RESP: FragThsd =%u\n", ul_temp); 201 break; 202 case RTS_THRESH_I: 203 dev_dbg(priv->adapter->dev, 204 "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); 205 break; 206 case SHORT_RETRY_LIM_I: 207 dev_dbg(priv->adapter->dev, 208 "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); 209 break; 210 case DTIM_PERIOD_I: 211 dev_dbg(priv->adapter->dev, 212 "info: SNMP_RESP: DTIM period=%u\n", ul_temp); 213 default: 214 break; 215 } 216 } 217 218 return 0; 219} 220 221/* 222 * This function handles the command response of get log request 223 * 224 * Handling includes changing the header fields into CPU format 225 * and sending the received parameters to application. 226 */ 227static int mwifiex_ret_get_log(struct mwifiex_private *priv, 228 struct host_cmd_ds_command *resp, 229 struct mwifiex_ds_get_stats *stats) 230{ 231 struct host_cmd_ds_802_11_get_log *get_log = 232 &resp->params.get_log; 233 234 if (stats) { 235 stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); 236 stats->failed = le32_to_cpu(get_log->failed); 237 stats->retry = le32_to_cpu(get_log->retry); 238 stats->multi_retry = le32_to_cpu(get_log->multi_retry); 239 stats->frame_dup = le32_to_cpu(get_log->frame_dup); 240 stats->rts_success = le32_to_cpu(get_log->rts_success); 241 stats->rts_failure = le32_to_cpu(get_log->rts_failure); 242 stats->ack_failure = le32_to_cpu(get_log->ack_failure); 243 stats->rx_frag = le32_to_cpu(get_log->rx_frag); 244 stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); 245 stats->fcs_error = le32_to_cpu(get_log->fcs_error); 246 stats->tx_frame = le32_to_cpu(get_log->tx_frame); 247 stats->wep_icv_error[0] = 248 le32_to_cpu(get_log->wep_icv_err_cnt[0]); 249 stats->wep_icv_error[1] = 250 le32_to_cpu(get_log->wep_icv_err_cnt[1]); 251 stats->wep_icv_error[2] = 252 le32_to_cpu(get_log->wep_icv_err_cnt[2]); 253 stats->wep_icv_error[3] = 254 le32_to_cpu(get_log->wep_icv_err_cnt[3]); 255 stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt); 256 stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt); 257 } 258 259 return 0; 260} 261 262/* 263 * This function handles the command response of set/get Tx rate 264 * configurations. 265 * 266 * Handling includes changing the header fields into CPU format 267 * and saving the following parameters in driver - 268 * - DSSS rate bitmap 269 * - OFDM rate bitmap 270 * - HT MCS rate bitmaps 271 * 272 * Based on the new rate bitmaps, the function re-evaluates if 273 * auto data rate has been activated. If not, it sends another 274 * query to the firmware to get the current Tx data rate. 275 */ 276static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, 277 struct host_cmd_ds_command *resp) 278{ 279 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; 280 struct mwifiex_rate_scope *rate_scope; 281 struct mwifiex_ie_types_header *head; 282 u16 tlv, tlv_buf_len, tlv_buf_left; 283 u8 *tlv_buf; 284 u32 i; 285 286 tlv_buf = ((u8 *)rate_cfg) + sizeof(struct host_cmd_ds_tx_rate_cfg); 287 tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*rate_cfg); 288 289 while (tlv_buf_left >= sizeof(*head)) { 290 head = (struct mwifiex_ie_types_header *)tlv_buf; 291 tlv = le16_to_cpu(head->type); 292 tlv_buf_len = le16_to_cpu(head->len); 293 294 if (tlv_buf_left < (sizeof(*head) + tlv_buf_len)) 295 break; 296 297 switch (tlv) { 298 case TLV_TYPE_RATE_SCOPE: 299 rate_scope = (struct mwifiex_rate_scope *) tlv_buf; 300 priv->bitmap_rates[0] = 301 le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); 302 priv->bitmap_rates[1] = 303 le16_to_cpu(rate_scope->ofdm_rate_bitmap); 304 for (i = 0; 305 i < 306 sizeof(rate_scope->ht_mcs_rate_bitmap) / 307 sizeof(u16); i++) 308 priv->bitmap_rates[2 + i] = 309 le16_to_cpu(rate_scope-> 310 ht_mcs_rate_bitmap[i]); 311 312 if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { 313 for (i = 0; i < ARRAY_SIZE(rate_scope-> 314 vht_mcs_rate_bitmap); 315 i++) 316 priv->bitmap_rates[10 + i] = 317 le16_to_cpu(rate_scope-> 318 vht_mcs_rate_bitmap[i]); 319 } 320 break; 321 /* Add RATE_DROP tlv here */ 322 } 323 324 tlv_buf += (sizeof(*head) + tlv_buf_len); 325 tlv_buf_left -= (sizeof(*head) + tlv_buf_len); 326 } 327 328 priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); 329 330 if (priv->is_data_rate_auto) 331 priv->data_rate = 0; 332 else 333 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, 334 HostCmd_ACT_GEN_GET, 0, NULL, false); 335 336 return 0; 337} 338 339/* 340 * This function handles the command response of get Tx power level. 341 * 342 * Handling includes saving the maximum and minimum Tx power levels 343 * in driver, as well as sending the values to user. 344 */ 345static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) 346{ 347 int length, max_power = -1, min_power = -1; 348 struct mwifiex_types_power_group *pg_tlv_hdr; 349 struct mwifiex_power_group *pg; 350 351 if (!data_buf) 352 return -1; 353 354 pg_tlv_hdr = (struct mwifiex_types_power_group *)((u8 *)data_buf); 355 pg = (struct mwifiex_power_group *) 356 ((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group)); 357 length = le16_to_cpu(pg_tlv_hdr->length); 358 359 /* At least one structure required to update power */ 360 if (length < sizeof(struct mwifiex_power_group)) 361 return 0; 362 363 max_power = pg->power_max; 364 min_power = pg->power_min; 365 length -= sizeof(struct mwifiex_power_group); 366 367 while (length >= sizeof(struct mwifiex_power_group)) { 368 pg++; 369 if (max_power < pg->power_max) 370 max_power = pg->power_max; 371 372 if (min_power > pg->power_min) 373 min_power = pg->power_min; 374 375 length -= sizeof(struct mwifiex_power_group); 376 } 377 priv->min_tx_power_level = (u8) min_power; 378 priv->max_tx_power_level = (u8) max_power; 379 380 return 0; 381} 382 383/* 384 * This function handles the command response of set/get Tx power 385 * configurations. 386 * 387 * Handling includes changing the header fields into CPU format 388 * and saving the current Tx power level in driver. 389 */ 390static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, 391 struct host_cmd_ds_command *resp) 392{ 393 struct mwifiex_adapter *adapter = priv->adapter; 394 struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; 395 struct mwifiex_types_power_group *pg_tlv_hdr; 396 struct mwifiex_power_group *pg; 397 u16 action = le16_to_cpu(txp_cfg->action); 398 u16 tlv_buf_left; 399 400 pg_tlv_hdr = (struct mwifiex_types_power_group *) 401 ((u8 *)txp_cfg + 402 sizeof(struct host_cmd_ds_txpwr_cfg)); 403 404 pg = (struct mwifiex_power_group *) 405 ((u8 *)pg_tlv_hdr + 406 sizeof(struct mwifiex_types_power_group)); 407 408 tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*txp_cfg); 409 if (tlv_buf_left < 410 le16_to_cpu(pg_tlv_hdr->length) + sizeof(*pg_tlv_hdr)) 411 return 0; 412 413 switch (action) { 414 case HostCmd_ACT_GEN_GET: 415 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) 416 mwifiex_get_power_level(priv, pg_tlv_hdr); 417 418 priv->tx_power_level = (u16) pg->power_min; 419 break; 420 421 case HostCmd_ACT_GEN_SET: 422 if (!le32_to_cpu(txp_cfg->mode)) 423 break; 424 425 if (pg->power_max == pg->power_min) 426 priv->tx_power_level = (u16) pg->power_min; 427 break; 428 default: 429 dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n", 430 action); 431 return 0; 432 } 433 dev_dbg(adapter->dev, 434 "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", 435 priv->tx_power_level, priv->max_tx_power_level, 436 priv->min_tx_power_level); 437 438 return 0; 439} 440 441/* 442 * This function handles the command response of get RF Tx power. 443 */ 444static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv, 445 struct host_cmd_ds_command *resp) 446{ 447 struct host_cmd_ds_rf_tx_pwr *txp = &resp->params.txp; 448 u16 action = le16_to_cpu(txp->action); 449 450 priv->tx_power_level = le16_to_cpu(txp->cur_level); 451 452 if (action == HostCmd_ACT_GEN_GET) { 453 priv->max_tx_power_level = txp->max_power; 454 priv->min_tx_power_level = txp->min_power; 455 } 456 457 dev_dbg(priv->adapter->dev, 458 "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n", 459 priv->tx_power_level, priv->max_tx_power_level, 460 priv->min_tx_power_level); 461 462 return 0; 463} 464 465/* 466 * This function handles the command response of set rf antenna 467 */ 468static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv, 469 struct host_cmd_ds_command *resp) 470{ 471 struct host_cmd_ds_rf_ant_mimo *ant_mimo = &resp->params.ant_mimo; 472 struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso; 473 struct mwifiex_adapter *adapter = priv->adapter; 474 475 if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) 476 dev_dbg(adapter->dev, 477 "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x" 478 " Rx action = 0x%x, Rx Mode = 0x%04x\n", 479 le16_to_cpu(ant_mimo->action_tx), 480 le16_to_cpu(ant_mimo->tx_ant_mode), 481 le16_to_cpu(ant_mimo->action_rx), 482 le16_to_cpu(ant_mimo->rx_ant_mode)); 483 else 484 dev_dbg(adapter->dev, 485 "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n", 486 le16_to_cpu(ant_siso->action), 487 le16_to_cpu(ant_siso->ant_mode)); 488 489 return 0; 490} 491 492/* 493 * This function handles the command response of set/get MAC address. 494 * 495 * Handling includes saving the MAC address in driver. 496 */ 497static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, 498 struct host_cmd_ds_command *resp) 499{ 500 struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = 501 &resp->params.mac_addr; 502 503 memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); 504 505 dev_dbg(priv->adapter->dev, 506 "info: set mac address: %pM\n", priv->curr_addr); 507 508 return 0; 509} 510 511/* 512 * This function handles the command response of set/get MAC multicast 513 * address. 514 */ 515static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, 516 struct host_cmd_ds_command *resp) 517{ 518 return 0; 519} 520 521/* 522 * This function handles the command response of get Tx rate query. 523 * 524 * Handling includes changing the header fields into CPU format 525 * and saving the Tx rate and HT information parameters in driver. 526 * 527 * Both rate configuration and current data rate can be retrieved 528 * with this request. 529 */ 530static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, 531 struct host_cmd_ds_command *resp) 532{ 533 priv->tx_rate = resp->params.tx_rate.tx_rate; 534 priv->tx_htinfo = resp->params.tx_rate.ht_info; 535 if (!priv->is_data_rate_auto) 536 priv->data_rate = 537 mwifiex_index_to_data_rate(priv, priv->tx_rate, 538 priv->tx_htinfo); 539 540 return 0; 541} 542 543/* 544 * This function handles the command response of a deauthenticate 545 * command. 546 * 547 * If the deauthenticated MAC matches the current BSS MAC, the connection 548 * state is reset. 549 */ 550static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, 551 struct host_cmd_ds_command *resp) 552{ 553 struct mwifiex_adapter *adapter = priv->adapter; 554 555 adapter->dbg.num_cmd_deauth++; 556 if (!memcmp(resp->params.deauth.mac_addr, 557 &priv->curr_bss_params.bss_descriptor.mac_address, 558 sizeof(resp->params.deauth.mac_addr))) 559 mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING); 560 561 return 0; 562} 563 564/* 565 * This function handles the command response of ad-hoc stop. 566 * 567 * The function resets the connection state in driver. 568 */ 569static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, 570 struct host_cmd_ds_command *resp) 571{ 572 mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING); 573 return 0; 574} 575 576/* 577 * This function handles the command response of set/get v1 key material. 578 * 579 * Handling includes updating the driver parameters to reflect the 580 * changes. 581 */ 582static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, 583 struct host_cmd_ds_command *resp) 584{ 585 struct host_cmd_ds_802_11_key_material *key = 586 &resp->params.key_material; 587 588 if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { 589 if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) { 590 dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); 591 priv->wpa_is_gtk_set = true; 592 priv->scan_block = false; 593 } 594 } 595 596 memset(priv->aes_key.key_param_set.key, 0, 597 sizeof(key->key_param_set.key)); 598 priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; 599 memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, 600 le16_to_cpu(priv->aes_key.key_param_set.key_len)); 601 602 return 0; 603} 604 605/* 606 * This function handles the command response of set/get v2 key material. 607 * 608 * Handling includes updating the driver parameters to reflect the 609 * changes. 610 */ 611static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, 612 struct host_cmd_ds_command *resp) 613{ 614 struct host_cmd_ds_802_11_key_material_v2 *key_v2; 615 __le16 len; 616 617 key_v2 = &resp->params.key_material_v2; 618 if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) { 619 if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) { 620 dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); 621 priv->wpa_is_gtk_set = true; 622 priv->scan_block = false; 623 } 624 } 625 626 if (key_v2->key_param_set.key_type != KEY_TYPE_ID_AES) 627 return 0; 628 629 memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0, 630 WLAN_KEY_LEN_CCMP); 631 priv->aes_key_v2.key_param_set.key_params.aes.key_len = 632 key_v2->key_param_set.key_params.aes.key_len; 633 len = priv->aes_key_v2.key_param_set.key_params.aes.key_len; 634 memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key, 635 key_v2->key_param_set.key_params.aes.key, le16_to_cpu(len)); 636 637 return 0; 638} 639 640/* Wrapper function for processing response of key material command */ 641static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, 642 struct host_cmd_ds_command *resp) 643{ 644 if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) 645 return mwifiex_ret_802_11_key_material_v2(priv, resp); 646 else 647 return mwifiex_ret_802_11_key_material_v1(priv, resp); 648} 649 650/* 651 * This function handles the command response of get 11d domain information. 652 */ 653static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, 654 struct host_cmd_ds_command *resp) 655{ 656 struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = 657 &resp->params.domain_info_resp; 658 struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; 659 u16 action = le16_to_cpu(domain_info->action); 660 u8 no_of_triplet; 661 662 no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) 663 - IEEE80211_COUNTRY_STRING_LEN) 664 / sizeof(struct ieee80211_country_ie_triplet)); 665 666 dev_dbg(priv->adapter->dev, 667 "info: 11D Domain Info Resp: no_of_triplet=%d\n", 668 no_of_triplet); 669 670 if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { 671 dev_warn(priv->adapter->dev, 672 "11D: invalid number of triplets %d returned\n", 673 no_of_triplet); 674 return -1; 675 } 676 677 switch (action) { 678 case HostCmd_ACT_GEN_SET: /* Proc Set Action */ 679 break; 680 case HostCmd_ACT_GEN_GET: 681 break; 682 default: 683 dev_err(priv->adapter->dev, 684 "11D: invalid action:%d\n", domain_info->action); 685 return -1; 686 } 687 688 return 0; 689} 690 691/* 692 * This function handles the command response of get extended version. 693 * 694 * Handling includes forming the extended version string and sending it 695 * to application. 696 */ 697static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, 698 struct host_cmd_ds_command *resp, 699 struct host_cmd_ds_version_ext *version_ext) 700{ 701 struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; 702 703 if (version_ext) { 704 version_ext->version_str_sel = ver_ext->version_str_sel; 705 memcpy(version_ext->version_str, ver_ext->version_str, 706 sizeof(char) * 128); 707 memcpy(priv->version_str, ver_ext->version_str, 128); 708 } 709 return 0; 710} 711 712/* 713 * This function handles the command response of remain on channel. 714 */ 715static int 716mwifiex_ret_remain_on_chan(struct mwifiex_private *priv, 717 struct host_cmd_ds_command *resp, 718 struct host_cmd_ds_remain_on_chan *roc_cfg) 719{ 720 struct host_cmd_ds_remain_on_chan *resp_cfg = &resp->params.roc_cfg; 721 722 if (roc_cfg) 723 memcpy(roc_cfg, resp_cfg, sizeof(*roc_cfg)); 724 725 return 0; 726} 727 728/* 729 * This function handles the command response of P2P mode cfg. 730 */ 731static int 732mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv, 733 struct host_cmd_ds_command *resp, 734 void *data_buf) 735{ 736 struct host_cmd_ds_p2p_mode_cfg *mode_cfg = &resp->params.mode_cfg; 737 738 if (data_buf) 739 *((u16 *)data_buf) = le16_to_cpu(mode_cfg->mode); 740 741 return 0; 742} 743 744/* 745 * This function handles the command response of register access. 746 * 747 * The register value and offset are returned to the user. For EEPROM 748 * access, the byte count is also returned. 749 */ 750static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, 751 void *data_buf) 752{ 753 struct mwifiex_ds_reg_rw *reg_rw; 754 struct mwifiex_ds_read_eeprom *eeprom; 755 union reg { 756 struct host_cmd_ds_mac_reg_access *mac; 757 struct host_cmd_ds_bbp_reg_access *bbp; 758 struct host_cmd_ds_rf_reg_access *rf; 759 struct host_cmd_ds_pmic_reg_access *pmic; 760 struct host_cmd_ds_802_11_eeprom_access *eeprom; 761 } r; 762 763 if (!data_buf) 764 return 0; 765 766 reg_rw = data_buf; 767 eeprom = data_buf; 768 switch (type) { 769 case HostCmd_CMD_MAC_REG_ACCESS: 770 r.mac = &resp->params.mac_reg; 771 reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.mac->offset)); 772 reg_rw->value = r.mac->value; 773 break; 774 case HostCmd_CMD_BBP_REG_ACCESS: 775 r.bbp = &resp->params.bbp_reg; 776 reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.bbp->offset)); 777 reg_rw->value = cpu_to_le32((u32) r.bbp->value); 778 break; 779 780 case HostCmd_CMD_RF_REG_ACCESS: 781 r.rf = &resp->params.rf_reg; 782 reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset)); 783 reg_rw->value = cpu_to_le32((u32) r.bbp->value); 784 break; 785 case HostCmd_CMD_PMIC_REG_ACCESS: 786 r.pmic = &resp->params.pmic_reg; 787 reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.pmic->offset)); 788 reg_rw->value = cpu_to_le32((u32) r.pmic->value); 789 break; 790 case HostCmd_CMD_CAU_REG_ACCESS: 791 r.rf = &resp->params.rf_reg; 792 reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset)); 793 reg_rw->value = cpu_to_le32((u32) r.rf->value); 794 break; 795 case HostCmd_CMD_802_11_EEPROM_ACCESS: 796 r.eeprom = &resp->params.eeprom; 797 pr_debug("info: EEPROM read len=%x\n", r.eeprom->byte_count); 798 if (le16_to_cpu(eeprom->byte_count) < 799 le16_to_cpu(r.eeprom->byte_count)) { 800 eeprom->byte_count = cpu_to_le16(0); 801 pr_debug("info: EEPROM read length is too big\n"); 802 return -1; 803 } 804 eeprom->offset = r.eeprom->offset; 805 eeprom->byte_count = r.eeprom->byte_count; 806 if (le16_to_cpu(eeprom->byte_count) > 0) 807 memcpy(&eeprom->value, &r.eeprom->value, 808 le16_to_cpu(r.eeprom->byte_count)); 809 810 break; 811 default: 812 return -1; 813 } 814 return 0; 815} 816 817/* 818 * This function handles the command response of get IBSS coalescing status. 819 * 820 * If the received BSSID is different than the current one, the current BSSID, 821 * beacon interval, ATIM window and ERP information are updated, along with 822 * changing the ad-hoc state accordingly. 823 */ 824static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, 825 struct host_cmd_ds_command *resp) 826{ 827 struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = 828 &(resp->params.ibss_coalescing); 829 830 if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) 831 return 0; 832 833 dev_dbg(priv->adapter->dev, 834 "info: new BSSID %pM\n", ibss_coal_resp->bssid); 835 836 /* If rsp has NULL BSSID, Just return..... No Action */ 837 if (is_zero_ether_addr(ibss_coal_resp->bssid)) { 838 dev_warn(priv->adapter->dev, "new BSSID is NULL\n"); 839 return 0; 840 } 841 842 /* If BSSID is diff, modify current BSS parameters */ 843 if (!ether_addr_equal(priv->curr_bss_params.bss_descriptor.mac_address, ibss_coal_resp->bssid)) { 844 /* BSSID */ 845 memcpy(priv->curr_bss_params.bss_descriptor.mac_address, 846 ibss_coal_resp->bssid, ETH_ALEN); 847 848 /* Beacon Interval */ 849 priv->curr_bss_params.bss_descriptor.beacon_period 850 = le16_to_cpu(ibss_coal_resp->beacon_interval); 851 852 /* ERP Information */ 853 priv->curr_bss_params.bss_descriptor.erp_flags = 854 (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); 855 856 priv->adhoc_state = ADHOC_COALESCED; 857 } 858 859 return 0; 860} 861static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv, 862 struct host_cmd_ds_command *resp) 863{ 864 struct host_cmd_ds_tdls_oper *cmd_tdls_oper = &resp->params.tdls_oper; 865 u16 reason = le16_to_cpu(cmd_tdls_oper->reason); 866 u16 action = le16_to_cpu(cmd_tdls_oper->tdls_action); 867 struct mwifiex_sta_node *node = 868 mwifiex_get_sta_entry(priv, cmd_tdls_oper->peer_mac); 869 870 switch (action) { 871 case ACT_TDLS_DELETE: 872 if (reason) { 873 if (!node || reason == TDLS_ERR_LINK_NONEXISTENT) 874 dev_dbg(priv->adapter->dev, 875 "TDLS link delete for %pM failed: reason %d\n", 876 cmd_tdls_oper->peer_mac, reason); 877 else 878 dev_err(priv->adapter->dev, 879 "TDLS link delete for %pM failed: reason %d\n", 880 cmd_tdls_oper->peer_mac, reason); 881 } else { 882 dev_dbg(priv->adapter->dev, 883 "TDLS link delete for %pM successful\n", 884 cmd_tdls_oper->peer_mac); 885 } 886 break; 887 case ACT_TDLS_CREATE: 888 if (reason) { 889 dev_err(priv->adapter->dev, 890 "TDLS link creation for %pM failed: reason %d", 891 cmd_tdls_oper->peer_mac, reason); 892 if (node && reason != TDLS_ERR_LINK_EXISTS) 893 node->tdls_status = TDLS_SETUP_FAILURE; 894 } else { 895 dev_dbg(priv->adapter->dev, 896 "TDLS link creation for %pM successful", 897 cmd_tdls_oper->peer_mac); 898 } 899 break; 900 case ACT_TDLS_CONFIG: 901 if (reason) { 902 dev_err(priv->adapter->dev, 903 "TDLS link config for %pM failed, reason %d\n", 904 cmd_tdls_oper->peer_mac, reason); 905 if (node) 906 node->tdls_status = TDLS_SETUP_FAILURE; 907 } else { 908 dev_dbg(priv->adapter->dev, 909 "TDLS link config for %pM successful\n", 910 cmd_tdls_oper->peer_mac); 911 } 912 break; 913 default: 914 dev_err(priv->adapter->dev, 915 "Unknown TDLS command action response %d", action); 916 return -1; 917 } 918 919 return 0; 920} 921/* 922 * This function handles the command response for subscribe event command. 923 */ 924static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv, 925 struct host_cmd_ds_command *resp) 926{ 927 struct host_cmd_ds_802_11_subsc_evt *cmd_sub_event = 928 &resp->params.subsc_evt; 929 930 /* For every subscribe event command (Get/Set/Clear), FW reports the 931 * current set of subscribed events*/ 932 dev_dbg(priv->adapter->dev, "Bitmap of currently subscribed events: %16x\n", 933 le16_to_cpu(cmd_sub_event->events)); 934 935 return 0; 936} 937 938/* This function handles the command response of set_cfg_data */ 939static int mwifiex_ret_cfg_data(struct mwifiex_private *priv, 940 struct host_cmd_ds_command *resp) 941{ 942 if (resp->result != HostCmd_RESULT_OK) { 943 dev_err(priv->adapter->dev, "Cal data cmd resp failed\n"); 944 return -1; 945 } 946 947 return 0; 948} 949 950/** This Function handles the command response of sdio rx aggr */ 951static int mwifiex_ret_sdio_rx_aggr_cfg(struct mwifiex_private *priv, 952 struct host_cmd_ds_command *resp) 953{ 954 struct mwifiex_adapter *adapter = priv->adapter; 955 struct host_cmd_sdio_sp_rx_aggr_cfg *cfg = 956 &resp->params.sdio_rx_aggr_cfg; 957 958 adapter->sdio_rx_aggr_enable = cfg->enable; 959 adapter->sdio_rx_block_size = le16_to_cpu(cfg->block_size); 960 961 return 0; 962} 963 964/* 965 * This function handles the command responses. 966 * 967 * This is a generic function, which calls command specific 968 * response handlers based on the command ID. 969 */ 970int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, 971 struct host_cmd_ds_command *resp) 972{ 973 int ret = 0; 974 struct mwifiex_adapter *adapter = priv->adapter; 975 void *data_buf = adapter->curr_cmd->data_buf; 976 977 /* If the command is not successful, cleanup and return failure */ 978 if (resp->result != HostCmd_RESULT_OK) { 979 mwifiex_process_cmdresp_error(priv, resp); 980 return -1; 981 } 982 /* Command successful, handle response */ 983 switch (cmdresp_no) { 984 case HostCmd_CMD_GET_HW_SPEC: 985 ret = mwifiex_ret_get_hw_spec(priv, resp); 986 break; 987 case HostCmd_CMD_CFG_DATA: 988 ret = mwifiex_ret_cfg_data(priv, resp); 989 break; 990 case HostCmd_CMD_MAC_CONTROL: 991 break; 992 case HostCmd_CMD_802_11_MAC_ADDRESS: 993 ret = mwifiex_ret_802_11_mac_address(priv, resp); 994 break; 995 case HostCmd_CMD_MAC_MULTICAST_ADR: 996 ret = mwifiex_ret_mac_multicast_adr(priv, resp); 997 break; 998 case HostCmd_CMD_TX_RATE_CFG: 999 ret = mwifiex_ret_tx_rate_cfg(priv, resp); 1000 break; 1001 case HostCmd_CMD_802_11_SCAN: 1002 ret = mwifiex_ret_802_11_scan(priv, resp); 1003 adapter->curr_cmd->wait_q_enabled = false; 1004 break; 1005 case HostCmd_CMD_802_11_SCAN_EXT: 1006 ret = mwifiex_ret_802_11_scan_ext(priv, resp); 1007 adapter->curr_cmd->wait_q_enabled = false; 1008 break; 1009 case HostCmd_CMD_802_11_BG_SCAN_QUERY: 1010 ret = mwifiex_ret_802_11_scan(priv, resp); 1011 dev_dbg(adapter->dev, 1012 "info: CMD_RESP: BG_SCAN result is ready!\n"); 1013 break; 1014 case HostCmd_CMD_TXPWR_CFG: 1015 ret = mwifiex_ret_tx_power_cfg(priv, resp); 1016 break; 1017 case HostCmd_CMD_RF_TX_PWR: 1018 ret = mwifiex_ret_rf_tx_power(priv, resp); 1019 break; 1020 case HostCmd_CMD_RF_ANTENNA: 1021 ret = mwifiex_ret_rf_antenna(priv, resp); 1022 break; 1023 case HostCmd_CMD_802_11_PS_MODE_ENH: 1024 ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); 1025 break; 1026 case HostCmd_CMD_802_11_HS_CFG_ENH: 1027 ret = mwifiex_ret_802_11_hs_cfg(priv, resp); 1028 break; 1029 case HostCmd_CMD_802_11_ASSOCIATE: 1030 ret = mwifiex_ret_802_11_associate(priv, resp); 1031 break; 1032 case HostCmd_CMD_802_11_DEAUTHENTICATE: 1033 ret = mwifiex_ret_802_11_deauthenticate(priv, resp); 1034 break; 1035 case HostCmd_CMD_802_11_AD_HOC_START: 1036 case HostCmd_CMD_802_11_AD_HOC_JOIN: 1037 ret = mwifiex_ret_802_11_ad_hoc(priv, resp); 1038 break; 1039 case HostCmd_CMD_802_11_AD_HOC_STOP: 1040 ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); 1041 break; 1042 case HostCmd_CMD_802_11_GET_LOG: 1043 ret = mwifiex_ret_get_log(priv, resp, data_buf); 1044 break; 1045 case HostCmd_CMD_RSSI_INFO: 1046 ret = mwifiex_ret_802_11_rssi_info(priv, resp); 1047 break; 1048 case HostCmd_CMD_802_11_SNMP_MIB: 1049 ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); 1050 break; 1051 case HostCmd_CMD_802_11_TX_RATE_QUERY: 1052 ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); 1053 break; 1054 case HostCmd_CMD_VERSION_EXT: 1055 ret = mwifiex_ret_ver_ext(priv, resp, data_buf); 1056 break; 1057 case HostCmd_CMD_REMAIN_ON_CHAN: 1058 ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf); 1059 break; 1060 case HostCmd_CMD_11AC_CFG: 1061 break; 1062 case HostCmd_CMD_P2P_MODE_CFG: 1063 ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf); 1064 break; 1065 case HostCmd_CMD_MGMT_FRAME_REG: 1066 case HostCmd_CMD_FUNC_INIT: 1067 case HostCmd_CMD_FUNC_SHUTDOWN: 1068 break; 1069 case HostCmd_CMD_802_11_KEY_MATERIAL: 1070 ret = mwifiex_ret_802_11_key_material(priv, resp); 1071 break; 1072 case HostCmd_CMD_802_11D_DOMAIN_INFO: 1073 ret = mwifiex_ret_802_11d_domain_info(priv, resp); 1074 break; 1075 case HostCmd_CMD_11N_ADDBA_REQ: 1076 ret = mwifiex_ret_11n_addba_req(priv, resp); 1077 break; 1078 case HostCmd_CMD_11N_DELBA: 1079 ret = mwifiex_ret_11n_delba(priv, resp); 1080 break; 1081 case HostCmd_CMD_11N_ADDBA_RSP: 1082 ret = mwifiex_ret_11n_addba_resp(priv, resp); 1083 break; 1084 case HostCmd_CMD_RECONFIGURE_TX_BUFF: 1085 adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. 1086 tx_buf.buff_size); 1087 adapter->tx_buf_size = (adapter->tx_buf_size 1088 / MWIFIEX_SDIO_BLOCK_SIZE) 1089 * MWIFIEX_SDIO_BLOCK_SIZE; 1090 adapter->curr_tx_buf_size = adapter->tx_buf_size; 1091 dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n", 1092 adapter->curr_tx_buf_size); 1093 1094 if (adapter->if_ops.update_mp_end_port) 1095 adapter->if_ops.update_mp_end_port(adapter, 1096 le16_to_cpu(resp->params.tx_buf.mp_end_port)); 1097 break; 1098 case HostCmd_CMD_AMSDU_AGGR_CTRL: 1099 break; 1100 case HostCmd_CMD_WMM_GET_STATUS: 1101 ret = mwifiex_ret_wmm_get_status(priv, resp); 1102 break; 1103 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: 1104 ret = mwifiex_ret_ibss_coalescing_status(priv, resp); 1105 break; 1106 case HostCmd_CMD_MAC_REG_ACCESS: 1107 case HostCmd_CMD_BBP_REG_ACCESS: 1108 case HostCmd_CMD_RF_REG_ACCESS: 1109 case HostCmd_CMD_PMIC_REG_ACCESS: 1110 case HostCmd_CMD_CAU_REG_ACCESS: 1111 case HostCmd_CMD_802_11_EEPROM_ACCESS: 1112 ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); 1113 break; 1114 case HostCmd_CMD_SET_BSS_MODE: 1115 break; 1116 case HostCmd_CMD_11N_CFG: 1117 break; 1118 case HostCmd_CMD_PCIE_DESC_DETAILS: 1119 break; 1120 case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: 1121 ret = mwifiex_ret_subsc_evt(priv, resp); 1122 break; 1123 case HostCmd_CMD_UAP_SYS_CONFIG: 1124 break; 1125 case HostCmd_CMD_UAP_BSS_START: 1126 adapter->tx_lock_flag = false; 1127 adapter->pps_uapsd_mode = false; 1128 adapter->delay_null_pkt = false; 1129 priv->bss_started = 1; 1130 break; 1131 case HostCmd_CMD_UAP_BSS_STOP: 1132 priv->bss_started = 0; 1133 break; 1134 case HostCmd_CMD_UAP_STA_DEAUTH: 1135 break; 1136 case HostCmd_CMD_MEF_CFG: 1137 break; 1138 case HostCmd_CMD_COALESCE_CFG: 1139 break; 1140 case HostCmd_CMD_TDLS_OPER: 1141 ret = mwifiex_ret_tdls_oper(priv, resp); 1142 break; 1143 case HostCmd_CMD_CHAN_REPORT_REQUEST: 1144 break; 1145 case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: 1146 ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); 1147 break; 1148 default: 1149 dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", 1150 resp->command); 1151 break; 1152 } 1153 1154 return ret; 1155} 1156