Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP Wireless LAN device driver: utility functions
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 
0016 static struct mwifiex_debug_data items[] = {
0017     {"debug_mask", item_size(debug_mask),
0018      item_addr(debug_mask), 1},
0019     {"int_counter", item_size(int_counter),
0020      item_addr(int_counter), 1},
0021     {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
0022      item_addr(packets_out[WMM_AC_VO]), 1},
0023     {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
0024      item_addr(packets_out[WMM_AC_VI]), 1},
0025     {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
0026      item_addr(packets_out[WMM_AC_BE]), 1},
0027     {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
0028      item_addr(packets_out[WMM_AC_BK]), 1},
0029     {"tx_buf_size", item_size(tx_buf_size),
0030      item_addr(tx_buf_size), 1},
0031     {"curr_tx_buf_size", item_size(curr_tx_buf_size),
0032      item_addr(curr_tx_buf_size), 1},
0033     {"ps_mode", item_size(ps_mode),
0034      item_addr(ps_mode), 1},
0035     {"ps_state", item_size(ps_state),
0036      item_addr(ps_state), 1},
0037     {"is_deep_sleep", item_size(is_deep_sleep),
0038      item_addr(is_deep_sleep), 1},
0039     {"wakeup_dev_req", item_size(pm_wakeup_card_req),
0040      item_addr(pm_wakeup_card_req), 1},
0041     {"wakeup_tries", item_size(pm_wakeup_fw_try),
0042      item_addr(pm_wakeup_fw_try), 1},
0043     {"hs_configured", item_size(is_hs_configured),
0044      item_addr(is_hs_configured), 1},
0045     {"hs_activated", item_size(hs_activated),
0046      item_addr(hs_activated), 1},
0047     {"num_tx_timeout", item_size(num_tx_timeout),
0048      item_addr(num_tx_timeout), 1},
0049     {"is_cmd_timedout", item_size(is_cmd_timedout),
0050      item_addr(is_cmd_timedout), 1},
0051     {"timeout_cmd_id", item_size(timeout_cmd_id),
0052      item_addr(timeout_cmd_id), 1},
0053     {"timeout_cmd_act", item_size(timeout_cmd_act),
0054      item_addr(timeout_cmd_act), 1},
0055     {"last_cmd_id", item_size(last_cmd_id),
0056      item_addr(last_cmd_id), DBG_CMD_NUM},
0057     {"last_cmd_act", item_size(last_cmd_act),
0058      item_addr(last_cmd_act), DBG_CMD_NUM},
0059     {"last_cmd_index", item_size(last_cmd_index),
0060      item_addr(last_cmd_index), 1},
0061     {"last_cmd_resp_id", item_size(last_cmd_resp_id),
0062      item_addr(last_cmd_resp_id), DBG_CMD_NUM},
0063     {"last_cmd_resp_index", item_size(last_cmd_resp_index),
0064      item_addr(last_cmd_resp_index), 1},
0065     {"last_event", item_size(last_event),
0066      item_addr(last_event), DBG_CMD_NUM},
0067     {"last_event_index", item_size(last_event_index),
0068      item_addr(last_event_index), 1},
0069     {"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap),
0070      item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM},
0071     {"last_mp_wr_ports", item_size(last_mp_wr_ports),
0072      item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM},
0073     {"last_mp_wr_len", item_size(last_mp_wr_len),
0074      item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM},
0075     {"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port),
0076      item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM},
0077     {"last_sdio_mp_index", item_size(last_sdio_mp_index),
0078      item_addr(last_sdio_mp_index), 1},
0079     {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
0080      item_addr(num_cmd_host_to_card_failure), 1},
0081     {"num_cmd_sleep_cfm_fail",
0082      item_size(num_cmd_sleep_cfm_host_to_card_failure),
0083      item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
0084     {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
0085      item_addr(num_tx_host_to_card_failure), 1},
0086     {"num_evt_deauth", item_size(num_event_deauth),
0087      item_addr(num_event_deauth), 1},
0088     {"num_evt_disassoc", item_size(num_event_disassoc),
0089      item_addr(num_event_disassoc), 1},
0090     {"num_evt_link_lost", item_size(num_event_link_lost),
0091      item_addr(num_event_link_lost), 1},
0092     {"num_cmd_deauth", item_size(num_cmd_deauth),
0093      item_addr(num_cmd_deauth), 1},
0094     {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
0095      item_addr(num_cmd_assoc_success), 1},
0096     {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
0097      item_addr(num_cmd_assoc_failure), 1},
0098     {"cmd_sent", item_size(cmd_sent),
0099      item_addr(cmd_sent), 1},
0100     {"data_sent", item_size(data_sent),
0101      item_addr(data_sent), 1},
0102     {"cmd_resp_received", item_size(cmd_resp_received),
0103      item_addr(cmd_resp_received), 1},
0104     {"event_received", item_size(event_received),
0105      item_addr(event_received), 1},
0106 
0107     /* variables defined in struct mwifiex_adapter */
0108     {"cmd_pending", adapter_item_size(cmd_pending),
0109      adapter_item_addr(cmd_pending), 1},
0110     {"tx_pending", adapter_item_size(tx_pending),
0111      adapter_item_addr(tx_pending), 1},
0112     {"rx_pending", adapter_item_size(rx_pending),
0113      adapter_item_addr(rx_pending), 1},
0114 };
0115 
0116 static int num_of_items = ARRAY_SIZE(items);
0117 
0118 /*
0119  * Firmware initialization complete callback handler.
0120  *
0121  * This function wakes up the function waiting on the init
0122  * wait queue for the firmware initialization to complete.
0123  */
0124 int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)
0125 {
0126 
0127     if (adapter->hw_status == MWIFIEX_HW_STATUS_READY)
0128         if (adapter->if_ops.init_fw_port)
0129             adapter->if_ops.init_fw_port(adapter);
0130 
0131     adapter->init_wait_q_woken = true;
0132     wake_up_interruptible(&adapter->init_wait_q);
0133     return 0;
0134 }
0135 
0136 /*
0137  * This function sends init/shutdown command
0138  * to firmware.
0139  */
0140 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
0141                  u32 func_init_shutdown)
0142 {
0143     u16 cmd;
0144 
0145     if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
0146         cmd = HostCmd_CMD_FUNC_INIT;
0147     } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
0148         cmd = HostCmd_CMD_FUNC_SHUTDOWN;
0149     } else {
0150         mwifiex_dbg(priv->adapter, ERROR,
0151                 "unsupported parameter\n");
0152         return -1;
0153     }
0154 
0155     return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true);
0156 }
0157 EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
0158 
0159 /*
0160  * IOCTL request handler to set/get debug information.
0161  *
0162  * This function collates/sets the information from/to different driver
0163  * structures.
0164  */
0165 int mwifiex_get_debug_info(struct mwifiex_private *priv,
0166                struct mwifiex_debug_info *info)
0167 {
0168     struct mwifiex_adapter *adapter = priv->adapter;
0169 
0170     if (info) {
0171         info->debug_mask = adapter->debug_mask;
0172         memcpy(info->packets_out,
0173                priv->wmm.packets_out,
0174                sizeof(priv->wmm.packets_out));
0175         info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size;
0176         info->tx_buf_size = (u32) adapter->tx_buf_size;
0177         info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
0178                                   info->rx_tbl);
0179         info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv,
0180                                 info->tx_tbl);
0181         info->tdls_peer_num = mwifiex_get_tdls_list(priv,
0182                                 info->tdls_list);
0183         info->ps_mode = adapter->ps_mode;
0184         info->ps_state = adapter->ps_state;
0185         info->is_deep_sleep = adapter->is_deep_sleep;
0186         info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
0187         info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
0188         info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED,
0189                           &adapter->work_flags);
0190         info->hs_activated = adapter->hs_activated;
0191         info->is_cmd_timedout = test_bit(MWIFIEX_IS_CMD_TIMEDOUT,
0192                          &adapter->work_flags);
0193         info->num_cmd_host_to_card_failure
0194                 = adapter->dbg.num_cmd_host_to_card_failure;
0195         info->num_cmd_sleep_cfm_host_to_card_failure
0196             = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
0197         info->num_tx_host_to_card_failure
0198                 = adapter->dbg.num_tx_host_to_card_failure;
0199         info->num_event_deauth = adapter->dbg.num_event_deauth;
0200         info->num_event_disassoc = adapter->dbg.num_event_disassoc;
0201         info->num_event_link_lost = adapter->dbg.num_event_link_lost;
0202         info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
0203         info->num_cmd_assoc_success =
0204                     adapter->dbg.num_cmd_assoc_success;
0205         info->num_cmd_assoc_failure =
0206                     adapter->dbg.num_cmd_assoc_failure;
0207         info->num_tx_timeout = adapter->dbg.num_tx_timeout;
0208         info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
0209         info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
0210         memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
0211                sizeof(adapter->dbg.last_cmd_id));
0212         memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
0213                sizeof(adapter->dbg.last_cmd_act));
0214         info->last_cmd_index = adapter->dbg.last_cmd_index;
0215         memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
0216                sizeof(adapter->dbg.last_cmd_resp_id));
0217         info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
0218         memcpy(info->last_event, adapter->dbg.last_event,
0219                sizeof(adapter->dbg.last_event));
0220         info->last_event_index = adapter->dbg.last_event_index;
0221         memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap,
0222                sizeof(adapter->dbg.last_mp_wr_bitmap));
0223         memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports,
0224                sizeof(adapter->dbg.last_mp_wr_ports));
0225         memcpy(info->last_mp_curr_wr_port,
0226                adapter->dbg.last_mp_curr_wr_port,
0227                sizeof(adapter->dbg.last_mp_curr_wr_port));
0228         memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len,
0229                sizeof(adapter->dbg.last_mp_wr_len));
0230         info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index;
0231         info->data_sent = adapter->data_sent;
0232         info->cmd_sent = adapter->cmd_sent;
0233         info->cmd_resp_received = adapter->cmd_resp_received;
0234     }
0235 
0236     return 0;
0237 }
0238 
0239 int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf,
0240                  struct mwifiex_debug_info *info)
0241 {
0242     char *p = buf;
0243     struct mwifiex_debug_data *d = &items[0];
0244     size_t size, addr;
0245     long val;
0246     int i, j;
0247 
0248     if (!info)
0249         return 0;
0250 
0251     for (i = 0; i < num_of_items; i++) {
0252         p += sprintf(p, "%s=", d[i].name);
0253 
0254         size = d[i].size / d[i].num;
0255 
0256         if (i < (num_of_items - 3))
0257             addr = d[i].addr + (size_t)info;
0258         else /* The last 3 items are struct mwifiex_adapter variables */
0259             addr = d[i].addr + (size_t)priv->adapter;
0260 
0261         for (j = 0; j < d[i].num; j++) {
0262             switch (size) {
0263             case 1:
0264                 val = *((u8 *)addr);
0265                 break;
0266             case 2:
0267                 val = get_unaligned((u16 *)addr);
0268                 break;
0269             case 4:
0270                 val = get_unaligned((u32 *)addr);
0271                 break;
0272             case 8:
0273                 val = get_unaligned((long long *)addr);
0274                 break;
0275             default:
0276                 val = -1;
0277                 break;
0278             }
0279 
0280             p += sprintf(p, "%#lx ", val);
0281             addr += size;
0282         }
0283 
0284         p += sprintf(p, "\n");
0285     }
0286 
0287     if (info->tx_tbl_num) {
0288         p += sprintf(p, "Tx BA stream table:\n");
0289         for (i = 0; i < info->tx_tbl_num; i++)
0290             p += sprintf(p, "tid = %d, ra = %pM\n",
0291                      info->tx_tbl[i].tid, info->tx_tbl[i].ra);
0292     }
0293 
0294     if (info->rx_tbl_num) {
0295         p += sprintf(p, "Rx reorder table:\n");
0296         for (i = 0; i < info->rx_tbl_num; i++) {
0297             p += sprintf(p, "tid = %d, ta = %pM, ",
0298                      info->rx_tbl[i].tid,
0299                      info->rx_tbl[i].ta);
0300             p += sprintf(p, "start_win = %d, ",
0301                      info->rx_tbl[i].start_win);
0302             p += sprintf(p, "win_size = %d, buffer: ",
0303                      info->rx_tbl[i].win_size);
0304 
0305             for (j = 0; j < info->rx_tbl[i].win_size; j++)
0306                 p += sprintf(p, "%c ",
0307                          info->rx_tbl[i].buffer[j] ?
0308                          '1' : '0');
0309 
0310             p += sprintf(p, "\n");
0311         }
0312     }
0313 
0314     if (info->tdls_peer_num) {
0315         p += sprintf(p, "TDLS peer table:\n");
0316         for (i = 0; i < info->tdls_peer_num; i++) {
0317             p += sprintf(p, "peer = %pM",
0318                      info->tdls_list[i].peer_addr);
0319             p += sprintf(p, "\n");
0320         }
0321     }
0322 
0323     return p - buf;
0324 }
0325 
0326 static int
0327 mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
0328               struct rxpd *rx_pd)
0329 {
0330     u16 stype;
0331     u8 category, action_code, *addr2;
0332     struct ieee80211_hdr *ieee_hdr = (void *)payload;
0333 
0334     stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE);
0335 
0336     switch (stype) {
0337     case IEEE80211_STYPE_ACTION:
0338         category = *(payload + sizeof(struct ieee80211_hdr));
0339         switch (category) {
0340         case WLAN_CATEGORY_PUBLIC:
0341             action_code = *(payload + sizeof(struct ieee80211_hdr)
0342                     + 1);
0343             if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
0344                 addr2 = ieee_hdr->addr2;
0345                 mwifiex_dbg(priv->adapter, INFO,
0346                         "TDLS discovery response %pM nf=%d, snr=%d\n",
0347                         addr2, rx_pd->nf, rx_pd->snr);
0348                 mwifiex_auto_tdls_update_peer_signal(priv,
0349                                      addr2,
0350                                      rx_pd->snr,
0351                                      rx_pd->nf);
0352             }
0353             break;
0354         case WLAN_CATEGORY_BACK:
0355             /*we dont indicate BACK action frames to cfg80211*/
0356             mwifiex_dbg(priv->adapter, INFO,
0357                     "drop BACK action frames");
0358             return -1;
0359         default:
0360             mwifiex_dbg(priv->adapter, INFO,
0361                     "unknown public action frame category %d\n",
0362                     category);
0363         }
0364         break;
0365     default:
0366         mwifiex_dbg(priv->adapter, INFO,
0367             "unknown mgmt frame subtype %#x\n", stype);
0368         return 0;
0369     }
0370 
0371     return 0;
0372 }
0373 /*
0374  * This function processes the received management packet and send it
0375  * to the kernel.
0376  */
0377 int
0378 mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
0379                 struct sk_buff *skb)
0380 {
0381     struct rxpd *rx_pd;
0382     u16 pkt_len;
0383     struct ieee80211_hdr *ieee_hdr;
0384 
0385     if (!skb)
0386         return -1;
0387 
0388     if (!priv->mgmt_frame_mask ||
0389         priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
0390         mwifiex_dbg(priv->adapter, ERROR,
0391                 "do not receive mgmt frames on uninitialized intf");
0392         return -1;
0393     }
0394 
0395     rx_pd = (struct rxpd *)skb->data;
0396 
0397     skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
0398     skb_pull(skb, sizeof(pkt_len));
0399 
0400     pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
0401 
0402     ieee_hdr = (void *)skb->data;
0403     if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
0404         if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
0405                           pkt_len, rx_pd))
0406             return -1;
0407     }
0408     /* Remove address4 */
0409     memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
0410         skb->data + sizeof(struct ieee80211_hdr),
0411         pkt_len - sizeof(struct ieee80211_hdr));
0412 
0413     pkt_len -= ETH_ALEN + sizeof(pkt_len);
0414     rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
0415 
0416     cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
0417              CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
0418              0);
0419 
0420     return 0;
0421 }
0422 
0423 /*
0424  * This function processes the received packet before sending it to the
0425  * kernel.
0426  *
0427  * It extracts the SKB from the received buffer and sends it to kernel.
0428  * In case the received buffer does not contain the data in SKB format,
0429  * the function creates a blank SKB, fills it with the data from the
0430  * received buffer and then sends this new SKB to the kernel.
0431  */
0432 int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
0433 {
0434     struct mwifiex_sta_node *src_node;
0435     struct ethhdr *p_ethhdr;
0436 
0437     if (!skb)
0438         return -1;
0439 
0440     priv->stats.rx_bytes += skb->len;
0441     priv->stats.rx_packets++;
0442 
0443     if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
0444         p_ethhdr = (void *)skb->data;
0445         src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
0446         if (src_node) {
0447             src_node->stats.last_rx = jiffies;
0448             src_node->stats.rx_bytes += skb->len;
0449             src_node->stats.rx_packets++;
0450         }
0451     }
0452 
0453     skb->dev = priv->netdev;
0454     skb->protocol = eth_type_trans(skb, priv->netdev);
0455     skb->ip_summed = CHECKSUM_NONE;
0456 
0457     /* This is required only in case of 11n and USB/PCIE as we alloc
0458      * a buffer of 4K only if its 11N (to be able to receive 4K
0459      * AMSDU packets). In case of SD we allocate buffers based
0460      * on the size of packet and hence this is not needed.
0461      *
0462      * Modifying the truesize here as our allocation for each
0463      * skb is 4K but we only receive 2K packets and this cause
0464      * the kernel to start dropping packets in case where
0465      * application has allocated buffer based on 2K size i.e.
0466      * if there a 64K packet received (in IP fragments and
0467      * application allocates 64K to receive this packet but
0468      * this packet would almost double up because we allocate
0469      * each 1.5K fragment in 4K and pass it up. As soon as the
0470      * 64K limit hits kernel will start to drop rest of the
0471      * fragments. Currently we fail the Filesndl-ht.scr script
0472      * for UDP, hence this fix
0473      */
0474     if ((priv->adapter->iface_type == MWIFIEX_USB ||
0475          priv->adapter->iface_type == MWIFIEX_PCIE) &&
0476         (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
0477         skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
0478 
0479     netif_rx(skb);
0480     return 0;
0481 }
0482 
0483 /*
0484  * IOCTL completion callback handler.
0485  *
0486  * This function is called when a pending IOCTL is completed.
0487  *
0488  * If work queue support is enabled, the function wakes up the
0489  * corresponding waiting function. Otherwise, it processes the
0490  * IOCTL response and frees the response buffer.
0491  */
0492 int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
0493              struct cmd_ctrl_node *cmd_node)
0494 {
0495     WARN_ON(!cmd_node->wait_q_enabled);
0496     mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n",
0497             adapter->cmd_wait_q.status);
0498 
0499     *cmd_node->condition = true;
0500     wake_up_interruptible(&adapter->cmd_wait_q.wait);
0501 
0502     return 0;
0503 }
0504 
0505 /* This function will return the pointer to station entry in station list
0506  * table which matches specified mac address.
0507  * This function should be called after acquiring RA list spinlock.
0508  * NULL is returned if station entry is not found in associated STA list.
0509  */
0510 struct mwifiex_sta_node *
0511 mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac)
0512 {
0513     struct mwifiex_sta_node *node;
0514 
0515     if (!mac)
0516         return NULL;
0517 
0518     list_for_each_entry(node, &priv->sta_list, list) {
0519         if (!memcmp(node->mac_addr, mac, ETH_ALEN))
0520             return node;
0521     }
0522 
0523     return NULL;
0524 }
0525 
0526 static struct mwifiex_sta_node *
0527 mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status)
0528 {
0529     struct mwifiex_sta_node *node;
0530 
0531     list_for_each_entry(node, &priv->sta_list, list) {
0532         if (node->tdls_status == status)
0533             return node;
0534     }
0535 
0536     return NULL;
0537 }
0538 
0539 /* If tdls channel switching is on-going, tx data traffic should be
0540  * blocked until the switching stage completed.
0541  */
0542 u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv)
0543 {
0544     struct mwifiex_sta_node *sta_ptr;
0545 
0546     if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
0547         return false;
0548 
0549     sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING);
0550     if (sta_ptr)
0551         return true;
0552 
0553     return false;
0554 }
0555 
0556 u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv)
0557 {
0558     struct mwifiex_sta_node *sta_ptr;
0559 
0560     if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
0561         return false;
0562 
0563     sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN);
0564     if (sta_ptr)
0565         return true;
0566 
0567     return false;
0568 }
0569 
0570 /* If tdls channel switching is on-going or tdls operate on off-channel,
0571  * cmd path should be blocked until tdls switched to base-channel.
0572  */
0573 u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv)
0574 {
0575     if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
0576         return true;
0577 
0578     if (mwifiex_is_tdls_chan_switching(priv) ||
0579         mwifiex_is_tdls_off_chan(priv))
0580         return false;
0581 
0582     return true;
0583 }
0584 
0585 /* This function will add a sta_node entry to associated station list
0586  * table with the given mac address.
0587  * If entry exist already, existing entry is returned.
0588  * If received mac address is NULL, NULL is returned.
0589  */
0590 struct mwifiex_sta_node *
0591 mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
0592 {
0593     struct mwifiex_sta_node *node;
0594 
0595     if (!mac)
0596         return NULL;
0597 
0598     spin_lock_bh(&priv->sta_list_spinlock);
0599     node = mwifiex_get_sta_entry(priv, mac);
0600     if (node)
0601         goto done;
0602 
0603     node = kzalloc(sizeof(*node), GFP_ATOMIC);
0604     if (!node)
0605         goto done;
0606 
0607     memcpy(node->mac_addr, mac, ETH_ALEN);
0608     list_add_tail(&node->list, &priv->sta_list);
0609 
0610 done:
0611     spin_unlock_bh(&priv->sta_list_spinlock);
0612     return node;
0613 }
0614 
0615 /* This function will search for HT IE in association request IEs
0616  * and set station HT parameters accordingly.
0617  */
0618 void
0619 mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
0620                int ies_len, struct mwifiex_sta_node *node)
0621 {
0622     struct ieee_types_header *ht_cap_ie;
0623     const struct ieee80211_ht_cap *ht_cap;
0624 
0625     if (!ies)
0626         return;
0627 
0628     ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
0629                          ies_len);
0630     if (ht_cap_ie) {
0631         ht_cap = (void *)(ht_cap_ie + 1);
0632         node->is_11n_enabled = 1;
0633         node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
0634                   IEEE80211_HT_CAP_MAX_AMSDU ?
0635                   MWIFIEX_TX_DATA_BUF_SIZE_8K :
0636                   MWIFIEX_TX_DATA_BUF_SIZE_4K;
0637     } else {
0638         node->is_11n_enabled = 0;
0639     }
0640 
0641     return;
0642 }
0643 
0644 /* This function will delete a station entry from station list */
0645 void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
0646 {
0647     struct mwifiex_sta_node *node;
0648 
0649     spin_lock_bh(&priv->sta_list_spinlock);
0650 
0651     node = mwifiex_get_sta_entry(priv, mac);
0652     if (node) {
0653         list_del(&node->list);
0654         kfree(node);
0655     }
0656 
0657     spin_unlock_bh(&priv->sta_list_spinlock);
0658     return;
0659 }
0660 
0661 /* This function will delete all stations from associated station list. */
0662 void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
0663 {
0664     struct mwifiex_sta_node *node, *tmp;
0665 
0666     spin_lock_bh(&priv->sta_list_spinlock);
0667 
0668     list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
0669         list_del(&node->list);
0670         kfree(node);
0671     }
0672 
0673     INIT_LIST_HEAD(&priv->sta_list);
0674     spin_unlock_bh(&priv->sta_list_spinlock);
0675     return;
0676 }
0677 
0678 /* This function adds histogram data to histogram array*/
0679 void mwifiex_hist_data_add(struct mwifiex_private *priv,
0680                u8 rx_rate, s8 snr, s8 nflr)
0681 {
0682     struct mwifiex_histogram_data *phist_data = priv->hist_data;
0683 
0684     if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES)
0685         mwifiex_hist_data_reset(priv);
0686     mwifiex_hist_data_set(priv, rx_rate, snr, nflr);
0687 }
0688 
0689 /* function to add histogram record */
0690 void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
0691                s8 nflr)
0692 {
0693     struct mwifiex_histogram_data *phist_data = priv->hist_data;
0694     s8 nf   = -nflr;
0695     s8 rssi = snr - nflr;
0696 
0697     atomic_inc(&phist_data->num_samples);
0698     atomic_inc(&phist_data->rx_rate[rx_rate]);
0699     atomic_inc(&phist_data->snr[snr + 128]);
0700     atomic_inc(&phist_data->noise_flr[nf + 128]);
0701     atomic_inc(&phist_data->sig_str[rssi + 128]);
0702 }
0703 
0704 /* function to reset histogram data during init/reset */
0705 void mwifiex_hist_data_reset(struct mwifiex_private *priv)
0706 {
0707     int ix;
0708     struct mwifiex_histogram_data *phist_data = priv->hist_data;
0709 
0710     atomic_set(&phist_data->num_samples, 0);
0711     for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++)
0712         atomic_set(&phist_data->rx_rate[ix], 0);
0713     for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++)
0714         atomic_set(&phist_data->snr[ix], 0);
0715     for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++)
0716         atomic_set(&phist_data->noise_flr[ix], 0);
0717     for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++)
0718         atomic_set(&phist_data->sig_str[ix], 0);
0719 }
0720 
0721 void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags)
0722 {
0723     struct sk_buff *skb;
0724     int buf_len, pad;
0725 
0726     buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ;
0727 
0728     skb = __dev_alloc_skb(buf_len, flags);
0729 
0730     if (!skb)
0731         return NULL;
0732 
0733     skb_reserve(skb, MWIFIEX_RX_HEADROOM);
0734 
0735     pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) -
0736           (long)skb->data;
0737 
0738     skb_reserve(skb, pad);
0739 
0740     return skb;
0741 }
0742 EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf);
0743 
0744 void mwifiex_fw_dump_event(struct mwifiex_private *priv)
0745 {
0746     mwifiex_send_cmd(priv, HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET,
0747              0, NULL, true);
0748 }
0749 EXPORT_SYMBOL_GPL(mwifiex_fw_dump_event);