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