1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * NXP Wireless LAN device driver: station command response handling 4 * 5 * Copyright 2011-2020 NXP 6 */ 7 8 #include "decl.h" 9 #include "ioctl.h" 10 #include "util.h" 11 #include "fw.h" 12 #include "main.h" 13 #include "wmm.h" 14 #include "11n.h" 15 #include "11ac.h" 16 17 18 /* 19 * This function handles the command response error case. 20 * 21 * For scan response error, the function cancels all the pending 22 * scan commands and generates an event to inform the applications 23 * of the scan completion. 24 * 25 * For Power Save command failure, we do not retry enter PS 26 * command in case of Ad-hoc mode. 27 * 28 * For all other response errors, the current command buffer is freed 29 * and returned to the free command queue. 30 */ 31 static void 32 mwifiex_process_cmdresp_error(struct mwifiex_private *priv, 33 struct host_cmd_ds_command *resp) 34 { 35 struct mwifiex_adapter *adapter = priv->adapter; 36 struct host_cmd_ds_802_11_ps_mode_enh *pm; 37 38 mwifiex_dbg(adapter, ERROR, 39 "CMD_RESP: cmd %#x error, result=%#x\n", 40 resp->command, resp->result); 41 42 if (adapter->curr_cmd->wait_q_enabled) 43 adapter->cmd_wait_q.status = -1; 44 45 switch (le16_to_cpu(resp->command)) { 46 case HostCmd_CMD_802_11_PS_MODE_ENH: 47 pm = &resp->params.psmode_enh; 48 mwifiex_dbg(adapter, ERROR, 49 "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n", 50 resp->result, le16_to_cpu(pm->action)); 51 /* We do not re-try enter-ps command in ad-hoc mode. */ 52 if (le16_to_cpu(pm->action) == EN_AUTO_PS && 53 (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && 54 priv->bss_mode == NL80211_IFTYPE_ADHOC) 55 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; 56 57 break; 58 case HostCmd_CMD_802_11_SCAN: 59 case HostCmd_CMD_802_11_SCAN_EXT: 60 mwifiex_cancel_scan(adapter); 61 break; 62 63 case HostCmd_CMD_MAC_CONTROL: 64 break; 65 66 case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: 67 mwifiex_dbg(adapter, MSG, 68 "SDIO RX single-port aggregation Not support\n"); 69 break; 70 71 default: 72 break; 73 } 74 /* Handling errors here */ 75 mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd); 76 77 spin_lock_bh(&adapter->mwifiex_cmd_lock); 78 adapter->curr_cmd = NULL; 79 spin_unlock_bh(&adapter->mwifiex_cmd_lock); 80 } 81 82 /* 83 * This function handles the command response of get RSSI info. 84 * 85 * Handling includes changing the header fields into CPU format 86 * and saving the following parameters in driver - 87 * - Last data and beacon RSSI value 88 * - Average data and beacon RSSI value 89 * - Last data and beacon NF value 90 * - Average data and beacon NF value 91 * 92 * The parameters are send to the application as well, along with 93 * calculated SNR values. 94 */ 95 static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, 96 struct host_cmd_ds_command *resp) 97 { 98 struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = 99 &resp->params.rssi_info_rsp; 100 struct mwifiex_ds_misc_subsc_evt *subsc_evt = 101 &priv->async_subsc_evt_storage; 102 103 priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); 104 priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); 105 106 priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg); 107 priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg); 108 109 priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last); 110 priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last); 111 112 priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg); 113 priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); 114 115 if (priv->subsc_evt_rssi_state == EVENT_HANDLED) 116 return 0; 117 118 memset(subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt)); 119 120 /* Resubscribe low and high rssi events with new thresholds */ 121 subsc_evt->events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; 122 subsc_evt->action = HostCmd_ACT_BITWISE_SET; 123 if (priv->subsc_evt_rssi_state == RSSI_LOW_RECVD) { 124 subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg - 125 priv->cqm_rssi_hyst); 126 subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold); 127 } else if (priv->subsc_evt_rssi_state == RSSI_HIGH_RECVD) { 128 subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold); 129 subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg + 130 priv->cqm_rssi_hyst); 131 } 132 subsc_evt->bcn_l_rssi_cfg.evt_freq = 1; 133 subsc_evt->bcn_h_rssi_cfg.evt_freq = 1; 134 135 priv->subsc_evt_rssi_state = EVENT_HANDLED; 136 137 mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 138 0, 0, subsc_evt, false); 139 140 return 0; 141 } 142 143 /* 144 * This function handles the command response of set/get SNMP 145 * MIB parameters. 146 * 147 * Handling includes changing the header fields into CPU format 148 * and saving the parameter in driver. 149 * 150 * The following parameters are supported - 151 * - Fragmentation threshold 152 * - RTS threshold 153 * - Short retry limit 154 */ 155 static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, 156 struct host_cmd_ds_command *resp, 157 u32 *data_buf) 158 { 159 struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; 160 u16 oid = le16_to_cpu(smib->oid); 161 u16 query_type = le16_to_cpu(smib->query_type); 162 u32 ul_temp; 163 164 mwifiex_dbg(priv->adapter, INFO, 165 "info: SNMP_RESP: oid value = %#x,\t" 166 "query_type = %#x, buf size = %#x\n", 167 oid, query_type, le16_to_cpu(smib->buf_size)); 168 if (query_type == HostCmd_ACT_GEN_GET) { 169 ul_temp = get_unaligned_le16(smib->value); 170 if (data_buf) 171 *data_buf = ul_temp; 172 switch (oid) { 173 case FRAG_THRESH_I: 174 mwifiex_dbg(priv->adapter, INFO, 175 "info: SNMP_RESP: FragThsd =%u\n", 176 ul_temp); 177 break; 178 case RTS_THRESH_I: 179 mwifiex_dbg(priv->adapter, INFO, 180 "info: SNMP_RESP: RTSThsd =%u\n", 181 ul_temp); 182 break; 183 case SHORT_RETRY_LIM_I: 184 mwifiex_dbg(priv->adapter, INFO, 185 "info: SNMP_RESP: TxRetryCount=%u\n", 186 ul_temp); 187 break; 188 case DTIM_PERIOD_I: 189 mwifiex_dbg(priv->adapter, INFO, 190 "info: SNMP_RESP: DTIM period=%u\n", 191 ul_temp); 192 break; 193 default: 194 break; 195 } 196 } 197 198 return 0; 199 } 200 201 /* 202 * This function handles the command response of get log request 203 * 204 * Handling includes changing the header fields into CPU format 205 * and sending the received parameters to application. 206 */ 207 static int mwifiex_ret_get_log(struct mwifiex_private *priv, 208 struct host_cmd_ds_command *resp, 209 struct mwifiex_ds_get_stats *stats) 210 { 211 struct host_cmd_ds_802_11_get_log *get_log = 212 &resp->params.get_log; 213 214 if (stats) { 215 stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); 216 stats->failed = le32_to_cpu(get_log->failed); 217 stats->retry = le32_to_cpu(get_log->retry); 218 stats->multi_retry = le32_to_cpu(get_log->multi_retry); 219 stats->frame_dup = le32_to_cpu(get_log->frame_dup); 220 stats->rts_success = le32_to_cpu(get_log->rts_success); 221 stats->rts_failure = le32_to_cpu(get_log->rts_failure); 222 stats->ack_failure = le32_to_cpu(get_log->ack_failure); 223 stats->rx_frag = le32_to_cpu(get_log->rx_frag); 224 stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); 225 stats->fcs_error = le32_to_cpu(get_log->fcs_error); 226 stats->tx_frame = le32_to_cpu(get_log->tx_frame); 227 stats->wep_icv_error[0] = 228 le32_to_cpu(get_log->wep_icv_err_cnt[0]); 229 stats->wep_icv_error[1] = 230 le32_to_cpu(get_log->wep_icv_err_cnt[1]); 231 stats->wep_icv_error[2] = 232 le32_to_cpu(get_log->wep_icv_err_cnt[2]); 233 stats->wep_icv_error[3] = 234 le32_to_cpu(get_log->wep_icv_err_cnt[3]); 235 stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt); 236 stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt); 237 } 238 239 return 0; 240 } 241 242 /* 243 * This function handles the command response of set/get Tx rate 244 * configurations. 245 * 246 * Handling includes changing the header fields into CPU format 247 * and saving the following parameters in driver - 248 * - DSSS rate bitmap 249 * - OFDM rate bitmap 250 * - HT MCS rate bitmaps 251 * 252 * Based on the new rate bitmaps, the function re-evaluates if 253 * auto data rate has been activated. If not, it sends another 254 * query to the firmware to get the current Tx data rate. 255 */ 256 static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, 257 struct host_cmd_ds_command *resp) 258 { 259 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; 260 struct mwifiex_rate_scope *rate_scope; 261 struct mwifiex_ie_types_header *head; 262 u16 tlv, tlv_buf_len, tlv_buf_left; 263 u8 *tlv_buf; 264 u32 i; 265 266 tlv_buf = ((u8 *)rate_cfg) + sizeof(struct host_cmd_ds_tx_rate_cfg); 267 tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*rate_cfg); 268 269 while (tlv_buf_left >= sizeof(*head)) { 270 head = (struct mwifiex_ie_types_header *)tlv_buf; 271 tlv = le16_to_cpu(head->type); 272 tlv_buf_len = le16_to_cpu(head->len); 273 274 if (tlv_buf_left < (sizeof(*head) + tlv_buf_len)) 275 break; 276 277 switch (tlv) { 278 case TLV_TYPE_RATE_SCOPE: 279 rate_scope = (struct mwifiex_rate_scope *) tlv_buf; 280 priv->bitmap_rates[0] = 281 le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); 282 priv->bitmap_rates[1] = 283 le16_to_cpu(rate_scope->ofdm_rate_bitmap); 284 for (i = 0; 285 i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); 286 i++) 287 priv->bitmap_rates[2 + i] = 288 le16_to_cpu(rate_scope-> 289 ht_mcs_rate_bitmap[i]); 290 291 if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { 292 for (i = 0; i < ARRAY_SIZE(rate_scope-> 293 vht_mcs_rate_bitmap); 294 i++) 295 priv->bitmap_rates[10 + i] = 296 le16_to_cpu(rate_scope-> 297 vht_mcs_rate_bitmap[i]); 298 } 299 break; 300 /* Add RATE_DROP tlv here */ 301 } 302 303 tlv_buf += (sizeof(*head) + tlv_buf_len); 304 tlv_buf_left -= (sizeof(*head) + tlv_buf_len); 305 } 306 307 priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); 308 309 if (priv->is_data_rate_auto) 310 priv->data_rate = 0; 311 else 312 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, 313 HostCmd_ACT_GEN_GET, 0, NULL, false); 314 315 return 0; 316 } 317 318 /* 319 * This function handles the command response of get Tx power level. 320 * 321 * Handling includes saving the maximum and minimum Tx power levels 322 * in driver, as well as sending the values to user. 323 */ 324 static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) 325 { 326 int length, max_power = -1, min_power = -1; 327 struct mwifiex_types_power_group *pg_tlv_hdr; 328 struct mwifiex_power_group *pg; 329 330 if (!data_buf) 331 return -1; 332 333 pg_tlv_hdr = (struct mwifiex_types_power_group *)((u8 *)data_buf); 334 pg = (struct mwifiex_power_group *) 335 ((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group)); 336 length = le16_to_cpu(pg_tlv_hdr->length); 337 338 /* At least one structure required to update power */ 339 if (length < sizeof(struct mwifiex_power_group)) 340 return 0; 341 342 max_power = pg->power_max; 343 min_power = pg->power_min; 344 length -= sizeof(struct mwifiex_power_group); 345 346 while (length >= sizeof(struct mwifiex_power_group)) { 347 pg++; 348 if (max_power < pg->power_max) 349 max_power = pg->power_max; 350 351 if (min_power > pg->power_min) 352 min_power = pg->power_min; 353 354 length -= sizeof(struct mwifiex_power_group); 355 } 356 priv->min_tx_power_level = (u8) min_power; 357 priv->max_tx_power_level = (u8) max_power; 358 359 return 0; 360 } 361 362 /* 363 * This function handles the command response of set/get Tx power 364 * configurations. 365 * 366 * Handling includes changing the header fields into CPU format 367 * and saving the current Tx power level in driver. 368 */ 369 static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, 370 struct host_cmd_ds_command *resp) 371 { 372 struct mwifiex_adapter *adapter = priv->adapter; 373 struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; 374 struct mwifiex_types_power_group *pg_tlv_hdr; 375 struct mwifiex_power_group *pg; 376 u16 action = le16_to_cpu(txp_cfg->action); 377 u16 tlv_buf_left; 378 379 pg_tlv_hdr = (struct mwifiex_types_power_group *) 380 ((u8 *)txp_cfg + 381 sizeof(struct host_cmd_ds_txpwr_cfg)); 382 383 pg = (struct mwifiex_power_group *) 384 ((u8 *)pg_tlv_hdr + 385 sizeof(struct mwifiex_types_power_group)); 386 387 tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*txp_cfg); 388 if (tlv_buf_left < 389 le16_to_cpu(pg_tlv_hdr->length) + sizeof(*pg_tlv_hdr)) 390 return 0; 391 392 switch (action) { 393 case HostCmd_ACT_GEN_GET: 394 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) 395 mwifiex_get_power_level(priv, pg_tlv_hdr); 396 397 priv->tx_power_level = (u16) pg->power_min; 398 break; 399 400 case HostCmd_ACT_GEN_SET: 401 if (!le32_to_cpu(txp_cfg->mode)) 402 break; 403 404 if (pg->power_max == pg->power_min) 405 priv->tx_power_level = (u16) pg->power_min; 406 break; 407 default: 408 mwifiex_dbg(adapter, ERROR, 409 "CMD_RESP: unknown cmd action %d\n", 410 action); 411 return 0; 412 } 413 mwifiex_dbg(adapter, INFO, 414 "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", 415 priv->tx_power_level, priv->max_tx_power_level, 416 priv->min_tx_power_level); 417 418 return 0; 419 } 420 421 /* 422 * This function handles the command response of get RF Tx power. 423 */ 424 static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv, 425 struct host_cmd_ds_command *resp) 426 { 427 struct host_cmd_ds_rf_tx_pwr *txp = &resp->params.txp; 428 u16 action = le16_to_cpu(txp->action); 429 430 priv->tx_power_level = le16_to_cpu(txp->cur_level); 431 432 if (action == HostCmd_ACT_GEN_GET) { 433 priv->max_tx_power_level = txp->max_power; 434 priv->min_tx_power_level = txp->min_power; 435 } 436 437 mwifiex_dbg(priv->adapter, INFO, 438 "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n", 439 priv->tx_power_level, priv->max_tx_power_level, 440 priv->min_tx_power_level); 441 442 return 0; 443 } 444 445 /* 446 * This function handles the command response of set rf antenna 447 */ 448 static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv, 449 struct host_cmd_ds_command *resp) 450 { 451 struct host_cmd_ds_rf_ant_mimo *ant_mimo = &resp->params.ant_mimo; 452 struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso; 453 struct mwifiex_adapter *adapter = priv->adapter; 454 455 if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) { 456 priv->tx_ant = le16_to_cpu(ant_mimo->tx_ant_mode); 457 priv->rx_ant = le16_to_cpu(ant_mimo->rx_ant_mode); 458 mwifiex_dbg(adapter, INFO, 459 "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t" 460 "Rx action = 0x%x, Rx Mode = 0x%04x\n", 461 le16_to_cpu(ant_mimo->action_tx), 462 le16_to_cpu(ant_mimo->tx_ant_mode), 463 le16_to_cpu(ant_mimo->action_rx), 464 le16_to_cpu(ant_mimo->rx_ant_mode)); 465 } else { 466 priv->tx_ant = le16_to_cpu(ant_siso->ant_mode); 467 priv->rx_ant = le16_to_cpu(ant_siso->ant_mode); 468 mwifiex_dbg(adapter, INFO, 469 "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n", 470 le16_to_cpu(ant_siso->action), 471 le16_to_cpu(ant_siso->ant_mode)); 472 } 473 return 0; 474 } 475 476 /* 477 * This function handles the command response of set/get MAC address. 478 * 479 * Handling includes saving the MAC address in driver. 480 */ 481 static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, 482 struct host_cmd_ds_command *resp) 483 { 484 struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = 485 &resp->params.mac_addr; 486 487 memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); 488 489 mwifiex_dbg(priv->adapter, INFO, 490 "info: set mac address: %pM\n", priv->curr_addr); 491 492 return 0; 493 } 494 495 /* 496 * This function handles the command response of set/get MAC multicast 497 * address. 498 */ 499 static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, 500 struct host_cmd_ds_command *resp) 501 { 502 return 0; 503 } 504 505 /* 506 * This function handles the command response of get Tx rate query. 507 * 508 * Handling includes changing the header fields into CPU format 509 * and saving the Tx rate and HT information parameters in driver. 510 * 511 * Both rate configuration and current data rate can be retrieved 512 * with this request. 513 */ 514 static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, 515 struct host_cmd_ds_command *resp) 516 { 517 priv->tx_rate = resp->params.tx_rate.tx_rate; 518 priv->tx_htinfo = resp->params.tx_rate.ht_info; 519 if (!priv->is_data_rate_auto) 520 priv->data_rate = 521 mwifiex_index_to_data_rate(priv, priv->tx_rate, 522 priv->tx_htinfo); 523 524 return 0; 525 } 526 527 /* 528 * This function handles the command response of a deauthenticate 529 * command. 530 * 531 * If the deauthenticated MAC matches the current BSS MAC, the connection 532 * state is reset. 533 */ 534 static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, 535 struct host_cmd_ds_command *resp) 536 { 537 struct mwifiex_adapter *adapter = priv->adapter; 538 539 adapter->dbg.num_cmd_deauth++; 540 if (!memcmp(resp->params.deauth.mac_addr, 541 &priv->curr_bss_params.bss_descriptor.mac_address, 542 sizeof(resp->params.deauth.mac_addr))) 543 mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING, 544 false); 545 546 return 0; 547 } 548 549 /* 550 * This function handles the command response of ad-hoc stop. 551 * 552 * The function resets the connection state in driver. 553 */ 554 static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, 555 struct host_cmd_ds_command *resp) 556 { 557 mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING, false); 558 return 0; 559 } 560 561 /* 562 * This function handles the command response of set/get v1 key material. 563 * 564 * Handling includes updating the driver parameters to reflect the 565 * changes. 566 */ 567 static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, 568 struct host_cmd_ds_command *resp) 569 { 570 struct host_cmd_ds_802_11_key_material *key = 571 &resp->params.key_material; 572 int len; 573 574 len = le16_to_cpu(key->key_param_set.key_len); 575 if (len > sizeof(key->key_param_set.key)) 576 return -EINVAL; 577 578 if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { 579 if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) { 580 mwifiex_dbg(priv->adapter, INFO, 581 "info: key: GTK is set\n"); 582 priv->wpa_is_gtk_set = true; 583 priv->scan_block = false; 584 priv->port_open = true; 585 } 586 } 587 588 memset(priv->aes_key.key_param_set.key, 0, 589 sizeof(key->key_param_set.key)); 590 priv->aes_key.key_param_set.key_len = cpu_to_le16(len); 591 memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, len); 592 593 return 0; 594 } 595 596 /* 597 * This function handles the command response of set/get v2 key material. 598 * 599 * Handling includes updating the driver parameters to reflect the 600 * changes. 601 */ 602 static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, 603 struct host_cmd_ds_command *resp) 604 { 605 struct host_cmd_ds_802_11_key_material_v2 *key_v2; 606 int len; 607 608 key_v2 = &resp->params.key_material_v2; 609 610 len = le16_to_cpu(key_v2->key_param_set.key_params.aes.key_len); 611 if (len > sizeof(key_v2->key_param_set.key_params.aes.key)) 612 return -EINVAL; 613 614 if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) { 615 if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) { 616 mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n"); 617 priv->wpa_is_gtk_set = true; 618 priv->scan_block = false; 619 priv->port_open = true; 620 } 621 } 622 623 if (key_v2->key_param_set.key_type != KEY_TYPE_ID_AES) 624 return 0; 625 626 memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0, 627 sizeof(key_v2->key_param_set.key_params.aes.key)); 628 priv->aes_key_v2.key_param_set.key_params.aes.key_len = 629 cpu_to_le16(len); 630 memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key, 631 key_v2->key_param_set.key_params.aes.key, len); 632 633 return 0; 634 } 635 636 /* Wrapper function for processing response of key material command */ 637 static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, 638 struct host_cmd_ds_command *resp) 639 { 640 if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) 641 return mwifiex_ret_802_11_key_material_v2(priv, resp); 642 else 643 return mwifiex_ret_802_11_key_material_v1(priv, resp); 644 } 645 646 /* 647 * This function handles the command response of get 11d domain information. 648 */ 649 static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, 650 struct host_cmd_ds_command *resp) 651 { 652 struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = 653 &resp->params.domain_info_resp; 654 struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; 655 u16 action = le16_to_cpu(domain_info->action); 656 u8 no_of_triplet; 657 658 no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) 659 - IEEE80211_COUNTRY_STRING_LEN) 660 / sizeof(struct ieee80211_country_ie_triplet)); 661 662 mwifiex_dbg(priv->adapter, INFO, 663 "info: 11D Domain Info Resp: no_of_triplet=%d\n", 664 no_of_triplet); 665 666 if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { 667 mwifiex_dbg(priv->adapter, FATAL, 668 "11D: invalid number of triplets %d returned\n", 669 no_of_triplet); 670 return -1; 671 } 672 673 switch (action) { 674 case HostCmd_ACT_GEN_SET: /* Proc Set Action */ 675 break; 676 case HostCmd_ACT_GEN_GET: 677 break; 678 default: 679 mwifiex_dbg(priv->adapter, ERROR, 680 "11D: invalid action:%d\n", domain_info->action); 681 return -1; 682 } 683 684 return 0; 685 } 686 687 /* 688 * This function handles the command response of get extended version. 689 * 690 * Handling includes forming the extended version string and sending it 691 * to application. 692 */ 693 static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, 694 struct host_cmd_ds_command *resp, 695 struct host_cmd_ds_version_ext *version_ext) 696 { 697 struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; 698 699 if (test_and_clear_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &priv->adapter->work_flags)) { 700 if (strncmp(ver_ext->version_str, "ChipRev:20, BB:9b(10.00), RF:40(21)", 701 MWIFIEX_VERSION_STR_LENGTH) == 0) { 702 struct mwifiex_ds_auto_ds auto_ds = { 703 .auto_ds = DEEP_SLEEP_OFF, 704 }; 705 706 mwifiex_dbg(priv->adapter, MSG, 707 "Bad HW revision detected, disabling deep sleep\n"); 708 709 if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, 710 DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, false)) { 711 mwifiex_dbg(priv->adapter, MSG, 712 "Disabling deep sleep failed.\n"); 713 } 714 } 715 716 return 0; 717 } 718 719 if (version_ext) { 720 version_ext->version_str_sel = ver_ext->version_str_sel; 721 memcpy(version_ext->version_str, ver_ext->version_str, 722 MWIFIEX_VERSION_STR_LENGTH); 723 memcpy(priv->version_str, ver_ext->version_str, 724 MWIFIEX_VERSION_STR_LENGTH); 725 726 /* Ensure the version string from the firmware is 0-terminated */ 727 priv->version_str[MWIFIEX_VERSION_STR_LENGTH - 1] = '\0'; 728 } 729 return 0; 730 } 731 732 /* 733 * This function handles the command response of remain on channel. 734 */ 735 static int 736 mwifiex_ret_remain_on_chan(struct mwifiex_private *priv, 737 struct host_cmd_ds_command *resp, 738 struct host_cmd_ds_remain_on_chan *roc_cfg) 739 { 740 struct host_cmd_ds_remain_on_chan *resp_cfg = &resp->params.roc_cfg; 741 742 if (roc_cfg) 743 memcpy(roc_cfg, resp_cfg, sizeof(*roc_cfg)); 744 745 return 0; 746 } 747 748 /* 749 * This function handles the command response of P2P mode cfg. 750 */ 751 static int 752 mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv, 753 struct host_cmd_ds_command *resp, 754 void *data_buf) 755 { 756 struct host_cmd_ds_p2p_mode_cfg *mode_cfg = &resp->params.mode_cfg; 757 758 if (data_buf) 759 put_unaligned_le16(le16_to_cpu(mode_cfg->mode), data_buf); 760 761 return 0; 762 } 763 764 /* This function handles the command response of mem_access command 765 */ 766 static int 767 mwifiex_ret_mem_access(struct mwifiex_private *priv, 768 struct host_cmd_ds_command *resp, void *pioctl_buf) 769 { 770 struct host_cmd_ds_mem_access *mem = (void *)&resp->params.mem; 771 772 priv->mem_rw.addr = le32_to_cpu(mem->addr); 773 priv->mem_rw.value = le32_to_cpu(mem->value); 774 775 return 0; 776 } 777 /* 778 * This function handles the command response of register access. 779 * 780 * The register value and offset are returned to the user. For EEPROM 781 * access, the byte count is also returned. 782 */ 783 static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, 784 void *data_buf) 785 { 786 struct mwifiex_ds_reg_rw *reg_rw; 787 struct mwifiex_ds_read_eeprom *eeprom; 788 union reg { 789 struct host_cmd_ds_mac_reg_access *mac; 790 struct host_cmd_ds_bbp_reg_access *bbp; 791 struct host_cmd_ds_rf_reg_access *rf; 792 struct host_cmd_ds_pmic_reg_access *pmic; 793 struct host_cmd_ds_802_11_eeprom_access *eeprom; 794 } r; 795 796 if (!data_buf) 797 return 0; 798 799 reg_rw = data_buf; 800 eeprom = data_buf; 801 switch (type) { 802 case HostCmd_CMD_MAC_REG_ACCESS: 803 r.mac = &resp->params.mac_reg; 804 reg_rw->offset = (u32) le16_to_cpu(r.mac->offset); 805 reg_rw->value = le32_to_cpu(r.mac->value); 806 break; 807 case HostCmd_CMD_BBP_REG_ACCESS: 808 r.bbp = &resp->params.bbp_reg; 809 reg_rw->offset = (u32) le16_to_cpu(r.bbp->offset); 810 reg_rw->value = (u32) r.bbp->value; 811 break; 812 813 case HostCmd_CMD_RF_REG_ACCESS: 814 r.rf = &resp->params.rf_reg; 815 reg_rw->offset = (u32) le16_to_cpu(r.rf->offset); 816 reg_rw->value = (u32) r.bbp->value; 817 break; 818 case HostCmd_CMD_PMIC_REG_ACCESS: 819 r.pmic = &resp->params.pmic_reg; 820 reg_rw->offset = (u32) le16_to_cpu(r.pmic->offset); 821 reg_rw->value = (u32) r.pmic->value; 822 break; 823 case HostCmd_CMD_CAU_REG_ACCESS: 824 r.rf = &resp->params.rf_reg; 825 reg_rw->offset = (u32) le16_to_cpu(r.rf->offset); 826 reg_rw->value = (u32) r.rf->value; 827 break; 828 case HostCmd_CMD_802_11_EEPROM_ACCESS: 829 r.eeprom = &resp->params.eeprom; 830 pr_debug("info: EEPROM read len=%x\n", 831 le16_to_cpu(r.eeprom->byte_count)); 832 if (eeprom->byte_count < le16_to_cpu(r.eeprom->byte_count)) { 833 eeprom->byte_count = 0; 834 pr_debug("info: EEPROM read length is too big\n"); 835 return -1; 836 } 837 eeprom->offset = le16_to_cpu(r.eeprom->offset); 838 eeprom->byte_count = le16_to_cpu(r.eeprom->byte_count); 839 if (eeprom->byte_count > 0) 840 memcpy(&eeprom->value, &r.eeprom->value, 841 min((u16)MAX_EEPROM_DATA, eeprom->byte_count)); 842 break; 843 default: 844 return -1; 845 } 846 return 0; 847 } 848 849 /* 850 * This function handles the command response of get IBSS coalescing status. 851 * 852 * If the received BSSID is different than the current one, the current BSSID, 853 * beacon interval, ATIM window and ERP information are updated, along with 854 * changing the ad-hoc state accordingly. 855 */ 856 static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, 857 struct host_cmd_ds_command *resp) 858 { 859 struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = 860 &(resp->params.ibss_coalescing); 861 862 if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) 863 return 0; 864 865 mwifiex_dbg(priv->adapter, INFO, 866 "info: new BSSID %pM\n", ibss_coal_resp->bssid); 867 868 /* If rsp has NULL BSSID, Just return..... No Action */ 869 if (is_zero_ether_addr(ibss_coal_resp->bssid)) { 870 mwifiex_dbg(priv->adapter, FATAL, "new BSSID is NULL\n"); 871 return 0; 872 } 873 874 /* If BSSID is diff, modify current BSS parameters */ 875 if (!ether_addr_equal(priv->curr_bss_params.bss_descriptor.mac_address, ibss_coal_resp->bssid)) { 876 /* BSSID */ 877 memcpy(priv->curr_bss_params.bss_descriptor.mac_address, 878 ibss_coal_resp->bssid, ETH_ALEN); 879 880 /* Beacon Interval */ 881 priv->curr_bss_params.bss_descriptor.beacon_period 882 = le16_to_cpu(ibss_coal_resp->beacon_interval); 883 884 /* ERP Information */ 885 priv->curr_bss_params.bss_descriptor.erp_flags = 886 (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); 887 888 priv->adhoc_state = ADHOC_COALESCED; 889 } 890 891 return 0; 892 } 893 static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv, 894 struct host_cmd_ds_command *resp) 895 { 896 struct host_cmd_ds_tdls_oper *cmd_tdls_oper = &resp->params.tdls_oper; 897 u16 reason = le16_to_cpu(cmd_tdls_oper->reason); 898 u16 action = le16_to_cpu(cmd_tdls_oper->tdls_action); 899 struct mwifiex_sta_node *node = 900 mwifiex_get_sta_entry(priv, cmd_tdls_oper->peer_mac); 901 902 switch (action) { 903 case ACT_TDLS_DELETE: 904 if (reason) { 905 if (!node || reason == TDLS_ERR_LINK_NONEXISTENT) 906 mwifiex_dbg(priv->adapter, MSG, 907 "TDLS link delete for %pM failed: reason %d\n", 908 cmd_tdls_oper->peer_mac, reason); 909 else 910 mwifiex_dbg(priv->adapter, ERROR, 911 "TDLS link delete for %pM failed: reason %d\n", 912 cmd_tdls_oper->peer_mac, reason); 913 } else { 914 mwifiex_dbg(priv->adapter, MSG, 915 "TDLS link delete for %pM successful\n", 916 cmd_tdls_oper->peer_mac); 917 } 918 break; 919 case ACT_TDLS_CREATE: 920 if (reason) { 921 mwifiex_dbg(priv->adapter, ERROR, 922 "TDLS link creation for %pM failed: reason %d", 923 cmd_tdls_oper->peer_mac, reason); 924 if (node && reason != TDLS_ERR_LINK_EXISTS) 925 node->tdls_status = TDLS_SETUP_FAILURE; 926 } else { 927 mwifiex_dbg(priv->adapter, MSG, 928 "TDLS link creation for %pM successful", 929 cmd_tdls_oper->peer_mac); 930 } 931 break; 932 case ACT_TDLS_CONFIG: 933 if (reason) { 934 mwifiex_dbg(priv->adapter, ERROR, 935 "TDLS link config for %pM failed, reason %d\n", 936 cmd_tdls_oper->peer_mac, reason); 937 if (node) 938 node->tdls_status = TDLS_SETUP_FAILURE; 939 } else { 940 mwifiex_dbg(priv->adapter, MSG, 941 "TDLS link config for %pM successful\n", 942 cmd_tdls_oper->peer_mac); 943 } 944 break; 945 default: 946 mwifiex_dbg(priv->adapter, ERROR, 947 "Unknown TDLS command action response %d", action); 948 return -1; 949 } 950 951 return 0; 952 } 953 /* 954 * This function handles the command response for subscribe event command. 955 */ 956 static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv, 957 struct host_cmd_ds_command *resp) 958 { 959 struct host_cmd_ds_802_11_subsc_evt *cmd_sub_event = 960 &resp->params.subsc_evt; 961 962 /* For every subscribe event command (Get/Set/Clear), FW reports the 963 * current set of subscribed events*/ 964 mwifiex_dbg(priv->adapter, EVENT, 965 "Bitmap of currently subscribed events: %16x\n", 966 le16_to_cpu(cmd_sub_event->events)); 967 968 return 0; 969 } 970 971 static int mwifiex_ret_uap_sta_list(struct mwifiex_private *priv, 972 struct host_cmd_ds_command *resp) 973 { 974 struct host_cmd_ds_sta_list *sta_list = 975 &resp->params.sta_list; 976 struct mwifiex_ie_types_sta_info *sta_info = (void *)&sta_list->tlv; 977 int i; 978 struct mwifiex_sta_node *sta_node; 979 980 for (i = 0; i < (le16_to_cpu(sta_list->sta_count)); i++) { 981 sta_node = mwifiex_get_sta_entry(priv, sta_info->mac); 982 if (unlikely(!sta_node)) 983 continue; 984 985 sta_node->stats.rssi = sta_info->rssi; 986 sta_info++; 987 } 988 989 return 0; 990 } 991 992 /* This function handles the command response of set_cfg_data */ 993 static int mwifiex_ret_cfg_data(struct mwifiex_private *priv, 994 struct host_cmd_ds_command *resp) 995 { 996 if (resp->result != HostCmd_RESULT_OK) { 997 mwifiex_dbg(priv->adapter, ERROR, "Cal data cmd resp failed\n"); 998 return -1; 999 } 1000 1001 return 0; 1002 } 1003 1004 /** This Function handles the command response of sdio rx aggr */ 1005 static int mwifiex_ret_sdio_rx_aggr_cfg(struct mwifiex_private *priv, 1006 struct host_cmd_ds_command *resp) 1007 { 1008 struct mwifiex_adapter *adapter = priv->adapter; 1009 struct host_cmd_sdio_sp_rx_aggr_cfg *cfg = 1010 &resp->params.sdio_rx_aggr_cfg; 1011 1012 adapter->sdio_rx_aggr_enable = cfg->enable; 1013 adapter->sdio_rx_block_size = le16_to_cpu(cfg->block_size); 1014 1015 return 0; 1016 } 1017 1018 static int mwifiex_ret_robust_coex(struct mwifiex_private *priv, 1019 struct host_cmd_ds_command *resp, 1020 bool *is_timeshare) 1021 { 1022 struct host_cmd_ds_robust_coex *coex = &resp->params.coex; 1023 struct mwifiex_ie_types_robust_coex *coex_tlv; 1024 u16 action = le16_to_cpu(coex->action); 1025 u32 mode; 1026 1027 coex_tlv = (struct mwifiex_ie_types_robust_coex 1028 *)((u8 *)coex + sizeof(struct host_cmd_ds_robust_coex)); 1029 if (action == HostCmd_ACT_GEN_GET) { 1030 mode = le32_to_cpu(coex_tlv->mode); 1031 if (mode == MWIFIEX_COEX_MODE_TIMESHARE) 1032 *is_timeshare = true; 1033 else 1034 *is_timeshare = false; 1035 } 1036 1037 return 0; 1038 } 1039 1040 static struct ieee80211_regdomain * 1041 mwifiex_create_custom_regdomain(struct mwifiex_private *priv, 1042 u8 *buf, u16 buf_len) 1043 { 1044 u16 num_chan = buf_len / 2; 1045 struct ieee80211_regdomain *regd; 1046 struct ieee80211_reg_rule *rule; 1047 bool new_rule; 1048 int idx, freq, prev_freq = 0; 1049 u32 bw, prev_bw = 0; 1050 u8 chflags, prev_chflags = 0, valid_rules = 0; 1051 1052 if (WARN_ON_ONCE(num_chan > NL80211_MAX_SUPP_REG_RULES)) 1053 return ERR_PTR(-EINVAL); 1054 1055 regd = kzalloc(struct_size(regd, reg_rules, num_chan), GFP_KERNEL); 1056 if (!regd) 1057 return ERR_PTR(-ENOMEM); 1058 1059 for (idx = 0; idx < num_chan; idx++) { 1060 u8 chan; 1061 enum nl80211_band band; 1062 1063 chan = *buf++; 1064 if (!chan) { 1065 kfree(regd); 1066 return NULL; 1067 } 1068 chflags = *buf++; 1069 band = (chan <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; 1070 freq = ieee80211_channel_to_frequency(chan, band); 1071 new_rule = false; 1072 1073 if (chflags & MWIFIEX_CHANNEL_DISABLED) 1074 continue; 1075 1076 if (band == NL80211_BAND_5GHZ) { 1077 if (!(chflags & MWIFIEX_CHANNEL_NOHT80)) 1078 bw = MHZ_TO_KHZ(80); 1079 else if (!(chflags & MWIFIEX_CHANNEL_NOHT40)) 1080 bw = MHZ_TO_KHZ(40); 1081 else 1082 bw = MHZ_TO_KHZ(20); 1083 } else { 1084 if (!(chflags & MWIFIEX_CHANNEL_NOHT40)) 1085 bw = MHZ_TO_KHZ(40); 1086 else 1087 bw = MHZ_TO_KHZ(20); 1088 } 1089 1090 if (idx == 0 || prev_chflags != chflags || prev_bw != bw || 1091 freq - prev_freq > 20) { 1092 valid_rules++; 1093 new_rule = true; 1094 } 1095 1096 rule = ®d->reg_rules[valid_rules - 1]; 1097 1098 rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10); 1099 1100 prev_chflags = chflags; 1101 prev_freq = freq; 1102 prev_bw = bw; 1103 1104 if (!new_rule) 1105 continue; 1106 1107 rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10); 1108 rule->power_rule.max_eirp = DBM_TO_MBM(19); 1109 1110 if (chflags & MWIFIEX_CHANNEL_PASSIVE) 1111 rule->flags = NL80211_RRF_NO_IR; 1112 1113 if (chflags & MWIFIEX_CHANNEL_DFS) 1114 rule->flags = NL80211_RRF_DFS; 1115 1116 rule->freq_range.max_bandwidth_khz = bw; 1117 } 1118 1119 regd->n_reg_rules = valid_rules; 1120 regd->alpha2[0] = '9'; 1121 regd->alpha2[1] = '9'; 1122 1123 return regd; 1124 } 1125 1126 static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv, 1127 struct host_cmd_ds_command *resp) 1128 { 1129 struct host_cmd_ds_chan_region_cfg *reg = &resp->params.reg_cfg; 1130 u16 action = le16_to_cpu(reg->action); 1131 u16 tlv, tlv_buf_len, tlv_buf_left; 1132 struct mwifiex_ie_types_header *head; 1133 struct ieee80211_regdomain *regd; 1134 u8 *tlv_buf; 1135 1136 if (action != HostCmd_ACT_GEN_GET) 1137 return 0; 1138 1139 tlv_buf = (u8 *)reg + sizeof(*reg); 1140 tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*reg); 1141 1142 while (tlv_buf_left >= sizeof(*head)) { 1143 head = (struct mwifiex_ie_types_header *)tlv_buf; 1144 tlv = le16_to_cpu(head->type); 1145 tlv_buf_len = le16_to_cpu(head->len); 1146 1147 if (tlv_buf_left < (sizeof(*head) + tlv_buf_len)) 1148 break; 1149 1150 switch (tlv) { 1151 case TLV_TYPE_CHAN_ATTR_CFG: 1152 mwifiex_dbg_dump(priv->adapter, CMD_D, "CHAN:", 1153 (u8 *)head + sizeof(*head), 1154 tlv_buf_len); 1155 regd = mwifiex_create_custom_regdomain(priv, 1156 (u8 *)head + sizeof(*head), tlv_buf_len); 1157 if (!IS_ERR(regd)) 1158 priv->adapter->regd = regd; 1159 break; 1160 } 1161 1162 tlv_buf += (sizeof(*head) + tlv_buf_len); 1163 tlv_buf_left -= (sizeof(*head) + tlv_buf_len); 1164 } 1165 1166 return 0; 1167 } 1168 1169 static int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv, 1170 struct host_cmd_ds_command *resp) 1171 { 1172 struct host_cmd_ds_pkt_aggr_ctrl *pkt_aggr_ctrl = 1173 &resp->params.pkt_aggr_ctrl; 1174 struct mwifiex_adapter *adapter = priv->adapter; 1175 1176 adapter->bus_aggr.enable = le16_to_cpu(pkt_aggr_ctrl->enable); 1177 if (adapter->bus_aggr.enable) 1178 adapter->intf_hdr_len = INTF_HEADER_LEN; 1179 adapter->bus_aggr.mode = MWIFIEX_BUS_AGGR_MODE_LEN_V2; 1180 adapter->bus_aggr.tx_aggr_max_size = 1181 le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_size); 1182 adapter->bus_aggr.tx_aggr_max_num = 1183 le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_num); 1184 adapter->bus_aggr.tx_aggr_align = 1185 le16_to_cpu(pkt_aggr_ctrl->tx_aggr_align); 1186 1187 return 0; 1188 } 1189 1190 static int mwifiex_ret_get_chan_info(struct mwifiex_private *priv, 1191 struct host_cmd_ds_command *resp, 1192 struct mwifiex_channel_band *channel_band) 1193 { 1194 struct host_cmd_ds_sta_configure *sta_cfg_cmd = &resp->params.sta_cfg; 1195 struct host_cmd_tlv_channel_band *tlv_band_channel; 1196 1197 tlv_band_channel = 1198 (struct host_cmd_tlv_channel_band *)sta_cfg_cmd->tlv_buffer; 1199 memcpy(&channel_band->band_config, &tlv_band_channel->band_config, 1200 sizeof(struct mwifiex_band_config)); 1201 channel_band->channel = tlv_band_channel->channel; 1202 1203 return 0; 1204 } 1205 1206 /* 1207 * This function handles the command responses. 1208 * 1209 * This is a generic function, which calls command specific 1210 * response handlers based on the command ID. 1211 */ 1212 int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, 1213 struct host_cmd_ds_command *resp) 1214 { 1215 int ret = 0; 1216 struct mwifiex_adapter *adapter = priv->adapter; 1217 void *data_buf = adapter->curr_cmd->data_buf; 1218 1219 /* If the command is not successful, cleanup and return failure */ 1220 if (resp->result != HostCmd_RESULT_OK) { 1221 mwifiex_process_cmdresp_error(priv, resp); 1222 return -1; 1223 } 1224 /* Command successful, handle response */ 1225 switch (cmdresp_no) { 1226 case HostCmd_CMD_GET_HW_SPEC: 1227 ret = mwifiex_ret_get_hw_spec(priv, resp); 1228 break; 1229 case HostCmd_CMD_CFG_DATA: 1230 ret = mwifiex_ret_cfg_data(priv, resp); 1231 break; 1232 case HostCmd_CMD_MAC_CONTROL: 1233 break; 1234 case HostCmd_CMD_802_11_MAC_ADDRESS: 1235 ret = mwifiex_ret_802_11_mac_address(priv, resp); 1236 break; 1237 case HostCmd_CMD_MAC_MULTICAST_ADR: 1238 ret = mwifiex_ret_mac_multicast_adr(priv, resp); 1239 break; 1240 case HostCmd_CMD_TX_RATE_CFG: 1241 ret = mwifiex_ret_tx_rate_cfg(priv, resp); 1242 break; 1243 case HostCmd_CMD_802_11_SCAN: 1244 ret = mwifiex_ret_802_11_scan(priv, resp); 1245 adapter->curr_cmd->wait_q_enabled = false; 1246 break; 1247 case HostCmd_CMD_802_11_SCAN_EXT: 1248 ret = mwifiex_ret_802_11_scan_ext(priv, resp); 1249 adapter->curr_cmd->wait_q_enabled = false; 1250 break; 1251 case HostCmd_CMD_802_11_BG_SCAN_QUERY: 1252 ret = mwifiex_ret_802_11_scan(priv, resp); 1253 cfg80211_sched_scan_results(priv->wdev.wiphy, 0); 1254 mwifiex_dbg(adapter, CMD, 1255 "info: CMD_RESP: BG_SCAN result is ready!\n"); 1256 break; 1257 case HostCmd_CMD_802_11_BG_SCAN_CONFIG: 1258 break; 1259 case HostCmd_CMD_TXPWR_CFG: 1260 ret = mwifiex_ret_tx_power_cfg(priv, resp); 1261 break; 1262 case HostCmd_CMD_RF_TX_PWR: 1263 ret = mwifiex_ret_rf_tx_power(priv, resp); 1264 break; 1265 case HostCmd_CMD_RF_ANTENNA: 1266 ret = mwifiex_ret_rf_antenna(priv, resp); 1267 break; 1268 case HostCmd_CMD_802_11_PS_MODE_ENH: 1269 ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); 1270 break; 1271 case HostCmd_CMD_802_11_HS_CFG_ENH: 1272 ret = mwifiex_ret_802_11_hs_cfg(priv, resp); 1273 break; 1274 case HostCmd_CMD_802_11_ASSOCIATE: 1275 ret = mwifiex_ret_802_11_associate(priv, resp); 1276 break; 1277 case HostCmd_CMD_802_11_DEAUTHENTICATE: 1278 ret = mwifiex_ret_802_11_deauthenticate(priv, resp); 1279 break; 1280 case HostCmd_CMD_802_11_AD_HOC_START: 1281 case HostCmd_CMD_802_11_AD_HOC_JOIN: 1282 ret = mwifiex_ret_802_11_ad_hoc(priv, resp); 1283 break; 1284 case HostCmd_CMD_802_11_AD_HOC_STOP: 1285 ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); 1286 break; 1287 case HostCmd_CMD_802_11_GET_LOG: 1288 ret = mwifiex_ret_get_log(priv, resp, data_buf); 1289 break; 1290 case HostCmd_CMD_RSSI_INFO: 1291 ret = mwifiex_ret_802_11_rssi_info(priv, resp); 1292 break; 1293 case HostCmd_CMD_802_11_SNMP_MIB: 1294 ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); 1295 break; 1296 case HostCmd_CMD_802_11_TX_RATE_QUERY: 1297 ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); 1298 break; 1299 case HostCmd_CMD_VERSION_EXT: 1300 ret = mwifiex_ret_ver_ext(priv, resp, data_buf); 1301 break; 1302 case HostCmd_CMD_REMAIN_ON_CHAN: 1303 ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf); 1304 break; 1305 case HostCmd_CMD_11AC_CFG: 1306 break; 1307 case HostCmd_CMD_PACKET_AGGR_CTRL: 1308 ret = mwifiex_ret_pkt_aggr_ctrl(priv, resp); 1309 break; 1310 case HostCmd_CMD_P2P_MODE_CFG: 1311 ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf); 1312 break; 1313 case HostCmd_CMD_MGMT_FRAME_REG: 1314 case HostCmd_CMD_FUNC_INIT: 1315 case HostCmd_CMD_FUNC_SHUTDOWN: 1316 break; 1317 case HostCmd_CMD_802_11_KEY_MATERIAL: 1318 ret = mwifiex_ret_802_11_key_material(priv, resp); 1319 break; 1320 case HostCmd_CMD_802_11D_DOMAIN_INFO: 1321 ret = mwifiex_ret_802_11d_domain_info(priv, resp); 1322 break; 1323 case HostCmd_CMD_11N_ADDBA_REQ: 1324 ret = mwifiex_ret_11n_addba_req(priv, resp); 1325 break; 1326 case HostCmd_CMD_11N_DELBA: 1327 ret = mwifiex_ret_11n_delba(priv, resp); 1328 break; 1329 case HostCmd_CMD_11N_ADDBA_RSP: 1330 ret = mwifiex_ret_11n_addba_resp(priv, resp); 1331 break; 1332 case HostCmd_CMD_RECONFIGURE_TX_BUFF: 1333 if (0xffff == (u16)le16_to_cpu(resp->params.tx_buf.buff_size)) { 1334 if (adapter->iface_type == MWIFIEX_USB && 1335 adapter->usb_mc_setup) { 1336 if (adapter->if_ops.multi_port_resync) 1337 adapter->if_ops. 1338 multi_port_resync(adapter); 1339 adapter->usb_mc_setup = false; 1340 adapter->tx_lock_flag = false; 1341 } 1342 break; 1343 } 1344 adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. 1345 tx_buf.buff_size); 1346 adapter->tx_buf_size = (adapter->tx_buf_size 1347 / MWIFIEX_SDIO_BLOCK_SIZE) 1348 * MWIFIEX_SDIO_BLOCK_SIZE; 1349 adapter->curr_tx_buf_size = adapter->tx_buf_size; 1350 mwifiex_dbg(adapter, CMD, "cmd: curr_tx_buf_size=%d\n", 1351 adapter->curr_tx_buf_size); 1352 1353 if (adapter->if_ops.update_mp_end_port) 1354 adapter->if_ops.update_mp_end_port(adapter, 1355 le16_to_cpu(resp->params.tx_buf.mp_end_port)); 1356 break; 1357 case HostCmd_CMD_AMSDU_AGGR_CTRL: 1358 break; 1359 case HostCmd_CMD_WMM_GET_STATUS: 1360 ret = mwifiex_ret_wmm_get_status(priv, resp); 1361 break; 1362 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: 1363 ret = mwifiex_ret_ibss_coalescing_status(priv, resp); 1364 break; 1365 case HostCmd_CMD_MEM_ACCESS: 1366 ret = mwifiex_ret_mem_access(priv, resp, data_buf); 1367 break; 1368 case HostCmd_CMD_MAC_REG_ACCESS: 1369 case HostCmd_CMD_BBP_REG_ACCESS: 1370 case HostCmd_CMD_RF_REG_ACCESS: 1371 case HostCmd_CMD_PMIC_REG_ACCESS: 1372 case HostCmd_CMD_CAU_REG_ACCESS: 1373 case HostCmd_CMD_802_11_EEPROM_ACCESS: 1374 ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); 1375 break; 1376 case HostCmd_CMD_SET_BSS_MODE: 1377 break; 1378 case HostCmd_CMD_11N_CFG: 1379 break; 1380 case HostCmd_CMD_PCIE_DESC_DETAILS: 1381 break; 1382 case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: 1383 ret = mwifiex_ret_subsc_evt(priv, resp); 1384 break; 1385 case HostCmd_CMD_UAP_SYS_CONFIG: 1386 break; 1387 case HOST_CMD_APCMD_STA_LIST: 1388 ret = mwifiex_ret_uap_sta_list(priv, resp); 1389 break; 1390 case HostCmd_CMD_UAP_BSS_START: 1391 adapter->tx_lock_flag = false; 1392 adapter->pps_uapsd_mode = false; 1393 adapter->delay_null_pkt = false; 1394 priv->bss_started = 1; 1395 break; 1396 case HostCmd_CMD_UAP_BSS_STOP: 1397 priv->bss_started = 0; 1398 break; 1399 case HostCmd_CMD_UAP_STA_DEAUTH: 1400 break; 1401 case HOST_CMD_APCMD_SYS_RESET: 1402 break; 1403 case HostCmd_CMD_MEF_CFG: 1404 break; 1405 case HostCmd_CMD_COALESCE_CFG: 1406 break; 1407 case HostCmd_CMD_TDLS_OPER: 1408 ret = mwifiex_ret_tdls_oper(priv, resp); 1409 break; 1410 case HostCmd_CMD_MC_POLICY: 1411 break; 1412 case HostCmd_CMD_CHAN_REPORT_REQUEST: 1413 break; 1414 case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: 1415 ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); 1416 break; 1417 case HostCmd_CMD_HS_WAKEUP_REASON: 1418 ret = mwifiex_ret_wakeup_reason(priv, resp, data_buf); 1419 break; 1420 case HostCmd_CMD_TDLS_CONFIG: 1421 break; 1422 case HostCmd_CMD_ROBUST_COEX: 1423 ret = mwifiex_ret_robust_coex(priv, resp, data_buf); 1424 break; 1425 case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG: 1426 break; 1427 case HostCmd_CMD_CHAN_REGION_CFG: 1428 ret = mwifiex_ret_chan_region_cfg(priv, resp); 1429 break; 1430 case HostCmd_CMD_STA_CONFIGURE: 1431 ret = mwifiex_ret_get_chan_info(priv, resp, data_buf); 1432 break; 1433 default: 1434 mwifiex_dbg(adapter, ERROR, 1435 "CMD_RESP: unknown cmd response %#x\n", 1436 resp->command); 1437 break; 1438 } 1439 1440 return ret; 1441 } 1442