Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP Wireless LAN device driver: station command response handling
0004  *
0005  * Copyright 2011-2020 NXP
0006  */
0007 
0008 #include "decl.h"
0009 #include "ioctl.h"
0010 #include "util.h"
0011 #include "fw.h"
0012 #include "main.h"
0013 #include "wmm.h"
0014 #include "11n.h"
0015 #include "11ac.h"
0016 
0017 
0018 /*
0019  * This function handles the command response error case.
0020  *
0021  * For scan response error, the function cancels all the pending
0022  * scan commands and generates an event to inform the applications
0023  * of the scan completion.
0024  *
0025  * For Power Save command failure, we do not retry enter PS
0026  * command in case of Ad-hoc mode.
0027  *
0028  * For all other response errors, the current command buffer is freed
0029  * and returned to the free command queue.
0030  */
0031 static void
0032 mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
0033                   struct host_cmd_ds_command *resp)
0034 {
0035     struct mwifiex_adapter *adapter = priv->adapter;
0036     struct host_cmd_ds_802_11_ps_mode_enh *pm;
0037 
0038     mwifiex_dbg(adapter, ERROR,
0039             "CMD_RESP: cmd %#x error, result=%#x\n",
0040             resp->command, resp->result);
0041 
0042     if (adapter->curr_cmd->wait_q_enabled)
0043         adapter->cmd_wait_q.status = -1;
0044 
0045     switch (le16_to_cpu(resp->command)) {
0046     case HostCmd_CMD_802_11_PS_MODE_ENH:
0047         pm = &resp->params.psmode_enh;
0048         mwifiex_dbg(adapter, ERROR,
0049                 "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n",
0050                 resp->result, le16_to_cpu(pm->action));
0051         /* We do not re-try enter-ps command in ad-hoc mode. */
0052         if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
0053             (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
0054             priv->bss_mode == NL80211_IFTYPE_ADHOC)
0055             adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
0056 
0057         break;
0058     case HostCmd_CMD_802_11_SCAN:
0059     case HostCmd_CMD_802_11_SCAN_EXT:
0060         mwifiex_cancel_scan(adapter);
0061         break;
0062 
0063     case HostCmd_CMD_MAC_CONTROL:
0064         break;
0065 
0066     case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
0067         mwifiex_dbg(adapter, MSG,
0068                 "SDIO RX single-port aggregation Not support\n");
0069         break;
0070 
0071     default:
0072         break;
0073     }
0074     /* Handling errors here */
0075     mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
0076 
0077     spin_lock_bh(&adapter->mwifiex_cmd_lock);
0078     adapter->curr_cmd = NULL;
0079     spin_unlock_bh(&adapter->mwifiex_cmd_lock);
0080 }
0081 
0082 /*
0083  * This function handles the command response of get RSSI info.
0084  *
0085  * Handling includes changing the header fields into CPU format
0086  * and saving the following parameters in driver -
0087  *      - Last data and beacon RSSI value
0088  *      - Average data and beacon RSSI value
0089  *      - Last data and beacon NF value
0090  *      - Average data and beacon NF value
0091  *
0092  * The parameters are send to the application as well, along with
0093  * calculated SNR values.
0094  */
0095 static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
0096                     struct host_cmd_ds_command *resp)
0097 {
0098     struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
0099                         &resp->params.rssi_info_rsp;
0100     struct mwifiex_ds_misc_subsc_evt *subsc_evt =
0101                         &priv->async_subsc_evt_storage;
0102 
0103     priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
0104     priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
0105 
0106     priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
0107     priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
0108 
0109     priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
0110     priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
0111 
0112     priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
0113     priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
0114 
0115     if (priv->subsc_evt_rssi_state == EVENT_HANDLED)
0116         return 0;
0117 
0118     memset(subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt));
0119 
0120     /* Resubscribe low and high rssi events with new thresholds */
0121     subsc_evt->events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH;
0122     subsc_evt->action = HostCmd_ACT_BITWISE_SET;
0123     if (priv->subsc_evt_rssi_state == RSSI_LOW_RECVD) {
0124         subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg -
0125                 priv->cqm_rssi_hyst);
0126         subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
0127     } else if (priv->subsc_evt_rssi_state == RSSI_HIGH_RECVD) {
0128         subsc_evt->bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold);
0129         subsc_evt->bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg +
0130                 priv->cqm_rssi_hyst);
0131     }
0132     subsc_evt->bcn_l_rssi_cfg.evt_freq = 1;
0133     subsc_evt->bcn_h_rssi_cfg.evt_freq = 1;
0134 
0135     priv->subsc_evt_rssi_state = EVENT_HANDLED;
0136 
0137     mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT,
0138              0, 0, subsc_evt, false);
0139 
0140     return 0;
0141 }
0142 
0143 /*
0144  * This function handles the command response of set/get SNMP
0145  * MIB parameters.
0146  *
0147  * Handling includes changing the header fields into CPU format
0148  * and saving the parameter in driver.
0149  *
0150  * The following parameters are supported -
0151  *      - Fragmentation threshold
0152  *      - RTS threshold
0153  *      - Short retry limit
0154  */
0155 static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
0156                        struct host_cmd_ds_command *resp,
0157                        u32 *data_buf)
0158 {
0159     struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
0160     u16 oid = le16_to_cpu(smib->oid);
0161     u16 query_type = le16_to_cpu(smib->query_type);
0162     u32 ul_temp;
0163 
0164     mwifiex_dbg(priv->adapter, INFO,
0165             "info: SNMP_RESP: oid value = %#x,\t"
0166             "query_type = %#x, buf size = %#x\n",
0167             oid, query_type, le16_to_cpu(smib->buf_size));
0168     if (query_type == HostCmd_ACT_GEN_GET) {
0169         ul_temp = get_unaligned_le16(smib->value);
0170         if (data_buf)
0171             *data_buf = ul_temp;
0172         switch (oid) {
0173         case FRAG_THRESH_I:
0174             mwifiex_dbg(priv->adapter, INFO,
0175                     "info: SNMP_RESP: FragThsd =%u\n",
0176                     ul_temp);
0177             break;
0178         case RTS_THRESH_I:
0179             mwifiex_dbg(priv->adapter, INFO,
0180                     "info: SNMP_RESP: RTSThsd =%u\n",
0181                     ul_temp);
0182             break;
0183         case SHORT_RETRY_LIM_I:
0184             mwifiex_dbg(priv->adapter, INFO,
0185                     "info: SNMP_RESP: TxRetryCount=%u\n",
0186                     ul_temp);
0187             break;
0188         case DTIM_PERIOD_I:
0189             mwifiex_dbg(priv->adapter, INFO,
0190                     "info: SNMP_RESP: DTIM period=%u\n",
0191                     ul_temp);
0192             break;
0193         default:
0194             break;
0195         }
0196     }
0197 
0198     return 0;
0199 }
0200 
0201 /*
0202  * This function handles the command response of get log request
0203  *
0204  * Handling includes changing the header fields into CPU format
0205  * and sending the received parameters to application.
0206  */
0207 static int mwifiex_ret_get_log(struct mwifiex_private *priv,
0208                    struct host_cmd_ds_command *resp,
0209                    struct mwifiex_ds_get_stats *stats)
0210 {
0211     struct host_cmd_ds_802_11_get_log *get_log =
0212         &resp->params.get_log;
0213 
0214     if (stats) {
0215         stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
0216         stats->failed = le32_to_cpu(get_log->failed);
0217         stats->retry = le32_to_cpu(get_log->retry);
0218         stats->multi_retry = le32_to_cpu(get_log->multi_retry);
0219         stats->frame_dup = le32_to_cpu(get_log->frame_dup);
0220         stats->rts_success = le32_to_cpu(get_log->rts_success);
0221         stats->rts_failure = le32_to_cpu(get_log->rts_failure);
0222         stats->ack_failure = le32_to_cpu(get_log->ack_failure);
0223         stats->rx_frag = le32_to_cpu(get_log->rx_frag);
0224         stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
0225         stats->fcs_error = le32_to_cpu(get_log->fcs_error);
0226         stats->tx_frame = le32_to_cpu(get_log->tx_frame);
0227         stats->wep_icv_error[0] =
0228             le32_to_cpu(get_log->wep_icv_err_cnt[0]);
0229         stats->wep_icv_error[1] =
0230             le32_to_cpu(get_log->wep_icv_err_cnt[1]);
0231         stats->wep_icv_error[2] =
0232             le32_to_cpu(get_log->wep_icv_err_cnt[2]);
0233         stats->wep_icv_error[3] =
0234             le32_to_cpu(get_log->wep_icv_err_cnt[3]);
0235         stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt);
0236         stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt);
0237     }
0238 
0239     return 0;
0240 }
0241 
0242 /*
0243  * This function handles the command response of set/get Tx rate
0244  * configurations.
0245  *
0246  * Handling includes changing the header fields into CPU format
0247  * and saving the following parameters in driver -
0248  *      - DSSS rate bitmap
0249  *      - OFDM rate bitmap
0250  *      - HT MCS rate bitmaps
0251  *
0252  * Based on the new rate bitmaps, the function re-evaluates if
0253  * auto data rate has been activated. If not, it sends another
0254  * query to the firmware to get the current Tx data rate.
0255  */
0256 static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
0257                    struct host_cmd_ds_command *resp)
0258 {
0259     struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
0260     struct mwifiex_rate_scope *rate_scope;
0261     struct mwifiex_ie_types_header *head;
0262     u16 tlv, tlv_buf_len, tlv_buf_left;
0263     u8 *tlv_buf;
0264     u32 i;
0265 
0266     tlv_buf = ((u8 *)rate_cfg) + sizeof(struct host_cmd_ds_tx_rate_cfg);
0267     tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*rate_cfg);
0268 
0269     while (tlv_buf_left >= sizeof(*head)) {
0270         head = (struct mwifiex_ie_types_header *)tlv_buf;
0271         tlv = le16_to_cpu(head->type);
0272         tlv_buf_len = le16_to_cpu(head->len);
0273 
0274         if (tlv_buf_left < (sizeof(*head) + tlv_buf_len))
0275             break;
0276 
0277         switch (tlv) {
0278         case TLV_TYPE_RATE_SCOPE:
0279             rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
0280             priv->bitmap_rates[0] =
0281                 le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
0282             priv->bitmap_rates[1] =
0283                 le16_to_cpu(rate_scope->ofdm_rate_bitmap);
0284             for (i = 0;
0285                  i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap);
0286                  i++)
0287                 priv->bitmap_rates[2 + i] =
0288                     le16_to_cpu(rate_scope->
0289                             ht_mcs_rate_bitmap[i]);
0290 
0291             if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) {
0292                 for (i = 0; i < ARRAY_SIZE(rate_scope->
0293                                vht_mcs_rate_bitmap);
0294                      i++)
0295                     priv->bitmap_rates[10 + i] =
0296                         le16_to_cpu(rate_scope->
0297                             vht_mcs_rate_bitmap[i]);
0298             }
0299             break;
0300             /* Add RATE_DROP tlv here */
0301         }
0302 
0303         tlv_buf += (sizeof(*head) + tlv_buf_len);
0304         tlv_buf_left -= (sizeof(*head) + tlv_buf_len);
0305     }
0306 
0307     priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
0308 
0309     if (priv->is_data_rate_auto)
0310         priv->data_rate = 0;
0311     else
0312         return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
0313                     HostCmd_ACT_GEN_GET, 0, NULL, false);
0314 
0315     return 0;
0316 }
0317 
0318 /*
0319  * This function handles the command response of get Tx power level.
0320  *
0321  * Handling includes saving the maximum and minimum Tx power levels
0322  * in driver, as well as sending the values to user.
0323  */
0324 static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
0325 {
0326     int length, max_power = -1, min_power = -1;
0327     struct mwifiex_types_power_group *pg_tlv_hdr;
0328     struct mwifiex_power_group *pg;
0329 
0330     if (!data_buf)
0331         return -1;
0332 
0333     pg_tlv_hdr = (struct mwifiex_types_power_group *)((u8 *)data_buf);
0334     pg = (struct mwifiex_power_group *)
0335         ((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group));
0336     length = le16_to_cpu(pg_tlv_hdr->length);
0337 
0338     /* At least one structure required to update power */
0339     if (length < sizeof(struct mwifiex_power_group))
0340         return 0;
0341 
0342     max_power = pg->power_max;
0343     min_power = pg->power_min;
0344     length -= sizeof(struct mwifiex_power_group);
0345 
0346     while (length >= sizeof(struct mwifiex_power_group)) {
0347         pg++;
0348         if (max_power < pg->power_max)
0349             max_power = pg->power_max;
0350 
0351         if (min_power > pg->power_min)
0352             min_power = pg->power_min;
0353 
0354         length -= sizeof(struct mwifiex_power_group);
0355     }
0356     priv->min_tx_power_level = (u8) min_power;
0357     priv->max_tx_power_level = (u8) max_power;
0358 
0359     return 0;
0360 }
0361 
0362 /*
0363  * This function handles the command response of set/get Tx power
0364  * configurations.
0365  *
0366  * Handling includes changing the header fields into CPU format
0367  * and saving the current Tx power level in driver.
0368  */
0369 static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
0370                     struct host_cmd_ds_command *resp)
0371 {
0372     struct mwifiex_adapter *adapter = priv->adapter;
0373     struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
0374     struct mwifiex_types_power_group *pg_tlv_hdr;
0375     struct mwifiex_power_group *pg;
0376     u16 action = le16_to_cpu(txp_cfg->action);
0377     u16 tlv_buf_left;
0378 
0379     pg_tlv_hdr = (struct mwifiex_types_power_group *)
0380         ((u8 *)txp_cfg +
0381          sizeof(struct host_cmd_ds_txpwr_cfg));
0382 
0383     pg = (struct mwifiex_power_group *)
0384         ((u8 *)pg_tlv_hdr +
0385          sizeof(struct mwifiex_types_power_group));
0386 
0387     tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*txp_cfg);
0388     if (tlv_buf_left <
0389             le16_to_cpu(pg_tlv_hdr->length) + sizeof(*pg_tlv_hdr))
0390         return 0;
0391 
0392     switch (action) {
0393     case HostCmd_ACT_GEN_GET:
0394         if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
0395             mwifiex_get_power_level(priv, pg_tlv_hdr);
0396 
0397         priv->tx_power_level = (u16) pg->power_min;
0398         break;
0399 
0400     case HostCmd_ACT_GEN_SET:
0401         if (!le32_to_cpu(txp_cfg->mode))
0402             break;
0403 
0404         if (pg->power_max == pg->power_min)
0405             priv->tx_power_level = (u16) pg->power_min;
0406         break;
0407     default:
0408         mwifiex_dbg(adapter, ERROR,
0409                 "CMD_RESP: unknown cmd action %d\n",
0410                 action);
0411         return 0;
0412     }
0413     mwifiex_dbg(adapter, INFO,
0414             "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
0415             priv->tx_power_level, priv->max_tx_power_level,
0416             priv->min_tx_power_level);
0417 
0418     return 0;
0419 }
0420 
0421 /*
0422  * This function handles the command response of get RF Tx power.
0423  */
0424 static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv,
0425                    struct host_cmd_ds_command *resp)
0426 {
0427     struct host_cmd_ds_rf_tx_pwr *txp = &resp->params.txp;
0428     u16 action = le16_to_cpu(txp->action);
0429 
0430     priv->tx_power_level = le16_to_cpu(txp->cur_level);
0431 
0432     if (action == HostCmd_ACT_GEN_GET) {
0433         priv->max_tx_power_level = txp->max_power;
0434         priv->min_tx_power_level = txp->min_power;
0435     }
0436 
0437     mwifiex_dbg(priv->adapter, INFO,
0438             "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n",
0439             priv->tx_power_level, priv->max_tx_power_level,
0440             priv->min_tx_power_level);
0441 
0442     return 0;
0443 }
0444 
0445 /*
0446  * This function handles the command response of set rf antenna
0447  */
0448 static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv,
0449                   struct host_cmd_ds_command *resp)
0450 {
0451     struct host_cmd_ds_rf_ant_mimo *ant_mimo = &resp->params.ant_mimo;
0452     struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso;
0453     struct mwifiex_adapter *adapter = priv->adapter;
0454 
0455     if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
0456         priv->tx_ant = le16_to_cpu(ant_mimo->tx_ant_mode);
0457         priv->rx_ant = le16_to_cpu(ant_mimo->rx_ant_mode);
0458         mwifiex_dbg(adapter, INFO,
0459                 "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t"
0460                 "Rx action = 0x%x, Rx Mode = 0x%04x\n",
0461                 le16_to_cpu(ant_mimo->action_tx),
0462                 le16_to_cpu(ant_mimo->tx_ant_mode),
0463                 le16_to_cpu(ant_mimo->action_rx),
0464                 le16_to_cpu(ant_mimo->rx_ant_mode));
0465     } else {
0466         priv->tx_ant = le16_to_cpu(ant_siso->ant_mode);
0467         priv->rx_ant = le16_to_cpu(ant_siso->ant_mode);
0468         mwifiex_dbg(adapter, INFO,
0469                 "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
0470                 le16_to_cpu(ant_siso->action),
0471                 le16_to_cpu(ant_siso->ant_mode));
0472     }
0473     return 0;
0474 }
0475 
0476 /*
0477  * This function handles the command response of set/get MAC address.
0478  *
0479  * Handling includes saving the MAC address in driver.
0480  */
0481 static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
0482                       struct host_cmd_ds_command *resp)
0483 {
0484     struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
0485                             &resp->params.mac_addr;
0486 
0487     memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
0488 
0489     mwifiex_dbg(priv->adapter, INFO,
0490             "info: set mac address: %pM\n", priv->curr_addr);
0491 
0492     return 0;
0493 }
0494 
0495 /*
0496  * This function handles the command response of set/get MAC multicast
0497  * address.
0498  */
0499 static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
0500                      struct host_cmd_ds_command *resp)
0501 {
0502     return 0;
0503 }
0504 
0505 /*
0506  * This function handles the command response of get Tx rate query.
0507  *
0508  * Handling includes changing the header fields into CPU format
0509  * and saving the Tx rate and HT information parameters in driver.
0510  *
0511  * Both rate configuration and current data rate can be retrieved
0512  * with this request.
0513  */
0514 static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
0515                         struct host_cmd_ds_command *resp)
0516 {
0517     priv->tx_rate = resp->params.tx_rate.tx_rate;
0518     priv->tx_htinfo = resp->params.tx_rate.ht_info;
0519     if (!priv->is_data_rate_auto)
0520         priv->data_rate =
0521             mwifiex_index_to_data_rate(priv, priv->tx_rate,
0522                            priv->tx_htinfo);
0523 
0524     return 0;
0525 }
0526 
0527 /*
0528  * This function handles the command response of a deauthenticate
0529  * command.
0530  *
0531  * If the deauthenticated MAC matches the current BSS MAC, the connection
0532  * state is reset.
0533  */
0534 static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
0535                          struct host_cmd_ds_command *resp)
0536 {
0537     struct mwifiex_adapter *adapter = priv->adapter;
0538 
0539     adapter->dbg.num_cmd_deauth++;
0540     if (!memcmp(resp->params.deauth.mac_addr,
0541             &priv->curr_bss_params.bss_descriptor.mac_address,
0542             sizeof(resp->params.deauth.mac_addr)))
0543         mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING,
0544                         false);
0545 
0546     return 0;
0547 }
0548 
0549 /*
0550  * This function handles the command response of ad-hoc stop.
0551  *
0552  * The function resets the connection state in driver.
0553  */
0554 static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
0555                       struct host_cmd_ds_command *resp)
0556 {
0557     mwifiex_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING, false);
0558     return 0;
0559 }
0560 
0561 /*
0562  * This function handles the command response of set/get v1 key material.
0563  *
0564  * Handling includes updating the driver parameters to reflect the
0565  * changes.
0566  */
0567 static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv,
0568                           struct host_cmd_ds_command *resp)
0569 {
0570     struct host_cmd_ds_802_11_key_material *key =
0571                         &resp->params.key_material;
0572     int len;
0573 
0574     len = le16_to_cpu(key->key_param_set.key_len);
0575     if (len > sizeof(key->key_param_set.key))
0576         return -EINVAL;
0577 
0578     if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
0579         if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
0580             mwifiex_dbg(priv->adapter, INFO,
0581                     "info: key: GTK is set\n");
0582             priv->wpa_is_gtk_set = true;
0583             priv->scan_block = false;
0584             priv->port_open = true;
0585         }
0586     }
0587 
0588     memset(priv->aes_key.key_param_set.key, 0,
0589            sizeof(key->key_param_set.key));
0590     priv->aes_key.key_param_set.key_len = cpu_to_le16(len);
0591     memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, len);
0592 
0593     return 0;
0594 }
0595 
0596 /*
0597  * This function handles the command response of set/get v2 key material.
0598  *
0599  * Handling includes updating the driver parameters to reflect the
0600  * changes.
0601  */
0602 static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
0603                           struct host_cmd_ds_command *resp)
0604 {
0605     struct host_cmd_ds_802_11_key_material_v2 *key_v2;
0606     int len;
0607 
0608     key_v2 = &resp->params.key_material_v2;
0609 
0610     len = le16_to_cpu(key_v2->key_param_set.key_params.aes.key_len);
0611     if (len > sizeof(key_v2->key_param_set.key_params.aes.key))
0612         return -EINVAL;
0613 
0614     if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) {
0615         if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) {
0616             mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n");
0617             priv->wpa_is_gtk_set = true;
0618             priv->scan_block = false;
0619             priv->port_open = true;
0620         }
0621     }
0622 
0623     if (key_v2->key_param_set.key_type != KEY_TYPE_ID_AES)
0624         return 0;
0625 
0626     memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0,
0627            sizeof(key_v2->key_param_set.key_params.aes.key));
0628     priv->aes_key_v2.key_param_set.key_params.aes.key_len =
0629                 cpu_to_le16(len);
0630     memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key,
0631            key_v2->key_param_set.key_params.aes.key, len);
0632 
0633     return 0;
0634 }
0635 
0636 /* Wrapper function for processing response of key material command */
0637 static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
0638                        struct host_cmd_ds_command *resp)
0639 {
0640     if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
0641         return mwifiex_ret_802_11_key_material_v2(priv, resp);
0642     else
0643         return mwifiex_ret_802_11_key_material_v1(priv, resp);
0644 }
0645 
0646 /*
0647  * This function handles the command response of get 11d domain information.
0648  */
0649 static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
0650                        struct host_cmd_ds_command *resp)
0651 {
0652     struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
0653         &resp->params.domain_info_resp;
0654     struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
0655     u16 action = le16_to_cpu(domain_info->action);
0656     u8 no_of_triplet;
0657 
0658     no_of_triplet = (u8) ((le16_to_cpu(domain->header.len)
0659                 - IEEE80211_COUNTRY_STRING_LEN)
0660                   / sizeof(struct ieee80211_country_ie_triplet));
0661 
0662     mwifiex_dbg(priv->adapter, INFO,
0663             "info: 11D Domain Info Resp: no_of_triplet=%d\n",
0664             no_of_triplet);
0665 
0666     if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
0667         mwifiex_dbg(priv->adapter, FATAL,
0668                 "11D: invalid number of triplets %d returned\n",
0669                 no_of_triplet);
0670         return -1;
0671     }
0672 
0673     switch (action) {
0674     case HostCmd_ACT_GEN_SET:  /* Proc Set Action */
0675         break;
0676     case HostCmd_ACT_GEN_GET:
0677         break;
0678     default:
0679         mwifiex_dbg(priv->adapter, ERROR,
0680                 "11D: invalid action:%d\n", domain_info->action);
0681         return -1;
0682     }
0683 
0684     return 0;
0685 }
0686 
0687 /*
0688  * This function handles the command response of get extended version.
0689  *
0690  * Handling includes forming the extended version string and sending it
0691  * to application.
0692  */
0693 static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
0694                    struct host_cmd_ds_command *resp,
0695                    struct host_cmd_ds_version_ext *version_ext)
0696 {
0697     struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
0698 
0699     if (test_and_clear_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &priv->adapter->work_flags)) {
0700         if (strncmp(ver_ext->version_str, "ChipRev:20, BB:9b(10.00), RF:40(21)",
0701                 MWIFIEX_VERSION_STR_LENGTH) == 0) {
0702             struct mwifiex_ds_auto_ds auto_ds = {
0703                 .auto_ds = DEEP_SLEEP_OFF,
0704             };
0705 
0706             mwifiex_dbg(priv->adapter, MSG,
0707                     "Bad HW revision detected, disabling deep sleep\n");
0708 
0709             if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
0710                          DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, false)) {
0711                 mwifiex_dbg(priv->adapter, MSG,
0712                         "Disabling deep sleep failed.\n");
0713             }
0714         }
0715 
0716         return 0;
0717     }
0718 
0719     if (version_ext) {
0720         version_ext->version_str_sel = ver_ext->version_str_sel;
0721         memcpy(version_ext->version_str, ver_ext->version_str,
0722                MWIFIEX_VERSION_STR_LENGTH);
0723         memcpy(priv->version_str, ver_ext->version_str,
0724                MWIFIEX_VERSION_STR_LENGTH);
0725 
0726         /* Ensure the version string from the firmware is 0-terminated */
0727         priv->version_str[MWIFIEX_VERSION_STR_LENGTH - 1] = '\0';
0728     }
0729     return 0;
0730 }
0731 
0732 /*
0733  * This function handles the command response of remain on channel.
0734  */
0735 static int
0736 mwifiex_ret_remain_on_chan(struct mwifiex_private *priv,
0737                struct host_cmd_ds_command *resp,
0738                struct host_cmd_ds_remain_on_chan *roc_cfg)
0739 {
0740     struct host_cmd_ds_remain_on_chan *resp_cfg = &resp->params.roc_cfg;
0741 
0742     if (roc_cfg)
0743         memcpy(roc_cfg, resp_cfg, sizeof(*roc_cfg));
0744 
0745     return 0;
0746 }
0747 
0748 /*
0749  * This function handles the command response of P2P mode cfg.
0750  */
0751 static int
0752 mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv,
0753              struct host_cmd_ds_command *resp,
0754              void *data_buf)
0755 {
0756     struct host_cmd_ds_p2p_mode_cfg *mode_cfg = &resp->params.mode_cfg;
0757 
0758     if (data_buf)
0759         put_unaligned_le16(le16_to_cpu(mode_cfg->mode), data_buf);
0760 
0761     return 0;
0762 }
0763 
0764 /* This function handles the command response of mem_access command
0765  */
0766 static int
0767 mwifiex_ret_mem_access(struct mwifiex_private *priv,
0768                struct host_cmd_ds_command *resp, void *pioctl_buf)
0769 {
0770     struct host_cmd_ds_mem_access *mem = (void *)&resp->params.mem;
0771 
0772     priv->mem_rw.addr = le32_to_cpu(mem->addr);
0773     priv->mem_rw.value = le32_to_cpu(mem->value);
0774 
0775     return 0;
0776 }
0777 /*
0778  * This function handles the command response of register access.
0779  *
0780  * The register value and offset are returned to the user. For EEPROM
0781  * access, the byte count is also returned.
0782  */
0783 static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
0784                   void *data_buf)
0785 {
0786     struct mwifiex_ds_reg_rw *reg_rw;
0787     struct mwifiex_ds_read_eeprom *eeprom;
0788     union reg {
0789         struct host_cmd_ds_mac_reg_access *mac;
0790         struct host_cmd_ds_bbp_reg_access *bbp;
0791         struct host_cmd_ds_rf_reg_access *rf;
0792         struct host_cmd_ds_pmic_reg_access *pmic;
0793         struct host_cmd_ds_802_11_eeprom_access *eeprom;
0794     } r;
0795 
0796     if (!data_buf)
0797         return 0;
0798 
0799     reg_rw = data_buf;
0800     eeprom = data_buf;
0801     switch (type) {
0802     case HostCmd_CMD_MAC_REG_ACCESS:
0803         r.mac = &resp->params.mac_reg;
0804         reg_rw->offset = (u32) le16_to_cpu(r.mac->offset);
0805         reg_rw->value = le32_to_cpu(r.mac->value);
0806         break;
0807     case HostCmd_CMD_BBP_REG_ACCESS:
0808         r.bbp = &resp->params.bbp_reg;
0809         reg_rw->offset = (u32) le16_to_cpu(r.bbp->offset);
0810         reg_rw->value = (u32) r.bbp->value;
0811         break;
0812 
0813     case HostCmd_CMD_RF_REG_ACCESS:
0814         r.rf = &resp->params.rf_reg;
0815         reg_rw->offset = (u32) le16_to_cpu(r.rf->offset);
0816         reg_rw->value = (u32) r.bbp->value;
0817         break;
0818     case HostCmd_CMD_PMIC_REG_ACCESS:
0819         r.pmic = &resp->params.pmic_reg;
0820         reg_rw->offset = (u32) le16_to_cpu(r.pmic->offset);
0821         reg_rw->value = (u32) r.pmic->value;
0822         break;
0823     case HostCmd_CMD_CAU_REG_ACCESS:
0824         r.rf = &resp->params.rf_reg;
0825         reg_rw->offset = (u32) le16_to_cpu(r.rf->offset);
0826         reg_rw->value = (u32) r.rf->value;
0827         break;
0828     case HostCmd_CMD_802_11_EEPROM_ACCESS:
0829         r.eeprom = &resp->params.eeprom;
0830         pr_debug("info: EEPROM read len=%x\n",
0831                 le16_to_cpu(r.eeprom->byte_count));
0832         if (eeprom->byte_count < le16_to_cpu(r.eeprom->byte_count)) {
0833             eeprom->byte_count = 0;
0834             pr_debug("info: EEPROM read length is too big\n");
0835             return -1;
0836         }
0837         eeprom->offset = le16_to_cpu(r.eeprom->offset);
0838         eeprom->byte_count = le16_to_cpu(r.eeprom->byte_count);
0839         if (eeprom->byte_count > 0)
0840             memcpy(&eeprom->value, &r.eeprom->value,
0841                    min((u16)MAX_EEPROM_DATA, eeprom->byte_count));
0842         break;
0843     default:
0844         return -1;
0845     }
0846     return 0;
0847 }
0848 
0849 /*
0850  * This function handles the command response of get IBSS coalescing status.
0851  *
0852  * If the received BSSID is different than the current one, the current BSSID,
0853  * beacon interval, ATIM window and ERP information are updated, along with
0854  * changing the ad-hoc state accordingly.
0855  */
0856 static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
0857                           struct host_cmd_ds_command *resp)
0858 {
0859     struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
0860                     &(resp->params.ibss_coalescing);
0861 
0862     if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
0863         return 0;
0864 
0865     mwifiex_dbg(priv->adapter, INFO,
0866             "info: new BSSID %pM\n", ibss_coal_resp->bssid);
0867 
0868     /* If rsp has NULL BSSID, Just return..... No Action */
0869     if (is_zero_ether_addr(ibss_coal_resp->bssid)) {
0870         mwifiex_dbg(priv->adapter, FATAL, "new BSSID is NULL\n");
0871         return 0;
0872     }
0873 
0874     /* If BSSID is diff, modify current BSS parameters */
0875     if (!ether_addr_equal(priv->curr_bss_params.bss_descriptor.mac_address, ibss_coal_resp->bssid)) {
0876         /* BSSID */
0877         memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
0878                ibss_coal_resp->bssid, ETH_ALEN);
0879 
0880         /* Beacon Interval */
0881         priv->curr_bss_params.bss_descriptor.beacon_period
0882             = le16_to_cpu(ibss_coal_resp->beacon_interval);
0883 
0884         /* ERP Information */
0885         priv->curr_bss_params.bss_descriptor.erp_flags =
0886             (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
0887 
0888         priv->adhoc_state = ADHOC_COALESCED;
0889     }
0890 
0891     return 0;
0892 }
0893 static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
0894                  struct host_cmd_ds_command *resp)
0895 {
0896     struct host_cmd_ds_tdls_oper *cmd_tdls_oper = &resp->params.tdls_oper;
0897     u16 reason = le16_to_cpu(cmd_tdls_oper->reason);
0898     u16 action = le16_to_cpu(cmd_tdls_oper->tdls_action);
0899     struct mwifiex_sta_node *node =
0900                mwifiex_get_sta_entry(priv, cmd_tdls_oper->peer_mac);
0901 
0902     switch (action) {
0903     case ACT_TDLS_DELETE:
0904         if (reason) {
0905             if (!node || reason == TDLS_ERR_LINK_NONEXISTENT)
0906                 mwifiex_dbg(priv->adapter, MSG,
0907                         "TDLS link delete for %pM failed: reason %d\n",
0908                         cmd_tdls_oper->peer_mac, reason);
0909             else
0910                 mwifiex_dbg(priv->adapter, ERROR,
0911                         "TDLS link delete for %pM failed: reason %d\n",
0912                         cmd_tdls_oper->peer_mac, reason);
0913         } else {
0914             mwifiex_dbg(priv->adapter, MSG,
0915                     "TDLS link delete for %pM successful\n",
0916                     cmd_tdls_oper->peer_mac);
0917         }
0918         break;
0919     case ACT_TDLS_CREATE:
0920         if (reason) {
0921             mwifiex_dbg(priv->adapter, ERROR,
0922                     "TDLS link creation for %pM failed: reason %d",
0923                     cmd_tdls_oper->peer_mac, reason);
0924             if (node && reason != TDLS_ERR_LINK_EXISTS)
0925                 node->tdls_status = TDLS_SETUP_FAILURE;
0926         } else {
0927             mwifiex_dbg(priv->adapter, MSG,
0928                     "TDLS link creation for %pM successful",
0929                     cmd_tdls_oper->peer_mac);
0930         }
0931         break;
0932     case ACT_TDLS_CONFIG:
0933         if (reason) {
0934             mwifiex_dbg(priv->adapter, ERROR,
0935                     "TDLS link config for %pM failed, reason %d\n",
0936                     cmd_tdls_oper->peer_mac, reason);
0937             if (node)
0938                 node->tdls_status = TDLS_SETUP_FAILURE;
0939         } else {
0940             mwifiex_dbg(priv->adapter, MSG,
0941                     "TDLS link config for %pM successful\n",
0942                     cmd_tdls_oper->peer_mac);
0943         }
0944         break;
0945     default:
0946         mwifiex_dbg(priv->adapter, ERROR,
0947                 "Unknown TDLS command action response %d", action);
0948         return -1;
0949     }
0950 
0951     return 0;
0952 }
0953 /*
0954  * This function handles the command response for subscribe event command.
0955  */
0956 static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
0957                  struct host_cmd_ds_command *resp)
0958 {
0959     struct host_cmd_ds_802_11_subsc_evt *cmd_sub_event =
0960         &resp->params.subsc_evt;
0961 
0962     /* For every subscribe event command (Get/Set/Clear), FW reports the
0963      * current set of subscribed events*/
0964     mwifiex_dbg(priv->adapter, EVENT,
0965             "Bitmap of currently subscribed events: %16x\n",
0966             le16_to_cpu(cmd_sub_event->events));
0967 
0968     return 0;
0969 }
0970 
0971 static int mwifiex_ret_uap_sta_list(struct mwifiex_private *priv,
0972                     struct host_cmd_ds_command *resp)
0973 {
0974     struct host_cmd_ds_sta_list *sta_list =
0975         &resp->params.sta_list;
0976     struct mwifiex_ie_types_sta_info *sta_info = (void *)&sta_list->tlv;
0977     int i;
0978     struct mwifiex_sta_node *sta_node;
0979 
0980     for (i = 0; i < (le16_to_cpu(sta_list->sta_count)); i++) {
0981         sta_node = mwifiex_get_sta_entry(priv, sta_info->mac);
0982         if (unlikely(!sta_node))
0983             continue;
0984 
0985         sta_node->stats.rssi = sta_info->rssi;
0986         sta_info++;
0987     }
0988 
0989     return 0;
0990 }
0991 
0992 /* This function handles the command response of set_cfg_data */
0993 static int mwifiex_ret_cfg_data(struct mwifiex_private *priv,
0994                 struct host_cmd_ds_command *resp)
0995 {
0996     if (resp->result != HostCmd_RESULT_OK) {
0997         mwifiex_dbg(priv->adapter, ERROR, "Cal data cmd resp failed\n");
0998         return -1;
0999     }
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 = &regd->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 }