Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  wmi.c   Sprache: C

 
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#include <linux/skbuff.h>
#include <linux/ctype.h>
#include <net/mac80211.h>
#include <net/cfg80211.h>
#include <linux/completion.h>
#include <linux/if_ether.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/uuid.h>
#include <linux/time.h>
#include <linux/of.h>
#include "core.h"
#include "debug.h"
#include "mac.h"
#include "hw.h"
#include "peer.h"
#include "testmode.h"
#include "p2p.h"

struct wmi_tlv_policy {
 size_t min_len;
};

struct wmi_tlv_svc_ready_parse {
 bool wmi_svc_bitmap_done;
};

struct wmi_tlv_dma_ring_caps_parse {
 struct wmi_dma_ring_capabilities *dma_ring_caps;
 u32 n_dma_ring_caps;
};

struct wmi_tlv_svc_rdy_ext_parse {
 struct ath11k_service_ext_param param;
 struct wmi_soc_mac_phy_hw_mode_caps *hw_caps;
 struct wmi_hw_mode_capabilities *hw_mode_caps;
 u32 n_hw_mode_caps;
 u32 tot_phy_id;
 struct wmi_hw_mode_capabilities pref_hw_mode_caps;
 struct wmi_mac_phy_capabilities *mac_phy_caps;
 u32 n_mac_phy_caps;
 struct wmi_soc_hal_reg_capabilities *soc_hal_reg_caps;
 struct wmi_hal_reg_capabilities_ext *ext_hal_reg_caps;
 u32 n_ext_hal_reg_caps;
 struct wmi_tlv_dma_ring_caps_parse dma_caps_parse;
 bool hw_mode_done;
 bool mac_phy_done;
 bool ext_hal_reg_done;
 bool mac_phy_chainmask_combo_done;
 bool mac_phy_chainmask_cap_done;
 bool oem_dma_ring_cap_done;
 bool dma_ring_cap_done;
};

struct wmi_tlv_svc_rdy_ext2_parse {
 struct wmi_tlv_dma_ring_caps_parse dma_caps_parse;
 bool dma_ring_cap_done;
};

struct wmi_tlv_rdy_parse {
 u32 num_extra_mac_addr;
};

struct wmi_tlv_dma_buf_release_parse {
 struct ath11k_wmi_dma_buf_release_fixed_param fixed;
 struct wmi_dma_buf_release_entry *buf_entry;
 struct wmi_dma_buf_release_meta_data *meta_data;
 u32 num_buf_entry;
 u32 num_meta;
 bool buf_entry_done;
 bool meta_data_done;
};

struct wmi_tlv_fw_stats_parse {
 const struct wmi_stats_event *ev;
 const struct wmi_per_chain_rssi_stats *rssi;
 struct ath11k_fw_stats *stats;
 int rssi_num;
 bool chain_rssi_done;
};

struct wmi_tlv_mgmt_rx_parse {
 const struct wmi_mgmt_rx_hdr *fixed;
 const u8 *frame_buf;
 bool frame_buf_done;
};

static const struct wmi_tlv_policy wmi_tlv_policies[] = {
 [WMI_TAG_ARRAY_BYTE]
  = { .min_len = 0 },
 [WMI_TAG_ARRAY_UINT32]
  = { .min_len = 0 },
 [WMI_TAG_SERVICE_READY_EVENT]
  = { .min_len = sizeof(struct wmi_service_ready_event) },
 [WMI_TAG_SERVICE_READY_EXT_EVENT]
  = { .min_len =  sizeof(struct wmi_service_ready_ext_event) },
 [WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS]
  = { .min_len = sizeof(struct wmi_soc_mac_phy_hw_mode_caps) },
 [WMI_TAG_SOC_HAL_REG_CAPABILITIES]
  = { .min_len = sizeof(struct wmi_soc_hal_reg_capabilities) },
 [WMI_TAG_VDEV_START_RESPONSE_EVENT]
  = { .min_len = sizeof(struct wmi_vdev_start_resp_event) },
 [WMI_TAG_PEER_DELETE_RESP_EVENT]
  = { .min_len = sizeof(struct wmi_peer_delete_resp_event) },
 [WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT]
  = { .min_len = sizeof(struct wmi_bcn_tx_status_event) },
 [WMI_TAG_VDEV_STOPPED_EVENT]
  = { .min_len = sizeof(struct wmi_vdev_stopped_event) },
 [WMI_TAG_REG_CHAN_LIST_CC_EVENT]
  = { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) },
 [WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]
  = { .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) },
 [WMI_TAG_MGMT_RX_HDR]
  = { .min_len = sizeof(struct wmi_mgmt_rx_hdr) },
 [WMI_TAG_MGMT_TX_COMPL_EVENT]
  = { .min_len = sizeof(struct wmi_mgmt_tx_compl_event) },
 [WMI_TAG_SCAN_EVENT]
  = { .min_len = sizeof(struct wmi_scan_event) },
 [WMI_TAG_PEER_STA_KICKOUT_EVENT]
  = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) },
 [WMI_TAG_ROAM_EVENT]
  = { .min_len = sizeof(struct wmi_roam_event) },
 [WMI_TAG_CHAN_INFO_EVENT]
  = { .min_len = sizeof(struct wmi_chan_info_event) },
 [WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT]
  = { .min_len = sizeof(struct wmi_pdev_bss_chan_info_event) },
 [WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT]
  = { .min_len = sizeof(struct wmi_vdev_install_key_compl_event) },
 [WMI_TAG_READY_EVENT] = {
  .min_len = sizeof(struct wmi_ready_event_min) },
 [WMI_TAG_SERVICE_AVAILABLE_EVENT]
  = {.min_len = sizeof(struct wmi_service_available_event) },
 [WMI_TAG_PEER_ASSOC_CONF_EVENT]
  = { .min_len = sizeof(struct wmi_peer_assoc_conf_event) },
 [WMI_TAG_STATS_EVENT]
  = { .min_len = sizeof(struct wmi_stats_event) },
 [WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT]
  = { .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
 [WMI_TAG_HOST_SWFDA_EVENT] = {
  .min_len = sizeof(struct wmi_fils_discovery_event) },
 [WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT] = {
  .min_len = sizeof(struct wmi_probe_resp_tx_status_event) },
 [WMI_TAG_VDEV_DELETE_RESP_EVENT] = {
  .min_len = sizeof(struct wmi_vdev_delete_resp_event) },
 [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = {
  .min_len = sizeof(struct wmi_obss_color_collision_event) },
 [WMI_TAG_11D_NEW_COUNTRY_EVENT] = {
  .min_len = sizeof(struct wmi_11d_new_cc_ev) },
 [WMI_TAG_PER_CHAIN_RSSI_STATS] = {
  .min_len = sizeof(struct wmi_per_chain_rssi_stats) },
 [WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = {
  .min_len = sizeof(struct wmi_twt_add_dialog_event) },
 [WMI_TAG_P2P_NOA_INFO] = {
  .min_len = sizeof(struct ath11k_wmi_p2p_noa_info) },
 [WMI_TAG_P2P_NOA_EVENT] = {
  .min_len = sizeof(struct wmi_p2p_noa_event) },
};

#define PRIMAP(_hw_mode_) \
 [_hw_mode_] = _hw_mode_##_PRI

static const int ath11k_hw_mode_pri_map[] = {
 PRIMAP(WMI_HOST_HW_MODE_SINGLE),
 PRIMAP(WMI_HOST_HW_MODE_DBS),
 PRIMAP(WMI_HOST_HW_MODE_SBS_PASSIVE),
 PRIMAP(WMI_HOST_HW_MODE_SBS),
 PRIMAP(WMI_HOST_HW_MODE_DBS_SBS),
 PRIMAP(WMI_HOST_HW_MODE_DBS_OR_SBS),
 /* keep last */
 PRIMAP(WMI_HOST_HW_MODE_MAX),
};

static int
ath11k_wmi_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len,
      int (*iter)(struct ath11k_base *ab, u16 tag, u16 len,
    const void *ptr, void *data),
      void *data)
{
 const void *begin = ptr;
 const struct wmi_tlv *tlv;
 u16 tlv_tag, tlv_len;
 int ret;

 while (len > 0) {
  if (len < sizeof(*tlv)) {
   ath11k_err(ab, "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
       ptr - begin, len, sizeof(*tlv));
   return -EINVAL;
  }

  tlv = ptr;
  tlv_tag = FIELD_GET(WMI_TLV_TAG, tlv->header);
  tlv_len = FIELD_GET(WMI_TLV_LEN, tlv->header);
  ptr += sizeof(*tlv);
  len -= sizeof(*tlv);

  if (tlv_len > len) {
   ath11k_err(ab, "wmi tlv parse failure of tag %u at byte %zd (%zu bytes left, %u expected)\n",
       tlv_tag, ptr - begin, len, tlv_len);
   return -EINVAL;
  }

  if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) &&
      wmi_tlv_policies[tlv_tag].min_len &&
      wmi_tlv_policies[tlv_tag].min_len > tlv_len) {
   ath11k_err(ab, "wmi tlv parse failure of tag %u at byte %zd (%u bytes is less than min length %zu)\n",
       tlv_tag, ptr - begin, tlv_len,
       wmi_tlv_policies[tlv_tag].min_len);
   return -EINVAL;
  }

  ret = iter(ab, tlv_tag, tlv_len, ptr, data);
  if (ret)
   return ret;

  ptr += tlv_len;
  len -= tlv_len;
 }

 return 0;
}

static int ath11k_wmi_tlv_iter_parse(struct ath11k_base *ab, u16 tag, u16 len,
         const void *ptr, void *data)
{
 const void **tb = data;

 if (tag < WMI_TAG_MAX)
  tb[tag] = ptr;

 return 0;
}

static int ath11k_wmi_tlv_parse(struct ath11k_base *ar, const void **tb,
    const void *ptr, size_t len)
{
 return ath11k_wmi_tlv_iter(ar, ptr, len, ath11k_wmi_tlv_iter_parse,
       (void *)tb);
}

const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,
     struct sk_buff *skb, gfp_t gfp)
{
 const void **tb;
 int ret;

 tb = kcalloc(WMI_TAG_MAX, sizeof(*tb), gfp);
 if (!tb)
  return ERR_PTR(-ENOMEM);

 ret = ath11k_wmi_tlv_parse(ab, tb, skb->data, skb->len);
 if (ret) {
  kfree(tb);
  return ERR_PTR(ret);
 }

 return tb;
}

static int ath11k_wmi_cmd_send_nowait(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
          u32 cmd_id)
{
 struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
 struct ath11k_base *ab = wmi->wmi_ab->ab;
 struct wmi_cmd_hdr *cmd_hdr;
 int ret;
 u32 cmd = 0;

 if (skb_push(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
  return -ENOMEM;

 cmd |= FIELD_PREP(WMI_CMD_HDR_CMD_ID, cmd_id);

 cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
 cmd_hdr->cmd_id = cmd;

 trace_ath11k_wmi_cmd(ab, cmd_id, skb->data, skb->len);

 memset(skb_cb, 0, sizeof(*skb_cb));
 ret = ath11k_htc_send(&ab->htc, wmi->eid, skb);

 if (ret)
  goto err_pull;

 return 0;

err_pull:
 skb_pull(skb, sizeof(struct wmi_cmd_hdr));
 return ret;
}

int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
   u32 cmd_id)
{
 struct ath11k_wmi_base *wmi_ab = wmi->wmi_ab;
 int ret = -EOPNOTSUPP;
 struct ath11k_base *ab = wmi_ab->ab;

 might_sleep();

 if (ab->hw_params.credit_flow) {
  wait_event_timeout(wmi_ab->tx_credits_wq, ({
   ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id);

   if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH,
         &wmi_ab->ab->dev_flags))
    ret = -ESHUTDOWN;

   (ret != -EAGAIN);
   }), WMI_SEND_TIMEOUT_HZ);
 } else {
  wait_event_timeout(wmi->tx_ce_desc_wq, ({
   ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id);

   if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH,
         &wmi_ab->ab->dev_flags))
    ret = -ESHUTDOWN;

   (ret != -ENOBUFS);
   }), WMI_SEND_TIMEOUT_HZ);
 }

 if (ret == -EAGAIN)
  ath11k_warn(wmi_ab->ab, "wmi command %d timeout\n", cmd_id);

 if (ret == -ENOBUFS)
  ath11k_warn(wmi_ab->ab, "ce desc not available for wmi command %d\n",
       cmd_id);

 return ret;
}

static int ath11k_pull_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
         const void *ptr,
         struct ath11k_service_ext_param *param)
{
 const struct wmi_service_ready_ext_event *ev = ptr;

 if (!ev)
  return -EINVAL;

 /* Move this to host based bitmap */
 param->default_conc_scan_config_bits = ev->default_conc_scan_config_bits;
 param->default_fw_config_bits = ev->default_fw_config_bits;
 param->he_cap_info = ev->he_cap_info;
 param->mpdu_density = ev->mpdu_density;
 param->max_bssid_rx_filters = ev->max_bssid_rx_filters;
 memcpy(¶m->ppet, &ev->ppet, sizeof(param->ppet));

 return 0;
}

static int
ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
          struct wmi_soc_mac_phy_hw_mode_caps *hw_caps,
          struct wmi_hw_mode_capabilities *wmi_hw_mode_caps,
          struct wmi_soc_hal_reg_capabilities *hal_reg_caps,
          struct wmi_mac_phy_capabilities *wmi_mac_phy_caps,
          u8 hw_mode_id, u8 phy_id,
          struct ath11k_pdev *pdev)
{
 struct wmi_mac_phy_capabilities *mac_phy_caps;
 struct ath11k_base *ab = wmi_handle->wmi_ab->ab;
 struct ath11k_band_cap *cap_band;
 struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
 u32 phy_map;
 u32 hw_idx, phy_idx = 0;

 if (!hw_caps || !wmi_hw_mode_caps || !hal_reg_caps)
  return -EINVAL;

 for (hw_idx = 0; hw_idx < hw_caps->num_hw_modes; hw_idx++) {
  if (hw_mode_id == wmi_hw_mode_caps[hw_idx].hw_mode_id)
   break;

  phy_map = wmi_hw_mode_caps[hw_idx].phy_id_map;
  while (phy_map) {
   phy_map >>= 1;
   phy_idx++;
  }
 }

 if (hw_idx == hw_caps->num_hw_modes)
  return -EINVAL;

 phy_idx += phy_id;
 if (phy_id >= hal_reg_caps->num_phy)
  return -EINVAL;

 mac_phy_caps = wmi_mac_phy_caps + phy_idx;

 pdev->pdev_id = mac_phy_caps->pdev_id;
 pdev_cap->supported_bands |= mac_phy_caps->supported_bands;
 pdev_cap->ampdu_density = mac_phy_caps->ampdu_density;
 ab->target_pdev_ids[ab->target_pdev_count].supported_bands =
  mac_phy_caps->supported_bands;
 ab->target_pdev_ids[ab->target_pdev_count].pdev_id = mac_phy_caps->pdev_id;
 ab->target_pdev_count++;

 if (!(mac_phy_caps->supported_bands & WMI_HOST_WLAN_2G_CAP) &&
     !(mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP))
  return -EINVAL;

 /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
 * band to band for a single radio, need to see how this should be
 * handled.
 */

 if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_2G_CAP) {
  pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_2g;
  pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_2g;
 }

 if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP) {
  pdev_cap->vht_cap = mac_phy_caps->vht_cap_info_5g;
  pdev_cap->vht_mcs = mac_phy_caps->vht_supp_mcs_5g;
  pdev_cap->he_mcs = mac_phy_caps->he_supp_mcs_5g;
  pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_5g;
  pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_5g;
  pdev_cap->nss_ratio_enabled =
   WMI_NSS_RATIO_ENABLE_DISABLE_GET(mac_phy_caps->nss_ratio);
  pdev_cap->nss_ratio_info =
   WMI_NSS_RATIO_INFO_GET(mac_phy_caps->nss_ratio);
 }

 /* tx/rx chainmask reported from fw depends on the actual hw chains used,
 * For example, for 4x4 capable macphys, first 4 chains can be used for first
 * mac and the remaining 4 chains can be used for the second mac or vice-versa.
 * In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0
 * will be advertised for second mac or vice-versa. Compute the shift value
 * for tx/rx chainmask which will be used to advertise supported ht/vht rates to
 * mac80211.
 */

 pdev_cap->tx_chain_mask_shift =
   find_first_bit((unsigned long *)&pdev_cap->tx_chain_mask, 32);
 pdev_cap->rx_chain_mask_shift =
   find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32);

 if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_2G_CAP) {
  cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
  cap_band->phy_id = mac_phy_caps->phy_id;
  cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g;
  cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g;
  cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g;
  cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext;
  cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g;
  memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g,
         sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
  memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet2g,
         sizeof(struct ath11k_ppe_threshold));
 }

 if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP) {
  cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
  cap_band->phy_id = mac_phy_caps->phy_id;
  cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g;
  cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g;
  cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g;
  cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext;
  cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g;
  memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g,
         sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
  memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g,
         sizeof(struct ath11k_ppe_threshold));

  cap_band = &pdev_cap->band[NL80211_BAND_6GHZ];
  cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g;
  cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g;
  cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g;
  cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext;
  cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g;
  memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g,
         sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
  memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g,
         sizeof(struct ath11k_ppe_threshold));
 }

 return 0;
}

static int
ath11k_pull_reg_cap_svc_rdy_ext(struct ath11k_pdev_wmi *wmi_handle,
    struct wmi_soc_hal_reg_capabilities *reg_caps,
    struct wmi_hal_reg_capabilities_ext *wmi_ext_reg_cap,
    u8 phy_idx,
    struct ath11k_hal_reg_capabilities_ext *param)
{
 struct wmi_hal_reg_capabilities_ext *ext_reg_cap;

 if (!reg_caps || !wmi_ext_reg_cap)
  return -EINVAL;

 if (phy_idx >= reg_caps->num_phy)
  return -EINVAL;

 ext_reg_cap = &wmi_ext_reg_cap[phy_idx];

 param->phy_id = ext_reg_cap->phy_id;
 param->eeprom_reg_domain = ext_reg_cap->eeprom_reg_domain;
 param->eeprom_reg_domain_ext =
         ext_reg_cap->eeprom_reg_domain_ext;
 param->regcap1 = ext_reg_cap->regcap1;
 param->regcap2 = ext_reg_cap->regcap2;
 /* check if param->wireless_mode is needed */
 param->low_2ghz_chan = ext_reg_cap->low_2ghz_chan;
 param->high_2ghz_chan = ext_reg_cap->high_2ghz_chan;
 param->low_5ghz_chan = ext_reg_cap->low_5ghz_chan;
 param->high_5ghz_chan = ext_reg_cap->high_5ghz_chan;

 return 0;
}

static int ath11k_pull_service_ready_tlv(struct ath11k_base *ab,
      const void *evt_buf,
      struct ath11k_targ_cap *cap)
{
 const struct wmi_service_ready_event *ev = evt_buf;

 if (!ev) {
  ath11k_err(ab, "%s: failed by NULL param\n",
      __func__);
  return -EINVAL;
 }

 cap->phy_capability = ev->phy_capability;
 cap->max_frag_entry = ev->max_frag_entry;
 cap->num_rf_chains = ev->num_rf_chains;
 cap->ht_cap_info = ev->ht_cap_info;
 cap->vht_cap_info = ev->vht_cap_info;
 cap->vht_supp_mcs = ev->vht_supp_mcs;
 cap->hw_min_tx_power = ev->hw_min_tx_power;
 cap->hw_max_tx_power = ev->hw_max_tx_power;
 cap->sys_cap_info = ev->sys_cap_info;
 cap->min_pkt_size_enable = ev->min_pkt_size_enable;
 cap->max_bcn_ie_size = ev->max_bcn_ie_size;
 cap->max_num_scan_channels = ev->max_num_scan_channels;
 cap->max_supported_macs = ev->max_supported_macs;
 cap->wmi_fw_sub_feat_caps = ev->wmi_fw_sub_feat_caps;
 cap->txrx_chainmask = ev->txrx_chainmask;
 cap->default_dbs_hw_mode_index = ev->default_dbs_hw_mode_index;
 cap->num_msdu_desc = ev->num_msdu_desc;

 return 0;
}

/* Save the wmi_service_bitmap into a linear bitmap. The wmi_services in
 * wmi_service ready event are advertised in b0-b3 (LSB 4-bits) of each
 * 4-byte word.
 */

static void ath11k_wmi_service_bitmap_copy(struct ath11k_pdev_wmi *wmi,
        const u32 *wmi_svc_bm)
{
 int i, j;

 for (i = 0, j = 0; i < WMI_SERVICE_BM_SIZE && j < WMI_MAX_SERVICE; i++) {
  do {
   if (wmi_svc_bm[i] & BIT(j % WMI_SERVICE_BITS_IN_SIZE32))
    set_bit(j, wmi->wmi_ab->svc_map);
  } while (++j % WMI_SERVICE_BITS_IN_SIZE32);
 }
}

static int ath11k_wmi_tlv_svc_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len,
     const void *ptr, void *data)
{
 struct wmi_tlv_svc_ready_parse *svc_ready = data;
 struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_ab.wmi[0];
 u16 expect_len;

 switch (tag) {
 case WMI_TAG_SERVICE_READY_EVENT:
  if (ath11k_pull_service_ready_tlv(ab, ptr, &ab->target_caps))
   return -EINVAL;
  break;

 case WMI_TAG_ARRAY_UINT32:
  if (!svc_ready->wmi_svc_bitmap_done) {
   expect_len = WMI_SERVICE_BM_SIZE * sizeof(u32);
   if (len < expect_len) {
    ath11k_warn(ab, "invalid len %d for the tag 0x%x\n",
         len, tag);
    return -EINVAL;
   }

   ath11k_wmi_service_bitmap_copy(wmi_handle, ptr);

   svc_ready->wmi_svc_bitmap_done = true;
  }
  break;
 default:
  break;
 }

 return 0;
}

static int ath11k_service_ready_event(struct ath11k_base *ab, struct sk_buff *skb)
{
 struct wmi_tlv_svc_ready_parse svc_ready = { };
 int ret;

 ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
      ath11k_wmi_tlv_svc_rdy_parse,
      &svc_ready);
 if (ret) {
  ath11k_warn(ab, "failed to parse tlv %d\n", ret);
  return ret;
 }

 ath11k_dbg(ab, ATH11K_DBG_WMI, "event service ready");

 return 0;
}

struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_ab, u32 len)
{
 struct sk_buff *skb;
 struct ath11k_base *ab = wmi_ab->ab;
 u32 round_len = roundup(len, 4);

 skb = ath11k_htc_alloc_skb(ab, WMI_SKB_HEADROOM + round_len);
 if (!skb)
  return NULL;

 skb_reserve(skb, WMI_SKB_HEADROOM);
 if (!IS_ALIGNED((unsigned long)skb->data, 4))
  ath11k_warn(ab, "unaligned WMI skb data\n");

 skb_put(skb, round_len);
 memset(skb->data, 0, round_len);

 return skb;
}

static u32 ath11k_wmi_mgmt_get_freq(struct ath11k *ar,
        struct ieee80211_tx_info *info)
{
 struct ath11k_base *ab = ar->ab;
 u32 freq = 0;

 if (ab->hw_params.support_off_channel_tx &&
     ar->scan.is_roc &&
     (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN))
  freq = ar->scan.roc_freq;

 return freq;
}

int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id,
    struct sk_buff *frame)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame);
 struct wmi_mgmt_send_cmd *cmd;
 struct wmi_tlv *frame_tlv;
 struct sk_buff *skb;
 u32 buf_len;
 int ret, len;

 buf_len = frame->len < WMI_MGMT_SEND_DOWNLD_LEN ?
    frame->len : WMI_MGMT_SEND_DOWNLD_LEN;

 len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4);

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_mgmt_send_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_MGMT_TX_SEND_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;
 cmd->desc_id = buf_id;
 cmd->chanfreq = ath11k_wmi_mgmt_get_freq(ar, info);
 cmd->paddr_lo = lower_32_bits(ATH11K_SKB_CB(frame)->paddr);
 cmd->paddr_hi = upper_32_bits(ATH11K_SKB_CB(frame)->paddr);
 cmd->frame_len = frame->len;
 cmd->buf_len = buf_len;
 cmd->tx_params_valid = 0;

 frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
 frame_tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
       FIELD_PREP(WMI_TLV_LEN, buf_len);

 memcpy(frame_tlv->value, frame->data, buf_len);

 ath11k_ce_byte_swap(frame_tlv->value, buf_len);

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to submit WMI_MGMT_TX_SEND_CMDID cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd mgmt tx send");

 return ret;
}

int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr,
      struct vdev_create_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_create_cmd *cmd;
 struct sk_buff *skb;
 struct wmi_vdev_txrx_streams *txrx_streams;
 struct wmi_tlv *tlv;
 int ret, len;
 void *ptr;

 /* It can be optimized my sending tx/rx chain configuration
 * only for supported bands instead of always sending it for
 * both the bands.
 */

 len = sizeof(*cmd) + TLV_HDR_SIZE +
  (WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams));

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_create_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_CREATE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->vdev_id = param->if_id;
 cmd->vdev_type = param->type;
 cmd->vdev_subtype = param->subtype;
 cmd->num_cfg_txrx_streams = WMI_NUM_SUPPORTED_BAND_MAX;
 cmd->pdev_id = param->pdev_id;
 cmd->mbssid_flags = param->mbssid_flags;
 cmd->mbssid_tx_vdev_id = param->mbssid_tx_vdev_id;

 ether_addr_copy(cmd->vdev_macaddr.addr, macaddr);

 ptr = skb->data + sizeof(*cmd);
 len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams);

 tlv = ptr;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
        FIELD_PREP(WMI_TLV_LEN, len);

 ptr += TLV_HDR_SIZE;
 txrx_streams = ptr;
 len = sizeof(*txrx_streams);
 txrx_streams->tlv_header =
  FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_TXRX_STREAMS) |
  FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
 txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G;
 txrx_streams->supported_tx_streams =
     param->chains[NL80211_BAND_2GHZ].tx;
 txrx_streams->supported_rx_streams =
     param->chains[NL80211_BAND_2GHZ].rx;

 txrx_streams++;
 txrx_streams->tlv_header =
  FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_TXRX_STREAMS) |
  FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
 txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G;
 txrx_streams->supported_tx_streams =
     param->chains[NL80211_BAND_5GHZ].tx;
 txrx_streams->supported_rx_streams =
     param->chains[NL80211_BAND_5GHZ].rx;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_CREATE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to submit WMI_VDEV_CREATE_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd vdev create id %d type %d subtype %d macaddr %pM pdevid %d\n",
     param->if_id, param->type, param->subtype,
     macaddr, param->pdev_id);

 return ret;
}

int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_delete_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_delete_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_DELETE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_DELETE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to submit WMI_VDEV_DELETE_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev delete id %d\n", vdev_id);

 return ret;
}

int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_stop_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_stop_cmd *)skb->data;

 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_STOP_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_STOP_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to submit WMI_VDEV_STOP cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev stop id 0x%x\n", vdev_id);

 return ret;
}

int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_down_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_down_cmd *)skb->data;

 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_DOWN_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_DOWN_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to submit WMI_VDEV_DOWN cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev down id 0x%x\n", vdev_id);

 return ret;
}

static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan,
           struct wmi_vdev_start_req_arg *arg)
{
 u32 center_freq1 = arg->channel.band_center_freq1;

 memset(chan, 0, sizeof(*chan));

 chan->mhz = arg->channel.freq;
 chan->band_center_freq1 = arg->channel.band_center_freq1;

 if (arg->channel.mode == MODE_11AX_HE160) {
  if (arg->channel.freq > arg->channel.band_center_freq1)
   chan->band_center_freq1 = center_freq1 + 40;
  else
   chan->band_center_freq1 = center_freq1 - 40;

  chan->band_center_freq2 = arg->channel.band_center_freq1;

 } else if ((arg->channel.mode == MODE_11AC_VHT80_80) ||
     (arg->channel.mode == MODE_11AX_HE80_80)) {
  chan->band_center_freq2 = arg->channel.band_center_freq2;
 } else {
  chan->band_center_freq2 = 0;
 }

 chan->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, arg->channel.mode);
 if (arg->channel.passive)
  chan->info |= WMI_CHAN_INFO_PASSIVE;
 if (arg->channel.allow_ibss)
  chan->info |= WMI_CHAN_INFO_ADHOC_ALLOWED;
 if (arg->channel.allow_ht)
  chan->info |= WMI_CHAN_INFO_ALLOW_HT;
 if (arg->channel.allow_vht)
  chan->info |= WMI_CHAN_INFO_ALLOW_VHT;
 if (arg->channel.allow_he)
  chan->info |= WMI_CHAN_INFO_ALLOW_HE;
 if (arg->channel.ht40plus)
  chan->info |= WMI_CHAN_INFO_HT40_PLUS;
 if (arg->channel.chan_radar)
  chan->info |= WMI_CHAN_INFO_DFS;
 if (arg->channel.freq2_radar)
  chan->info |= WMI_CHAN_INFO_DFS_FREQ2;

 chan->reg_info_1 = FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR,
          arg->channel.max_power) |
  FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR,
      arg->channel.max_reg_power);

 chan->reg_info_2 = FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX,
          arg->channel.max_antenna_gain) |
  FIELD_PREP(WMI_CHAN_REG_INFO2_MAX_TX_PWR,
      arg->channel.max_power);
}

int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg,
     bool restart)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_start_request_cmd *cmd;
 struct sk_buff *skb;
 struct wmi_channel *chan;
 struct wmi_tlv *tlv;
 void *ptr;
 int ret, len;

 if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
  return -EINVAL;

 len = sizeof(*cmd) + sizeof(*chan) + TLV_HDR_SIZE;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_VDEV_START_REQUEST_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = arg->vdev_id;
 cmd->beacon_interval = arg->bcn_intval;
 cmd->bcn_tx_rate = arg->bcn_tx_rate;
 cmd->dtim_period = arg->dtim_period;
 cmd->num_noa_descriptors = arg->num_noa_descriptors;
 cmd->preferred_rx_streams = arg->pref_rx_streams;
 cmd->preferred_tx_streams = arg->pref_tx_streams;
 cmd->cac_duration_ms = arg->cac_duration_ms;
 cmd->regdomain = arg->regdomain;
 cmd->he_ops = arg->he_ops;
 cmd->mbssid_flags = arg->mbssid_flags;
 cmd->mbssid_tx_vdev_id = arg->mbssid_tx_vdev_id;

 if (!restart) {
  if (arg->ssid) {
   cmd->ssid.ssid_len = arg->ssid_len;
   memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
  }
  if (arg->hidden_ssid)
   cmd->flags |= WMI_VDEV_START_HIDDEN_SSID;
  if (arg->pmf_enabled)
   cmd->flags |= WMI_VDEV_START_PMF_ENABLED;
 }

 cmd->flags |= WMI_VDEV_START_LDPC_RX_ENABLED;
 if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
  cmd->flags |= WMI_VDEV_START_HW_ENCRYPTION_DISABLED;

 ptr = skb->data + sizeof(*cmd);
 chan = ptr;

 ath11k_wmi_put_wmi_channel(chan, arg);

 chan->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_CHANNEL) |
      FIELD_PREP(WMI_TLV_LEN,
          sizeof(*chan) - TLV_HDR_SIZE);
 ptr += sizeof(*chan);

 tlv = ptr;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
        FIELD_PREP(WMI_TLV_LEN, 0);

 /* Note: This is a nested TLV containing:
 * [wmi_tlv][ath11k_wmi_p2p_noa_descriptor][wmi_tlv]..
 */


 ptr += sizeof(*tlv);

 if (restart)
  ret = ath11k_wmi_cmd_send(wmi, skb,
       WMI_VDEV_RESTART_REQUEST_CMDID);
 else
  ret = ath11k_wmi_cmd_send(wmi, skb,
       WMI_VDEV_START_REQUEST_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to submit vdev_%s cmd\n",
       restart ? "restart" : "start");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev %s id 0x%x freq 0x%x mode 0x%x\n",
     restart ? "restart" : "start", arg->vdev_id,
     arg->channel.freq, arg->channel.mode);

 return ret;
}

int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid,
         u8 *tx_bssid, u32 nontx_profile_idx, u32 nontx_profile_cnt)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_up_cmd *cmd;
 struct ieee80211_bss_conf *bss_conf;
 struct ath11k_vif *arvif;
 struct sk_buff *skb;
 int ret;

 arvif = ath11k_mac_get_arvif(ar, vdev_id);

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_up_cmd *)skb->data;

 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_UP_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;
 cmd->vdev_assoc_id = aid;

 ether_addr_copy(cmd->vdev_bssid.addr, bssid);

 cmd->nontx_profile_idx = nontx_profile_idx;
 cmd->nontx_profile_cnt = nontx_profile_cnt;
 if (tx_bssid)
  ether_addr_copy(cmd->tx_vdev_bssid.addr, tx_bssid);

 if (arvif && arvif->vif->type == NL80211_IFTYPE_STATION) {
  bss_conf = &arvif->vif->bss_conf;

  if (bss_conf->nontransmitted) {
   ether_addr_copy(cmd->tx_vdev_bssid.addr,
     bss_conf->transmitter_bssid);
   cmd->nontx_profile_idx = bss_conf->bssid_index;
   cmd->nontx_profile_cnt = bss_conf->bssid_indicator;
  }
 }

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_UP_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to submit WMI_VDEV_UP cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd vdev up id 0x%x assoc id %d bssid %pM\n",
     vdev_id, aid, bssid);

 return ret;
}

int ath11k_wmi_send_peer_create_cmd(struct ath11k *ar,
        struct peer_create_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_peer_create_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_peer_create_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_CREATE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 ether_addr_copy(cmd->peer_macaddr.addr, param->peer_addr);
 cmd->peer_type = param->peer_type;
 cmd->vdev_id = param->vdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_CREATE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to submit WMI_PEER_CREATE cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer create vdev_id %d peer_addr %pM\n",
     param->vdev_id, param->peer_addr);

 return ret;
}

int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar,
        const u8 *peer_addr, u8 vdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_peer_delete_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_peer_delete_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_DELETE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 cmd->vdev_id = vdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_DELETE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PEER_DELETE cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer delete vdev_id %d peer_addr %pM\n",
     vdev_id,  peer_addr);

 return ret;
}

int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar,
           struct pdev_set_regdomain_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_pdev_set_regdomain_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_PDEV_SET_REGDOMAIN_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->reg_domain = param->current_rd_in_use;
 cmd->reg_domain_2g = param->current_rd_2g;
 cmd->reg_domain_5g = param->current_rd_5g;
 cmd->conformance_test_limit_2g = param->ctl_2g;
 cmd->conformance_test_limit_5g = param->ctl_5g;
 cmd->dfs_domain = param->dfs_domain;
 cmd->pdev_id = param->pdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_REGDOMAIN_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_PDEV_SET_REGDOMAIN cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n",
     param->current_rd_in_use, param->current_rd_2g,
     param->current_rd_5g, param->dfs_domain, param->pdev_id);

 return ret;
}

int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr,
         u32 vdev_id, u32 param_id, u32 param_val)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_peer_set_param_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_peer_set_param_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_SET_PARAM_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 cmd->vdev_id = vdev_id;
 cmd->param_id = param_id;
 cmd->param_value = param_val;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_SET_PARAM_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PEER_SET_PARAM cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer set param vdev %d peer 0x%pM set param %d value %d\n",
     vdev_id, peer_addr, param_id, param_val);

 return ret;
}

int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar,
     u8 peer_addr[ETH_ALEN],
     struct peer_flush_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_peer_flush_tids_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_FLUSH_TIDS_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 cmd->peer_tid_bitmap = param->peer_tid_bitmap;
 cmd->vdev_id = param->vdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_FLUSH_TIDS_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_PEER_FLUSH_TIDS cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer flush tids vdev_id %d peer_addr %pM tids %08x\n",
     param->vdev_id, peer_addr, param->peer_tid_bitmap);

 return ret;
}

int ath11k_wmi_peer_rx_reorder_queue_setup(struct ath11k *ar,
        int vdev_id, const u8 *addr,
        dma_addr_t paddr, u8 tid,
        u8 ba_window_size_valid,
        u32 ba_window_size)
{
 struct wmi_peer_reorder_queue_setup_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_peer_reorder_queue_setup_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_REORDER_QUEUE_SETUP_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 ether_addr_copy(cmd->peer_macaddr.addr, addr);
 cmd->vdev_id = vdev_id;
 cmd->tid = tid;
 cmd->queue_ptr_lo = lower_32_bits(paddr);
 cmd->queue_ptr_hi = upper_32_bits(paddr);
 cmd->queue_no = tid;
 cmd->ba_window_size_valid = ba_window_size_valid;
 cmd->ba_window_size = ba_window_size;

 ret = ath11k_wmi_cmd_send(ar->wmi, skb,
      WMI_PEER_REORDER_QUEUE_SETUP_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_PEER_REORDER_QUEUE_SETUP\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer reorder queue setup addr %pM vdev_id %d tid %d\n",
     addr, vdev_id, tid);

 return ret;
}

int
ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar,
     struct rx_reorder_queue_remove_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_peer_reorder_queue_remove_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_peer_reorder_queue_remove_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_REORDER_QUEUE_REMOVE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 ether_addr_copy(cmd->peer_macaddr.addr, param->peer_macaddr);
 cmd->vdev_id = param->vdev_id;
 cmd->tid_mask = param->peer_tid_bitmap;

 ret = ath11k_wmi_cmd_send(wmi, skb,
      WMI_PEER_REORDER_QUEUE_REMOVE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_PEER_REORDER_QUEUE_REMOVE_CMDID");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer reorder queue remove peer_macaddr %pM vdev_id %d tid_map %d",
     param->peer_macaddr, param->vdev_id, param->peer_tid_bitmap);

 return ret;
}

int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id,
         u32 param_value, u8 pdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_pdev_set_param_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_pdev_set_param_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SET_PARAM_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->pdev_id = pdev_id;
 cmd->param_id = param_id;
 cmd->param_value = param_value;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_PARAM_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PDEV_SET_PARAM cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd pdev set param %d pdev id %d value %d\n",
     param_id, pdev_id, param_value);

 return ret;
}

int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id,
    enum wmi_sta_ps_mode psmode)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_pdev_set_ps_mode_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_pdev_set_ps_mode_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_STA_POWERSAVE_MODE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;
 cmd->sta_ps_mode = psmode;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_MODE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PDEV_SET_PARAM cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd sta powersave mode psmode %d vdev id %d\n",
     psmode, vdev_id);

 return ret;
}

int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt,
       u32 pdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_pdev_suspend_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_pdev_suspend_cmd *)skb->data;

 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SUSPEND_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->suspend_opt = suspend_opt;
 cmd->pdev_id = pdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SUSPEND_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PDEV_SUSPEND cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd pdev suspend pdev_id %d\n", pdev_id);

 return ret;
}

int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_pdev_resume_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_pdev_resume_cmd *)skb->data;

 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_RESUME_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->pdev_id = pdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_RESUME_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PDEV_RESUME cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd pdev resume pdev id %d\n", pdev_id);

 return ret;
}

/* TODO FW Support for the cmd is not available yet.
 * Can be tested once the command and corresponding
 * event is implemented in FW
 */

int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar,
       enum wmi_bss_chan_info_req_type type)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_pdev_bss_chan_info_req_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_pdev_bss_chan_info_req_cmd *)skb->data;

 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_PDEV_BSS_CHAN_INFO_REQUEST) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->req_type = type;
 cmd->pdev_id = ar->pdev->pdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb,
      WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_PDEV_BSS_CHAN_INFO_REQUEST cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd pdev bss chan info request type %d\n", type);

 return ret;
}

int ath11k_wmi_send_set_ap_ps_param_cmd(struct ath11k *ar, u8 *peer_addr,
     struct ap_ps_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_ap_ps_peer_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_ap_ps_peer_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_AP_PS_PEER_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->vdev_id = param->vdev_id;
 ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 cmd->param = param->param;
 cmd->value = param->value;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_AP_PS_PEER_PARAM_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_AP_PS_PEER_PARAM_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd ap ps peer param vdev id %d peer %pM param %d value %d\n",
     param->vdev_id, peer_addr, param->param, param->value);

 return ret;
}

int ath11k_wmi_set_sta_ps_param(struct ath11k *ar, u32 vdev_id,
    u32 param, u32 param_value)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_sta_powersave_param_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_sta_powersave_param_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_STA_POWERSAVE_PARAM_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->vdev_id = vdev_id;
 cmd->param = param;
 cmd->value = param_value;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_PARAM_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_STA_POWERSAVE_PARAM_CMDID");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd set powersave param vdev_id %d param %d value %d\n",
     vdev_id, param, param_value);

 return ret;
}

int ath11k_wmi_force_fw_hang_cmd(struct ath11k *ar, u32 type, u32 delay_time_ms)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_force_fw_hang_cmd *cmd;
 struct sk_buff *skb;
 int ret, len;

 len = sizeof(*cmd);

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_FORCE_FW_HANG_CMD) |
     FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);

 cmd->type = type;
 cmd->delay_time_ms = delay_time_ms;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_FORCE_FW_HANG_CMDID);

 if (ret) {
  ath11k_warn(ar->ab, "Failed to send WMI_FORCE_FW_HANG_CMDID");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd force fw hang");

 return ret;
}

int ath11k_wmi_vdev_set_param_cmd(struct ath11k *ar, u32 vdev_id,
      u32 param_id, u32 param_value)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_set_param_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_set_param_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_SET_PARAM_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->vdev_id = vdev_id;
 cmd->param_id = param_id;
 cmd->param_value = param_value;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_PARAM_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_VDEV_SET_PARAM_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd vdev set param vdev 0x%x param %d value %d\n",
     vdev_id, param_id, param_value);

 return ret;
}

int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar,
          struct stats_request_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_request_stats_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_request_stats_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_REQUEST_STATS_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->stats_id = param->stats_id;
 cmd->vdev_id = param->vdev_id;
 cmd->pdev_id = param->pdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_REQUEST_STATS_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_REQUEST_STATS cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd request stats 0x%x vdev id %d pdev id %d\n",
     param->stats_id, param->vdev_id, param->pdev_id);

 return ret;
}

int ath11k_wmi_send_pdev_temperature_cmd(struct ath11k *ar)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_get_pdev_temperature_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_get_pdev_temperature_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_GET_TEMPERATURE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->pdev_id = ar->pdev->pdev_id;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_GET_TEMPERATURE_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_PDEV_GET_TEMPERATURE cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id);

 return ret;
}

int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
         u32 vdev_id, u32 bcn_ctrl_op)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_bcn_offload_ctrl_cmd *cmd;
 struct sk_buff *skb;
 int ret;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_bcn_offload_ctrl_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_BCN_OFFLOAD_CTRL_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->vdev_id = vdev_id;
 cmd->bcn_ctrl_op = bcn_ctrl_op;

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BCN_OFFLOAD_CTRL_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_BCN_OFFLOAD_CTRL_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd bcn offload ctrl vdev id %d ctrl_op %d\n",
     vdev_id, bcn_ctrl_op);

 return ret;
}

int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id,
        const u8 *p2p_ie)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_p2p_go_set_beacon_ie_cmd *cmd;
 size_t p2p_ie_len, aligned_len;
 struct wmi_tlv *tlv;
 struct sk_buff *skb;
 int ret, len;

 p2p_ie_len = p2p_ie[1] + 2;
 aligned_len = roundup(p2p_ie_len, 4);

 len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_p2p_go_set_beacon_ie_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_P2P_GO_SET_BEACON_IE) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;
 cmd->ie_buf_len = p2p_ie_len;

 tlv = (struct wmi_tlv *)cmd->tlv;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
        FIELD_PREP(WMI_TLV_LEN, aligned_len);
 memcpy(tlv->value, p2p_ie, p2p_ie_len);

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_P2P_GO_SET_BEACON_IE);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_P2P_GO_SET_BEACON_IE\n");
  dev_kfree_skb(skb);
 }

 return ret;
}

int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
   struct ieee80211_mutable_offsets *offs,
   struct sk_buff *bcn, u32 ema_params)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_bcn_tmpl_cmd *cmd;
 struct wmi_bcn_prb_info *bcn_prb_info;
 struct wmi_tlv *tlv;
 struct sk_buff *skb;
 void *ptr;
 int ret, len;
 size_t aligned_len = roundup(bcn->len, 4);
 struct ieee80211_vif *vif;
 struct ath11k_vif *arvif = ath11k_mac_get_arvif(ar, vdev_id);

 if (!arvif) {
  ath11k_warn(ar->ab, "failed to find arvif with vdev id %d\n", vdev_id);
  return -EINVAL;
 }

 vif = arvif->vif;

 len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_bcn_tmpl_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_BCN_TMPL_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = vdev_id;
 cmd->tim_ie_offset = offs->tim_offset;

 if (vif->bss_conf.csa_active) {
  cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0];
  cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1];
 }

 cmd->buf_len = bcn->len;
 cmd->mbssid_ie_offset = offs->mbssid_off;
 cmd->ema_params = ema_params;

 ptr = skb->data + sizeof(*cmd);

 bcn_prb_info = ptr;
 len = sizeof(*bcn_prb_info);
 bcn_prb_info->tlv_header = FIELD_PREP(WMI_TLV_TAG,
           WMI_TAG_BCN_PRB_INFO) |
       FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
 bcn_prb_info->caps = 0;
 bcn_prb_info->erp = 0;

 ptr += sizeof(*bcn_prb_info);

 tlv = ptr;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
        FIELD_PREP(WMI_TLV_LEN, aligned_len);
 memcpy(tlv->value, bcn->data, bcn->len);

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BCN_TMPL_CMDID);
 if (ret) {
  ath11k_warn(ar->ab, "failed to send WMI_BCN_TMPL_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd bcn tmpl");

 return ret;
}

int ath11k_wmi_vdev_install_key(struct ath11k *ar,
    struct wmi_vdev_install_key_arg *arg)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_vdev_install_key_cmd *cmd;
 struct wmi_tlv *tlv;
 struct sk_buff *skb;
 int ret, len;
 int key_len_aligned = roundup(arg->key_len, sizeof(uint32_t));

 len = sizeof(*cmd) + TLV_HDR_SIZE + key_len_aligned;

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_INSTALL_KEY_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
 cmd->vdev_id = arg->vdev_id;
 ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
 cmd->key_idx = arg->key_idx;
 cmd->key_flags = arg->key_flags;
 cmd->key_cipher = arg->key_cipher;
 cmd->key_len = arg->key_len;
 cmd->key_txmic_len = arg->key_txmic_len;
 cmd->key_rxmic_len = arg->key_rxmic_len;

 if (arg->key_rsc_counter)
  memcpy(&cmd->key_rsc_counter, &arg->key_rsc_counter,
         sizeof(struct wmi_key_seq_counter));

 tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
        FIELD_PREP(WMI_TLV_LEN, key_len_aligned);
 if (arg->key_data)
  memcpy(tlv->value, (u8 *)arg->key_data, key_len_aligned);

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_INSTALL_KEY_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_VDEV_INSTALL_KEY cmd\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd vdev install key idx %d cipher %d len %d\n",
     arg->key_idx, arg->key_cipher, arg->key_len);

 return ret;
}

static inline void
ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
      struct peer_assoc_params *param,
      bool hw_crypto_disabled)
{
 cmd->peer_flags = 0;

 if (param->is_wme_set) {
  if (param->qos_flag)
   cmd->peer_flags |= WMI_PEER_QOS;
  if (param->apsd_flag)
   cmd->peer_flags |= WMI_PEER_APSD;
  if (param->ht_flag)
   cmd->peer_flags |= WMI_PEER_HT;
  if (param->bw_40)
   cmd->peer_flags |= WMI_PEER_40MHZ;
  if (param->bw_80)
   cmd->peer_flags |= WMI_PEER_80MHZ;
  if (param->bw_160)
   cmd->peer_flags |= WMI_PEER_160MHZ;

  /* Typically if STBC is enabled for VHT it should be enabled
 * for HT as well
 **/

  if (param->stbc_flag)
   cmd->peer_flags |= WMI_PEER_STBC;

  /* Typically if LDPC is enabled for VHT it should be enabled
 * for HT as well
 **/

  if (param->ldpc_flag)
   cmd->peer_flags |= WMI_PEER_LDPC;

  if (param->static_mimops_flag)
   cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS;
  if (param->dynamic_mimops_flag)
   cmd->peer_flags |= WMI_PEER_DYN_MIMOPS;
  if (param->spatial_mux_flag)
   cmd->peer_flags |= WMI_PEER_SPATIAL_MUX;
  if (param->vht_flag)
   cmd->peer_flags |= WMI_PEER_VHT;
  if (param->he_flag)
   cmd->peer_flags |= WMI_PEER_HE;
  if (param->twt_requester)
   cmd->peer_flags |= WMI_PEER_TWT_REQ;
  if (param->twt_responder)
   cmd->peer_flags |= WMI_PEER_TWT_RESP;
 }

 /* Suppress authorization for all AUTH modes that need 4-way handshake
 * (during re-association).
 * Authorization will be done for these modes on key installation.
 */

 if (param->auth_flag)
  cmd->peer_flags |= WMI_PEER_AUTH;
 if (param->need_ptk_4_way) {
  cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
  if (!hw_crypto_disabled && param->is_assoc)
   cmd->peer_flags &= ~WMI_PEER_AUTH;
 }
 if (param->need_gtk_2_way)
  cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
 /* safe mode bypass the 4-way handshake */
 if (param->safe_mode_enabled)
  cmd->peer_flags &= ~(WMI_PEER_NEED_PTK_4_WAY |
         WMI_PEER_NEED_GTK_2_WAY);

 if (param->is_pmf_enabled)
  cmd->peer_flags |= WMI_PEER_PMF;

 /* Disable AMSDU for station transmit, if user configures it */
 /* Disable AMSDU for AP transmit to 11n Stations, if user configures
 * it
 * if (param->amsdu_disable) Add after FW support
 **/


 /* Target asserts if node is marked HT and all MCS is set to 0.
 * Mark the node as non-HT if all the mcs rates are disabled through
 * iwpriv
 **/

 if (param->peer_ht_rates.num_rates == 0)
  cmd->peer_flags &= ~WMI_PEER_HT;
}

int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar,
       struct peer_assoc_params *param)
{
 struct ath11k_pdev_wmi *wmi = ar->wmi;
 struct wmi_peer_assoc_complete_cmd *cmd;
 struct wmi_vht_rate_set *mcs;
 struct wmi_he_rate_set *he_mcs;
 struct sk_buff *skb;
 struct wmi_tlv *tlv;
 void *ptr;
 u32 peer_legacy_rates_align;
 u32 peer_ht_rates_align;
 int i, ret, len;

 peer_legacy_rates_align = roundup(param->peer_legacy_rates.num_rates,
       sizeof(u32));
 peer_ht_rates_align = roundup(param->peer_ht_rates.num_rates,
          sizeof(u32));

 len = sizeof(*cmd) +
       TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) +
       TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) +
       sizeof(*mcs) + TLV_HDR_SIZE +
       (sizeof(*he_mcs) * param->peer_he_mcs_count);

 skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
 if (!skb)
  return -ENOMEM;

 ptr = skb->data;

 cmd = ptr;
 cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
         WMI_TAG_PEER_ASSOC_COMPLETE_CMD) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);

 cmd->vdev_id = param->vdev_id;

 cmd->peer_new_assoc = param->peer_new_assoc;
 cmd->peer_associd = param->peer_associd;

 ath11k_wmi_copy_peer_flags(cmd, param,
       test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED,
         &ar->ab->dev_flags));

 ether_addr_copy(cmd->peer_macaddr.addr, param->peer_mac);

 cmd->peer_rate_caps = param->peer_rate_caps;
 cmd->peer_caps = param->peer_caps;
 cmd->peer_listen_intval = param->peer_listen_intval;
 cmd->peer_ht_caps = param->peer_ht_caps;
 cmd->peer_max_mpdu = param->peer_max_mpdu;
 cmd->peer_mpdu_density = param->peer_mpdu_density;
 cmd->peer_vht_caps = param->peer_vht_caps;
 cmd->peer_phymode = param->peer_phymode;

 /* Update 11ax capabilities */
 cmd->peer_he_cap_info = param->peer_he_cap_macinfo[0];
 cmd->peer_he_cap_info_ext = param->peer_he_cap_macinfo[1];
 cmd->peer_he_cap_info_internal = param->peer_he_cap_macinfo_internal;
 cmd->peer_he_caps_6ghz = param->peer_he_caps_6ghz;
 cmd->peer_he_ops = param->peer_he_ops;
 memcpy(&cmd->peer_he_cap_phy, ¶m->peer_he_cap_phyinfo,
        sizeof(param->peer_he_cap_phyinfo));
 memcpy(&cmd->peer_ppet, ¶m->peer_ppet,
        sizeof(param->peer_ppet));

 /* Update peer legacy rate information */
 ptr += sizeof(*cmd);

 tlv = ptr;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
        FIELD_PREP(WMI_TLV_LEN, peer_legacy_rates_align);

 ptr += TLV_HDR_SIZE;

 cmd->num_peer_legacy_rates = param->peer_legacy_rates.num_rates;
 memcpy(ptr, param->peer_legacy_rates.rates,
        param->peer_legacy_rates.num_rates);

 /* Update peer HT rate information */
 ptr += peer_legacy_rates_align;

 tlv = ptr;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
        FIELD_PREP(WMI_TLV_LEN, peer_ht_rates_align);
 ptr += TLV_HDR_SIZE;
 cmd->num_peer_ht_rates = param->peer_ht_rates.num_rates;
 memcpy(ptr, param->peer_ht_rates.rates,
        param->peer_ht_rates.num_rates);

 /* VHT Rates */
 ptr += peer_ht_rates_align;

 mcs = ptr;

 mcs->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VHT_RATE_SET) |
     FIELD_PREP(WMI_TLV_LEN, sizeof(*mcs) - TLV_HDR_SIZE);

 cmd->peer_nss = param->peer_nss;

 /* Update bandwidth-NSS mapping */
 cmd->peer_bw_rxnss_override = 0;
 cmd->peer_bw_rxnss_override |= param->peer_bw_rxnss_override;

 if (param->vht_capable) {
  mcs->rx_max_rate = param->rx_max_rate;
  mcs->rx_mcs_set = param->rx_mcs_set;
  mcs->tx_max_rate = param->tx_max_rate;
  mcs->tx_mcs_set = param->tx_mcs_set;
 }

 /* HE Rates */
 cmd->peer_he_mcs = param->peer_he_mcs_count;
 cmd->min_data_rate = param->min_data_rate;

 ptr += sizeof(*mcs);

 len = param->peer_he_mcs_count * sizeof(*he_mcs);

 tlv = ptr;
 tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
        FIELD_PREP(WMI_TLV_LEN, len);
 ptr += TLV_HDR_SIZE;

 /* Loop through the HE rate set */
 for (i = 0; i < param->peer_he_mcs_count; i++) {
  he_mcs = ptr;
  he_mcs->tlv_header = FIELD_PREP(WMI_TLV_TAG,
      WMI_TAG_HE_RATE_SET) |
         FIELD_PREP(WMI_TLV_LEN,
      sizeof(*he_mcs) - TLV_HDR_SIZE);

  he_mcs->rx_mcs_set = param->peer_he_tx_mcs_set[i];
  he_mcs->tx_mcs_set = param->peer_he_rx_mcs_set[i];
  ptr += sizeof(*he_mcs);
 }

 ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_ASSOC_CMDID);
 if (ret) {
  ath11k_warn(ar->ab,
       "failed to send WMI_PEER_ASSOC_CMDID\n");
  dev_kfree_skb(skb);
 }

 ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
     "cmd peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n",
     cmd->vdev_id, cmd->peer_associd, param->peer_mac,
     cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps,
     cmd->peer_listen_intval, cmd->peer_ht_caps,
     cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode,
     cmd->peer_mpdu_density,
     cmd->peer_vht_caps, cmd->peer_he_cap_info,
     cmd->peer_he_ops, cmd->peer_he_cap_info_ext,
     cmd->peer_he_cap_phy[0], cmd->peer_he_cap_phy[1],
     cmd->peer_he_cap_phy[2],
     cmd->peer_bw_rxnss_override);

 return ret;
}

void ath11k_wmi_start_scan_init(struct ath11k *ar,
    struct scan_req_params *arg)
{
 /* setup commonly used values */
 arg->scan_req_id = 1;
 if (ar->state_11d == ATH11K_11D_PREPARING)
  arg->scan_priority = WMI_SCAN_PRIORITY_MEDIUM;
 else
  arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
 arg->dwell_time_active = 50;
 arg->dwell_time_active_2g = 0;
 arg->dwell_time_passive = 150;
 arg->dwell_time_active_6g = 40;
 arg->dwell_time_passive_6g = 30;
 arg->min_rest_time = 50;
 arg->max_rest_time = 500;
 arg->repeat_probe_time = 0;
 arg->probe_spacing_time = 0;
 arg->idle_time = 0;
 arg->max_scan_time = 20000;
 arg->probe_delay = 5;
 arg->notify_scan_events = WMI_SCAN_EVENT_STARTED |
      WMI_SCAN_EVENT_COMPLETED |
      WMI_SCAN_EVENT_BSS_CHANNEL |
      WMI_SCAN_EVENT_FOREIGN_CHAN |
      WMI_SCAN_EVENT_DEQUEUED;
 arg->scan_f_chan_stat_evnt = 1;

 if (test_bit(WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE,
       ar->ab->wmi_ab.svc_map))
  arg->scan_ctrl_flags_ext |=
   WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE;

 arg->num_bssid = 1;

 /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be
 * ZEROs in probe request
 */

 eth_broadcast_addr(arg->bssid_list[0].addr);
}

static inline void
ath11k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd,
           struct scan_req_params *param)
{
 /* Scan events subscription */
 if (param->scan_ev_started)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_STARTED;
 if (param->scan_ev_completed)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_COMPLETED;
 if (param->scan_ev_bss_chan)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_BSS_CHANNEL;
 if (param->scan_ev_foreign_chan)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_FOREIGN_CHAN;
 if (param->scan_ev_dequeued)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_DEQUEUED;
 if (param->scan_ev_preempted)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_PREEMPTED;
 if (param->scan_ev_start_failed)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_START_FAILED;
 if (param->scan_ev_restarted)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_RESTARTED;
 if (param->scan_ev_foreign_chn_exit)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT;
 if (param->scan_ev_suspended)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_SUSPENDED;
 if (param->scan_ev_resumed)
  cmd->notify_scan_events |=  WMI_SCAN_EVENT_RESUMED;

 /** Set scan control flags */
 cmd->scan_ctrl_flags = 0;
 if (param->scan_f_passive)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_PASSIVE;
 if (param->scan_f_strict_passive_pch)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_STRICT_PASSIVE_ON_PCHN;
 if (param->scan_f_promisc_mode)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FILTER_PROMISCUOS;
 if (param->scan_f_capture_phy_err)
  cmd->scan_ctrl_flags |=  WMI_SCAN_CAPTURE_PHY_ERROR;
 if (param->scan_f_half_rate)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_HALF_RATE_SUPPORT;
 if (param->scan_f_quarter_rate)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT;
 if (param->scan_f_cck_rates)
  cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_CCK_RATES;
 if (param->scan_f_ofdm_rates)
  cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_OFDM_RATES;
 if (param->scan_f_chan_stat_evnt)
  cmd->scan_ctrl_flags |=  WMI_SCAN_CHAN_STAT_EVENT;
 if (param->scan_f_filter_prb_req)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FILTER_PROBE_REQ;
 if (param->scan_f_bcast_probe)
  cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_BCAST_PROBE_REQ;
 if (param->scan_f_offchan_mgmt_tx)
  cmd->scan_ctrl_flags |=  WMI_SCAN_OFFCHAN_MGMT_TX;
 if (param->scan_f_offchan_data_tx)
  cmd->scan_ctrl_flags |=  WMI_SCAN_OFFCHAN_DATA_TX;
 if (param->scan_f_force_active_dfs_chn)
  cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS;
 if (param->scan_f_add_tpc_ie_in_probe)
  cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ;
 if (param->scan_f_add_ds_ie_in_probe)
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge