diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mld')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/constants.h | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/d3.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/fw.c | 14 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/iface.c | 13 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/link.c | 16 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 103 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/mld.c | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/mld.h | 25 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 100 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/notif.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/roc.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/rx.c | 1691 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/rx.h | 5 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mld/sta.c | 2 |
14 files changed, 1089 insertions, 895 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h index 49accf96f44b..5d23a618ae3c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h @@ -75,5 +75,7 @@ #define IWL_MLD_FTM_RESP_LMR_FEEDBACK_SUPPORT true #define IWL_MLD_FTM_NON_TB_MIN_TIME_BETWEEN_MSR 7 #define IWL_MLD_FTM_NON_TB_MAX_TIME_BETWEEN_MSR 1000 +#define IWL_MLD_STA_EXT_CAPA_SIZE 9 +#define IWL_MLD_EXT_CAPA_NUM_IFTYPES 1 #endif /* __iwl_mld_constants_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index 1d4282a21f09..dd85be94433c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -1794,6 +1794,10 @@ iwl_mld_send_proto_offload(struct iwl_mld *mld, u32 enabled = 0; cmd = kzalloc(hcmd.len[0], GFP_KERNEL); + if (!cmd) { + IWL_DEBUG_WOWLAN(mld, "Failed to allocate proto offload cmd\n"); + return -ENOMEM; + } #if IS_ENABLED(CONFIG_IPV6) struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index b372173c4a79..19da521a4bab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -124,9 +124,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, u16 status; switch (version) { - case 6: case 7: - expected_sz = sizeof(struct iwl_alive_ntf_v6); + expected_sz = sizeof(struct iwl_alive_ntf_v7); break; case 8: expected_sz = sizeof(struct iwl_alive_ntf); @@ -168,11 +167,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, umac_error_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr) & ~FW_ADDR_CACHE_CONTROL; - if (umac_error_table >= trans->mac_cfg->base->min_umac_error_event_table) - iwl_fw_umac_set_alive_err_table(trans, umac_error_table); - else - IWL_ERR(mld, "Not valid error log pointer 0x%08X\n", - umac_error_table); + iwl_fw_umac_set_alive_err_table(trans, umac_error_table); alive_data->valid = status == IWL_ALIVE_STATUS_OK; @@ -188,9 +183,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, le32_to_cpu(umac->umac_major), le32_to_cpu(umac->umac_minor)); - if (version >= 7) - IWL_DEBUG_FW(mld, "FW alive flags 0x%x\n", - le16_to_cpu(palive->flags)); + IWL_DEBUG_FW(mld, "FW alive flags 0x%x\n", + le16_to_cpu(palive->flags)); if (version >= 8) IWL_DEBUG_FW(mld, "platform_id 0x%llx\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index ed379825a923..a5ececfc13e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -528,6 +528,19 @@ void iwl_mld_handle_probe_resp_data_notif(struct iwl_mld *mld, mld_link = &iwl_mld_vif_from_mac80211(vif)->deflink; + /* len_low should be 2 + n*13 (where n is the number of descriptors. + * 13 is the size of a NoA descriptor). We can have either one or two + * descriptors. + */ + if (IWL_FW_CHECK(mld, notif->noa_active && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) * 2, + "Invalid noa_attr.len_low (%d)\n", + notif->noa_attr.len_low)) + return; + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); if (!new_data) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index f6f52d297a72..d89840a1152b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -465,10 +465,13 @@ int iwl_mld_add_link(struct iwl_mld *mld, int ret; if (!link) { - if (is_deflink) + if (is_deflink) { link = &mld_vif->deflink; - else + } else { link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return -ENOMEM; + } } else { WARN_ON(!mld->fw_status.in_hw_restart); } @@ -572,8 +575,12 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, /* Not in EMLSR and we can't hear the link. * Try to switch to a better link. EMLSR case is handled below. */ - if (!iwl_mld_emlsr_active(vif)) + if (!iwl_mld_emlsr_active(vif)) { + IWL_DEBUG_EHT(mld, + "missed beacons exceeds threshold. link_id=%u. Try to switch to a better link.\n", + link_id); iwl_mld_int_mlo_scan(mld, vif); + } } /* no more logic if we're not in EMLSR */ @@ -592,7 +599,8 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, return; IWL_DEBUG_EHT(mld, - "missed bcn on the other link (link_id=%u): %u\n", + "missed bcn link_id=%u: %u consecutive=%u, other link_id=%u: %u\n", + link_id, missed_bcon, missed_bcon_since_rx, other_link->link_id, scnd_lnk_bcn_lost); /* Exit EMLSR if we lost more than diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 5725104a53bf..55b484c16280 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -23,6 +23,7 @@ #include "roc.h" #include "mlo.h" #include "stats.h" +#include "iwl-nvm-parse.h" #include "ftm-initiator.h" #include "low_latency.h" #include "fw/api/scan.h" @@ -75,13 +76,12 @@ iwl_mld_iface_combinations[] = { }, }; -static const u8 if_types_ext_capa_sta[] = { - [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, - [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, - [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF | - WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB, - [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB, - [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, +static const u8 ext_capa_base[IWL_MLD_STA_EXT_CAPA_SIZE] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF | + WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB, + [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB, }; #define IWL_MLD_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \ @@ -94,18 +94,6 @@ static const u8 if_types_ext_capa_sta[] = { IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \ IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT) -static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { - { - .iftype = NL80211_IFTYPE_STATION, - .extended_capabilities = if_types_ext_capa_sta, - .extended_capabilities_mask = if_types_ext_capa_sta, - .extended_capabilities_len = sizeof(if_types_ext_capa_sta), - /* relevant only if EHT is supported */ - .eml_capabilities = IWL_MLD_EMLSR_CAPA, - .mld_capa_and_ops = IWL_MLD_CAPA_OPS, - }, -}; - static void iwl_mld_hw_set_addresses(struct iwl_mld *mld) { struct wiphy *wiphy = mld->wiphy; @@ -335,21 +323,37 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT)) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PROTECTED_TWT); - wiphy->iftype_ext_capab = NULL; - wiphy->num_iftype_ext_capab = 0; - - if (!iwlwifi_mod_params.disable_11ax) { - wiphy->iftype_ext_capab = iftypes_ext_capa; - wiphy->num_iftype_ext_capab = ARRAY_SIZE(iftypes_ext_capa); - - ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); - ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); - } - if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; else wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* We are done for non-HE */ + if (iwlwifi_mod_params.disable_11ax) + return; + + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); + + wiphy->iftype_ext_capab = mld->ext_capab; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(mld->ext_capab); + + BUILD_BUG_ON(sizeof(mld->sta_ext_capab) < sizeof(ext_capa_base)); + + memcpy(mld->sta_ext_capab, ext_capa_base, sizeof(ext_capa_base)); + + mld->ext_capab[0].iftype = NL80211_IFTYPE_STATION; + mld->ext_capab[0].extended_capabilities = mld->sta_ext_capab; + mld->ext_capab[0].extended_capabilities_mask = mld->sta_ext_capab; + mld->ext_capab[0].extended_capabilities_len = sizeof(mld->sta_ext_capab); + + if (!mld->nvm_data->sku_cap_11be_enable || + iwlwifi_mod_params.disable_11be) + return; + + mld->ext_capab[0].eml_capabilities = IWL_MLD_EMLSR_CAPA; + mld->ext_capab[0].mld_capa_and_ops = IWL_MLD_CAPA_OPS; + } static void iwl_mac_hw_set_misc(struct iwl_mld *mld) @@ -393,11 +397,9 @@ static int iwl_mld_hw_verify_preconditions(struct iwl_mld *mld) TLC_MNG_UPDATE_NOTIF, 0) >= 4) + (iwl_fw_lookup_notif_ver(mld->fw, LEGACY_GROUP, REPLY_RX_MPDU_CMD, 0) >= 6) + - (iwl_fw_lookup_notif_ver(mld->fw, DATA_PATH_GROUP, - RX_NO_DATA_NOTIF, 0) >= 4) + (iwl_fw_lookup_notif_ver(mld->fw, LONG_GROUP, TX_CMD, 0) >= 9); - if (ratecheck != 0 && ratecheck != 5) { + if (ratecheck != 0 && ratecheck != 4) { IWL_ERR(mld, "Firmware has inconsistent rates\n"); return -EINVAL; } @@ -680,6 +682,8 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw, #endif iwl_mld_rm_vif(mld, vif); + + mld->monitor.phy.valid = false; } struct iwl_mld_mc_iter_data { @@ -2591,11 +2595,44 @@ iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return NEG_TTLM_RES_ACCEPT; } +static int iwl_mld_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + *tx_ant = iwl_mld_get_valid_tx_ant(mld); + *rx_ant = iwl_mld_get_valid_rx_ant(mld); + + return 0; +} + +static int iwl_mld_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + if (WARN_ON(!mld->nvm_data)) + return -EBUSY; + + /* mac80211 ensures the device is not started, + * so the firmware cannot be running + */ + + mld->set_tx_ant = tx_ant; + mld->set_rx_ant = rx_ant; + + iwl_reinit_cab(mld->trans, mld->nvm_data, tx_ant, rx_ant, mld->fw); + + return 0; +} + const struct ieee80211_ops iwl_mld_hw_ops = { .tx = iwl_mld_mac80211_tx, .start = iwl_mld_mac80211_start, .stop = iwl_mld_mac80211_stop, .config = iwl_mld_mac80211_config, + .get_antenna = iwl_mld_get_antenna, + .set_antenna = iwl_mld_set_antenna, .add_interface = iwl_mld_mac80211_add_interface, .remove_interface = iwl_mld_mac80211_remove_interface, .conf_tx = iwl_mld_mac80211_conf_tx, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index a6962256bdd1..8a4c96385640 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -259,6 +259,7 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = { HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(TLC_MNG_UPDATE_NOTIF), HCMD_NAME(BEACON_FILTER_IN_NOTIF), + HCMD_NAME(PHY_AIR_SNIFFER_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 94dc9da6360d..22efe8e10f53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -118,7 +118,11 @@ * @monitor.cur_bssid: current bssid tracked by the sniffer * @monitor.ptp_time: set the Rx mactime using the device's PTP clock time * @monitor.p80: primary channel position relative to he whole bandwidth, in - * steps of 80 MHz + * steps of 80 MHz + * @monitor.phy: PHY data information + * @monitor.phy.data: PHY data (&struct iwl_rx_phy_air_sniffer_ntfy) received + * @monitor.phy.valid: PHY data is valid (was received) + * @monitor.phy.used: PHY data was used by an RX * @fw_id_to_link_sta: maps a fw id of a sta to the corresponding * ieee80211_link_sta. This is not cleaned up on restart since we want to * preserve the fw sta ids during a restart (for SN/PN restoring). @@ -134,6 +138,8 @@ * @fw: a pointer to the fw object * @hw: pointer to the hw object. * @wiphy: a pointer to the wiphy struct, for easier access to it. + * @ext_capab: extended capabilities that will be set to wiphy on registration. + * @sta_ext_capab: extended capabilities for the station interface. * @nvm_data: pointer to the nvm_data that includes all our capabilities * @fwrt: fw runtime data * @debugfs_dir: debugfs directory @@ -180,6 +186,8 @@ * @mcast_filter_cmd: pointer to the multicast filter command. * @mgmt_tx_ant: stores the last TX antenna index; used for setting * TX rate_n_flags for non-STA mgmt frames (toggles on every TX failure). + * @set_tx_ant: stores the last TX antenna bitmask set by user space (if any) + * @set_rx_ant: stores the last RX antenna bitmask set by user space (if any) * @fw_rates_ver_3: FW rates are in version 3 * @low_latency: low-latency manager. * @tzone: thermal zone device's data @@ -205,6 +213,10 @@ struct iwl_mld { u32 ampdu_ref; bool ampdu_toggle; u8 p80; + struct { + struct iwl_rx_phy_air_sniffer_ntfy data; + u8 valid:1, used:1; + } phy; #ifdef CONFIG_IWLWIFI_DEBUGFS __le16 cur_aid; u8 cur_bssid[ETH_ALEN]; @@ -225,6 +237,8 @@ struct iwl_mld { const struct iwl_fw *fw; struct ieee80211_hw *hw; struct wiphy *wiphy; + struct wiphy_iftype_ext_capab ext_capab[IWL_MLD_EXT_CAPA_NUM_IFTYPES]; + u8 sta_ext_capab[IWL_MLD_STA_EXT_CAPA_SIZE]; struct iwl_nvm_data *nvm_data; struct iwl_fw_runtime fwrt; struct dentry *debugfs_dir; @@ -279,6 +293,9 @@ struct iwl_mld { u8 mgmt_tx_ant; + u8 set_tx_ant; + u8 set_rx_ant; + bool fw_rates_ver_3; struct iwl_mld_low_latency low_latency; @@ -374,6 +391,9 @@ static inline u8 iwl_mld_get_valid_tx_ant(const struct iwl_mld *mld) if (mld->nvm_data && mld->nvm_data->valid_tx_ant) tx_ant &= mld->nvm_data->valid_tx_ant; + if (mld->set_tx_ant) + tx_ant &= mld->set_tx_ant; + return tx_ant; } @@ -384,6 +404,9 @@ static inline u8 iwl_mld_get_valid_rx_ant(const struct iwl_mld *mld) if (mld->nvm_data && mld->nvm_data->valid_rx_ant) rx_ant &= mld->nvm_data->valid_rx_ant; + if (mld->set_rx_ant) + rx_ant &= mld->set_rx_ant; + return rx_ant; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index 241a6271d13d..c6b151f26921 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -31,11 +31,9 @@ static void iwl_mld_print_emlsr_blocked(struct iwl_mld *mld, u32 mask) { #define NAME_FMT(x) "%s" #define NAME_PR(x) (mask & IWL_MLD_EMLSR_BLOCKED_##x) ? "[" #x "]" : "", - IWL_DEBUG_INFO(mld, - "EMLSR blocked = " HANDLE_EMLSR_BLOCKED_REASONS(NAME_FMT) - " (0x%x)\n", - HANDLE_EMLSR_BLOCKED_REASONS(NAME_PR) - mask); + IWL_DEBUG_EHT(mld, + "EMLSR blocked = " HANDLE_EMLSR_BLOCKED_REASONS(NAME_FMT) + " (0x%x)\n", HANDLE_EMLSR_BLOCKED_REASONS(NAME_PR) mask); #undef NAME_FMT #undef NAME_PR } @@ -72,11 +70,9 @@ static void iwl_mld_print_emlsr_exit(struct iwl_mld *mld, u32 mask) { #define NAME_FMT(x) "%s" #define NAME_PR(x) (mask & IWL_MLD_EMLSR_EXIT_##x) ? "[" #x "]" : "", - IWL_DEBUG_INFO(mld, - "EMLSR exit = " HANDLE_EMLSR_EXIT_REASONS(NAME_FMT) - " (0x%x)\n", - HANDLE_EMLSR_EXIT_REASONS(NAME_PR) - mask); + IWL_DEBUG_EHT(mld, + "EMLSR exit = " HANDLE_EMLSR_EXIT_REASONS(NAME_FMT) + " (0x%x)\n", HANDLE_EMLSR_EXIT_REASONS(NAME_PR) mask); #undef NAME_FMT #undef NAME_PR } @@ -170,10 +166,10 @@ static void iwl_mld_check_emlsr_prevention(struct iwl_mld *mld, WARN_ON(mld_vif->emlsr.exit_repeat_count > 3); } - IWL_DEBUG_INFO(mld, - "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n", - delay / HZ, mld_vif->emlsr.exit_repeat_count, - iwl_mld_get_emlsr_exit_string(reason), reason); + IWL_DEBUG_EHT(mld, + "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n", + delay / HZ, mld_vif->emlsr.exit_repeat_count, + iwl_mld_get_emlsr_exit_string(reason), reason); wiphy_delayed_work_queue(mld->wiphy, &mld_vif->emlsr.prevent_done_wk, delay); @@ -217,10 +213,10 @@ static int _iwl_mld_exit_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, link_to_keep = __ffs(vif->active_links); new_active_links = BIT(link_to_keep); - IWL_DEBUG_INFO(mld, - "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n", - iwl_mld_get_emlsr_exit_string(exit), exit, - vif->active_links, new_active_links); + IWL_DEBUG_EHT(mld, + "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n", + iwl_mld_get_emlsr_exit_string(exit), exit, + vif->active_links, new_active_links); if (sync) ret = ieee80211_set_active_links(vif, new_active_links); @@ -262,9 +258,8 @@ static int _iwl_mld_emlsr_block(struct iwl_mld *mld, struct ieee80211_vif *vif, mld_vif->emlsr.blocked_reasons |= reason; - IWL_DEBUG_INFO(mld, - "Blocking EMLSR mode. reason = %s (0x%x)\n", - iwl_mld_get_emlsr_blocked_string(reason), reason); + IWL_DEBUG_EHT(mld, "Blocking EMLSR mode. reason = %s (0x%x)\n", + iwl_mld_get_emlsr_blocked_string(reason), reason); iwl_mld_print_emlsr_blocked(mld, mld_vif->emlsr.blocked_reasons); if (reason == IWL_MLD_EMLSR_BLOCKED_TPT) @@ -335,9 +330,8 @@ void iwl_mld_unblock_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, mld_vif->emlsr.blocked_reasons &= ~reason; - IWL_DEBUG_INFO(mld, - "Unblocking EMLSR mode. reason = %s (0x%x)\n", - iwl_mld_get_emlsr_blocked_string(reason), reason); + IWL_DEBUG_EHT(mld, "Unblocking EMLSR mode. reason = %s (0x%x)\n", + iwl_mld_get_emlsr_blocked_string(reason), reason); iwl_mld_print_emlsr_blocked(mld, mld_vif->emlsr.blocked_reasons); if (reason == IWL_MLD_EMLSR_BLOCKED_TPT) @@ -348,7 +342,7 @@ void iwl_mld_unblock_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif, if (mld_vif->emlsr.blocked_reasons) return; - IWL_DEBUG_INFO(mld, "EMLSR is unblocked\n"); + IWL_DEBUG_EHT(mld, "EMLSR is unblocked\n"); iwl_mld_int_mlo_scan(mld, vif); } @@ -365,18 +359,17 @@ iwl_mld_vif_iter_emlsr_mode_notif(void *data, u8 *mac, switch (action) { case ESR_RECOMMEND_LEAVE: - IWL_DEBUG_INFO(mld_vif->mld, - "FW recommend leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_EHT(mld_vif->mld, + "FW recommend leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); iwl_mld_exit_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_EXIT_FW_REQUEST, iwl_mld_get_primary_link(vif)); break; case ESR_FORCE_LEAVE: - IWL_DEBUG_INFO(mld_vif->mld, - "FW force leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_EHT(mld_vif->mld, "FW force leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); fallthrough; case ESR_RECOMMEND_ENTER: default: @@ -412,11 +405,12 @@ void iwl_mld_handle_emlsr_trans_fail_notif(struct iwl_mld *mld, struct ieee80211_bss_conf *bss_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id); - IWL_DEBUG_INFO(mld, "Failed to %s EMLSR on link %d (FW: %d), reason %d\n", - le32_to_cpu(notif->activation) ? "enter" : "exit", - bss_conf ? bss_conf->link_id : -1, - le32_to_cpu(notif->link_id), - le32_to_cpu(notif->err_code)); + IWL_DEBUG_EHT(mld, + "Failed to %s EMLSR on link %d (FW: %d), reason %d\n", + le32_to_cpu(notif->activation) ? "enter" : "exit", + bss_conf ? bss_conf->link_id : -1, + le32_to_cpu(notif->link_id), + le32_to_cpu(notif->err_code)); if (IWL_FW_CHECK(mld, !bss_conf, "FW reported failure to %sactivate EMLSR on a non-existing link: %d\n", @@ -590,8 +584,8 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) spin_unlock_bh(&queue_counter->lock); } - IWL_DEBUG_INFO(mld, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", - total_tx, total_rx); + IWL_DEBUG_EHT(mld, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", + total_tx, total_rx); /* If we don't have enough MPDUs - exit EMLSR */ if (total_tx < IWL_MLD_ENTER_EMLSR_TPT_THRESH && @@ -603,10 +597,10 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) /* EMLSR is not active */ if (sec_link_id == -1) - return; + goto schedule; - IWL_DEBUG_INFO(mld, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", - sec_link_id, sec_link_tx, sec_link_rx); + IWL_DEBUG_EHT(mld, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", + sec_link_id, sec_link_tx, sec_link_rx); /* Calculate the percentage of the secondary link TX/RX */ sec_link_tx_perc = total_tx ? sec_link_tx * 100 / total_tx : 0; @@ -625,6 +619,7 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) return; } +schedule: /* Check again when the next window ends */ wiphy_delayed_work_queue(mld_vif->mld->wiphy, &mld_vif->emlsr.check_tpt_wk, @@ -702,10 +697,8 @@ iwl_mld_emlsr_disallowed_with_link(struct iwl_mld *mld, ret |= IWL_MLD_EMLSR_EXIT_CSA; if (ret) { - IWL_DEBUG_INFO(mld, - "Link %d is not allowed for EMLSR as %s\n", - link->link_id, - primary ? "primary" : "secondary"); + IWL_DEBUG_EHT(mld, "Link %d is not allowed for EMLSR as %s\n", + link->link_id, primary ? "primary" : "secondary"); iwl_mld_print_emlsr_exit(mld, ret); } @@ -869,13 +862,12 @@ iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif, reason_mask |= IWL_MLD_EMLSR_EXIT_CHAN_LOAD; if (reason_mask) { - IWL_DEBUG_INFO(mld, - "Links %d and %d are not a valid pair for EMLSR\n", - a->link_id, b->link_id); - IWL_DEBUG_INFO(mld, - "Links bandwidth are: %d and %d\n", - nl80211_chan_width_to_mhz(a->chandef->width), - nl80211_chan_width_to_mhz(b->chandef->width)); + IWL_DEBUG_EHT(mld, + "Links %d and %d are not a valid pair for EMLSR\n", + a->link_id, b->link_id); + IWL_DEBUG_EHT(mld, "Links bandwidth are: %d and %d\n", + nl80211_chan_width_to_mhz(a->chandef->width), + nl80211_chan_width_to_mhz(b->chandef->width)); iwl_mld_print_emlsr_exit(mld, reason_mask); } @@ -993,8 +985,8 @@ static void _iwl_mld_select_links(struct iwl_mld *mld, } set_active: - IWL_DEBUG_INFO(mld, "Link selection result: 0x%x. Primary = %d\n", - new_active, new_primary); + IWL_DEBUG_EHT(mld, "Link selection result: 0x%x. Primary = %d\n", + new_active, new_primary); mld_vif->emlsr.selected_primary = new_primary; mld_vif->emlsr.selected_links = new_active; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 884973d0b344..4cf3920b005f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -589,8 +589,8 @@ void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi, else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP, RX_QUEUES_NOTIFICATION))) iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, 0); - else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF)) - iwl_mld_rx_monitor_no_data(mld, napi, pkt, 0); + else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, PHY_AIR_SNIFFER_NOTIF)) + iwl_mld_handle_phy_air_sniffer_notif(mld, napi, pkt); else iwl_mld_rx_notif(mld, rxb, pkt); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/roc.c b/drivers/net/wireless/intel/iwlwifi/mld/roc.c index 4136c98030d0..4e37a288471e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/roc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/roc.c @@ -231,7 +231,9 @@ void iwl_mld_handle_roc_notif(struct iwl_mld *mld, struct ieee80211_vif *vif; vif = iwl_mld_find_roc_vif(mld, activity); - if (WARN_ON(!vif)) + if (IWL_FW_CHECK(mld, !vif, + "unexpected ROC notif from FW for activity %d\n", + activity)) return; mld_vif = iwl_mld_vif_from_mac80211(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 20d866dd92c2..6a76e3fcb581 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -18,41 +18,32 @@ /* stores relevant PHY data fields extracted from iwl_rx_mpdu_desc */ struct iwl_mld_rx_phy_data { - enum iwl_rx_phy_info_type info_type; - __le32 data0; - __le32 data1; - __le32 data2; - __le32 data3; - __le32 eht_data4; - __le32 data5; - __le16 data4; + struct iwl_rx_phy_air_sniffer_ntfy *ntfy; bool first_subframe; bool with_data; - __le32 rx_vec[4]; u32 rate_n_flags; u32 gp2_on_air_rise; + /* phy_info is only valid when we have a frame, i.e. with_data=true */ u16 phy_info; u8 energy_a, energy_b; }; static void -iwl_mld_fill_phy_data(struct iwl_mld *mld, - struct iwl_rx_mpdu_desc *desc, - struct iwl_mld_rx_phy_data *phy_data) +iwl_mld_fill_phy_data_from_mpdu(struct iwl_mld *mld, + struct iwl_rx_mpdu_desc *desc, + struct iwl_mld_rx_phy_data *phy_data) { + if (unlikely(mld->monitor.phy.valid)) { + mld->monitor.phy.used = true; + phy_data->ntfy = &mld->monitor.phy.data; + } + phy_data->phy_info = le16_to_cpu(desc->phy_info); phy_data->rate_n_flags = iwl_v3_rate_from_v2_v3(desc->v3.rate_n_flags, mld->fw_rates_ver_3); phy_data->gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise); phy_data->energy_a = desc->v3.energy_a; phy_data->energy_b = desc->v3.energy_b; - phy_data->data0 = desc->v3.phy_data0; - phy_data->data1 = desc->v3.phy_data1; - phy_data->data2 = desc->v3.phy_data2; - phy_data->data3 = desc->v3.phy_data3; - phy_data->data4 = desc->phy_data4; - phy_data->eht_data4 = desc->phy_eht_data4; - phy_data->data5 = desc->v3.phy_data5; phy_data->with_data = true; } @@ -217,26 +208,19 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id, } static void -iwl_mld_decode_he_phy_ru_alloc(struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_radiotap_he *he, - struct ieee80211_radiotap_he_mu *he_mu, - struct ieee80211_rx_status *rx_status) +iwl_mld_he_set_ru_alloc(struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_he *he, + u8 ru_with_p80) { - /* Unfortunately, we have to leave the mac80211 data - * incorrect for the case that we receive an HE-MU - * transmission and *don't* have the HE phy data (due - * to the bits being used for TSF). This shouldn't - * happen though as management frames where we need - * the TSF/timers are not be transmitted in HE-MU. - */ - u8 ru = le32_get_bits(phy_data->data1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK); - u32 rate_n_flags = phy_data->rate_n_flags; - u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + u8 ru = ru_with_p80 >> 1; + u8 p80 = ru_with_p80 & 1; u8 offs = 0; rx_status->bw = RATE_INFO_BW_HE_RU; he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); switch (ru) { case 0 ... 36: @@ -266,227 +250,262 @@ iwl_mld_decode_he_phy_ru_alloc(struct iwl_mld_rx_phy_data *phy_data, rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; break; } + he->data2 |= le16_encode_bits(offs, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); - he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); - if (phy_data->data1 & cpu_to_le32(IWL_RX_PHY_DATA1_HE_RU_ALLOC_SEC80)) - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); -#define CHECK_BW(bw) \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ - RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS); \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \ - RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) - CHECK_BW(20); - CHECK_BW(40); - CHECK_BW(80); - CHECK_BW(160); - - if (he_mu) - he_mu->flags2 |= - le16_encode_bits(u32_get_bits(rate_n_flags, - RATE_MCS_CHAN_WIDTH_MSK), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); - else if (he_type == RATE_MCS_HE_TYPE_TRIG) - he->data6 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | - le16_encode_bits(u32_get_bits(rate_n_flags, - RATE_MCS_CHAN_WIDTH_MSK), - IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW); + he->data2 |= le16_encode_bits(p80, IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); } +#define RTAP_ENC_HE(src, src_msk, dst_msk) \ + le16_encode_bits(le32_get_bits(src, src_msk), dst_msk) + static void -iwl_mld_decode_he_mu_ext(struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_radiotap_he_mu *he_mu) +iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_he *he, + struct ieee80211_radiotap_he_mu *he_mu, + struct ieee80211_rx_status *rx_status) { - u32 phy_data2 = le32_to_cpu(phy_data->data2); - u32 phy_data3 = le32_to_cpu(phy_data->data3); - u16 phy_data4 = le16_to_cpu(phy_data->data4); u32 rate_n_flags = phy_data->rate_n_flags; - if (u32_get_bits(phy_data4, IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK)) { + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_DCM, + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_MCS, + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_PRMBL_PUNC_TYPE, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_MU_NUM_OF_SIGB_SYM_OR_USER_NUM, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_MU_SIGB_COMP, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); + + if (phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU && + le32_get_bits(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_COMMON_CC1_CRC_OK)) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN); he_mu->flags1 |= - le16_encode_bits(u32_get_bits(phy_data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); - - he_mu->ru_ch1[0] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0); - he_mu->ru_ch1[1] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1); - he_mu->ru_ch1[2] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU2); - he_mu->ru_ch1[3] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3); + RTAP_ENC_HE(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_CENTER_RU_CC1, + IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); + + he_mu->ru_ch1[0] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_A1); + he_mu->ru_ch1[1] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_C1); + he_mu->ru_ch1[2] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_A2); + he_mu->ru_ch1[3] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_C2); } - if (u32_get_bits(phy_data4, IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK) && + if (phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU && + le32_get_bits(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_COMMON_CC2_CRC_OK) && (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN); he_mu->flags2 |= - le16_encode_bits(u32_get_bits(phy_data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); - - he_mu->ru_ch2[0] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU0); - he_mu->ru_ch2[1] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU1); - he_mu->ru_ch2[2] = u32_get_bits(phy_data2, - IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU2); - he_mu->ru_ch2[3] = u32_get_bits(phy_data3, - IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU3); + RTAP_ENC_HE(phy_data->ntfy->sigs.he.cmn[2], + OFDM_RX_FRAME_HE_CENTER_RU_CC2, + IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); + + he_mu->ru_ch2[0] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_B1); + he_mu->ru_ch2[1] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_D1); + he_mu->ru_ch2[2] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[0], + OFDM_RX_FRAME_HE_RU_ALLOC_0_B2); + he_mu->ru_ch2[3] = le32_get_bits(phy_data->ntfy->sigs.he.cmn[1], + OFDM_RX_FRAME_HE_RU_ALLOC_1_D2); } + +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + + he_mu->flags2 |= + le16_encode_bits(u32_get_bits(rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); + + iwl_mld_he_set_ru_alloc(rx_status, he, + le32_get_bits(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_STA_RU)); +} + +static void +iwl_mld_decode_he_tb_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_he *he, + struct ieee80211_rx_status *rx_status) +{ + u32 rate_n_flags = phy_data->rate_n_flags; + u32 nsts; + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN); + + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_1, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_2, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_3, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_SPATIAL_REUSE_4, + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4); + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a1, + OFDM_RX_HE_TRIG_BSS_COLOR, + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + + he->data6 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | + le16_encode_bits(u32_get_bits(rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK), + IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW); + + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_TB_RX)) + return; + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_DOPPLER, + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PE_DISAMBIG, + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he_tb.a2, + OFDM_RX_HE_TRIG_TXOP_DURATION, + IEEE80211_RADIOTAP_HE_DATA6_TXOP); + + iwl_mld_he_set_ru_alloc(rx_status, he, + le32_get_bits(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU)); + + nsts = le32_get_bits(phy_data->ntfy->sigs.he_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NSTS) + 1; + rx_status->nss = nsts >> !!(rate_n_flags & RATE_MCS_STBC_MSK); } static void iwl_mld_decode_he_phy_data(struct iwl_mld_rx_phy_data *phy_data, struct ieee80211_radiotap_he *he, struct ieee80211_radiotap_he_mu *he_mu, - struct ieee80211_rx_status *rx_status, - int queue) + struct ieee80211_rx_status *rx_status) { - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_NONE: - case IWL_RX_PHY_INFO_TYPE_CCK: - case IWL_RX_PHY_INFO_TYPE_OFDM_LGCY: - case IWL_RX_PHY_INFO_TYPE_HT: - case IWL_RX_PHY_INFO_TYPE_VHT_SU: - case IWL_RX_PHY_INFO_TYPE_VHT_MU: - case IWL_RX_PHY_INFO_TYPE_EHT_MU: - case IWL_RX_PHY_INFO_TYPE_EHT_TB: - case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT: - return; - case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data2, - IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4), - IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4); - fallthrough; - case IWL_RX_PHY_INFO_TYPE_HE_SU: - case IWL_RX_PHY_INFO_TYPE_HE_MU: - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_TB: - /* HE common */ - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); - he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_BSS_COLOR_MASK), - IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); - if (phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB && - phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB_EXT) { - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_UPLINK), - IEEE80211_RADIOTAP_HE_DATA3_UL_DL); - } - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM), - IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); - he->data5 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK), - IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); - he->data5 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_PE_DISAMBIG), - IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); - he->data5 |= le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_HE_LTF_NUM_MASK), - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); - he->data6 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_TXOP_DUR_MASK), - IEEE80211_RADIOTAP_HE_DATA6_TXOP); - he->data6 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_DOPPLER), - IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); - break; - } + u32 rate_n_flags = phy_data->rate_n_flags; + u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + u32 nsts; - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_MU: - case IWL_RX_PHY_INFO_TYPE_HE_SU: - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN); - he->data4 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK), - IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); - break; - default: - /* nothing here */ - break; - } + switch (he_type) { + case RATE_MCS_HE_TYPE_TRIG: + iwl_mld_decode_he_tb_phy_data(phy_data, he, rx_status); + /* that's it, below is only for SU/MU */ + return; + case RATE_MCS_HE_TYPE_MU: + iwl_mld_decode_he_mu(phy_data, he, he_mu, rx_status); - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - he_mu->flags1 |= - le16_encode_bits(le16_get_bits(phy_data->data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); - he_mu->flags1 |= - le16_encode_bits(le16_get_bits(phy_data->data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_MCS_MASK), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); - he_mu->flags2 |= - le16_encode_bits(le16_get_bits(phy_data->data4, - IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); - iwl_mld_decode_he_mu_ext(phy_data, he_mu); - fallthrough; - case IWL_RX_PHY_INFO_TYPE_HE_MU: - he_mu->flags2 |= - le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); - he_mu->flags2 |= - le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); - fallthrough; - case IWL_RX_PHY_INFO_TYPE_HE_TB: - case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: - iwl_mld_decode_he_phy_ru_alloc(phy_data, he, he_mu, rx_status); + nsts = le32_get_bits(phy_data->ntfy->sigs.he.b, + OFDM_RX_FRAME_HE_SIGB_NSTS) + 1; break; - case IWL_RX_PHY_INFO_TYPE_HE_SU: + case RATE_MCS_HE_TYPE_SU: + case RATE_MCS_HE_TYPE_EXT_SU: he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN); - he->data3 |= le16_encode_bits(le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_HE_BEAM_CHNG), - IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); - break; - default: - /* nothing */ + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_BEAM_CHANGE, + IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); + + nsts = le32_get_bits(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_NSTS) + 1; break; } + + rx_status->nss = nsts >> !!(rate_n_flags & RATE_MCS_STBC_MSK); + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_PE_DISAMBIG, + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); + he->data5 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_MU_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_TXOP_DURATION, + IEEE80211_RADIOTAP_HE_DATA6_TXOP); + he->data6 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, + OFDM_RX_FRAME_HE_DOPPLER, + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_BSS_COLOR, + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + he->data3 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_UL_FLAG, + IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + he->data4 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_SPATIAL_REUSE, + IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); } -static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data, - int queue) +static void iwl_mld_rx_he(struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_he *he = NULL; @@ -510,48 +529,28 @@ static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), }; - u16 phy_info = phy_data->phy_info; he = skb_put_data(skb, &known, sizeof(known)); rx_status->flag |= RX_FLAG_RADIOTAP_HE; - if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU || - phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU_EXT) { - he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); - rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; - } - - /* report the AMPDU-EOF bit on single frames */ - if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { - rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) - iwl_mld_decode_he_phy_data(phy_data, he, he_mu, rx_status, - queue); - - /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && - (phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) { - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - if (he_type == RATE_MCS_HE_TYPE_EXT_SU && - rate_n_flags & RATE_MCS_HE_106T_MSK) { - rx_status->bw = RATE_INFO_BW_HE_RU; - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - } - - /* actually data is filled in mac80211 */ - if (he_type == RATE_MCS_HE_TYPE_SU || - he_type == RATE_MCS_HE_TYPE_EXT_SU) + switch (he_type) { + case RATE_MCS_HE_TYPE_EXT_SU: + /* + * Except for this special case we won't have + * HE RU allocation info outside of monitor mode + * since we don't get the PHY notif. + */ + if (rate_n_flags & RATE_MCS_HE_106T_MSK) { + rx_status->bw = RATE_INFO_BW_HE_RU; + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + } + fallthrough; + case RATE_MCS_HE_TYPE_SU: + /* actual data is filled in mac80211 */ he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + break; + } #define CHECK_TYPE(F) \ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ @@ -567,8 +566,7 @@ static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, if (rate_n_flags & RATE_MCS_BF_MSK) he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF); - switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> - RATE_MCS_HE_GI_LTF_POS) { + switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { case 0: if (he_type == RATE_MCS_HE_TYPE_TRIG) rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; @@ -609,37 +607,52 @@ static void iwl_mld_rx_he(struct iwl_mld *mld, struct sk_buff *skb, he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + + if (likely(!phy_data->ntfy)) + return; + + if (he_type == RATE_MCS_HE_TYPE_MU) { + he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); + rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; + } + + iwl_mld_decode_he_phy_data(phy_data, he, he_mu, rx_status); } static void iwl_mld_decode_lsig(struct sk_buff *skb, struct iwl_mld_rx_phy_data *phy_data) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u32 format = phy_data->rate_n_flags & RATE_MCS_MOD_TYPE_MSK; struct ieee80211_radiotap_lsig *lsig; + u32 lsig_len, rate; - switch (phy_data->info_type) { - case IWL_RX_PHY_INFO_TYPE_HT: - case IWL_RX_PHY_INFO_TYPE_VHT_SU: - case IWL_RX_PHY_INFO_TYPE_VHT_MU: - case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_SU: - case IWL_RX_PHY_INFO_TYPE_HE_MU: - case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_HE_TB: - case IWL_RX_PHY_INFO_TYPE_EHT_MU: - case IWL_RX_PHY_INFO_TYPE_EHT_TB: - case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT: - case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT: - lsig = skb_put(skb, sizeof(*lsig)); - lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN); - lsig->data2 = le16_encode_bits(le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_LSIG_LEN_MASK), - IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH); - rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; - break; - default: - break; - } + if (likely(!phy_data->ntfy)) + return; + + /* + * Technically legacy CCK/OFDM frames don't have an L-SIG + * since that's the compat format for HT (non-greenfield) + * and up. However, it's meant to be compatible with the + * LENGTH and RATE fields in Clause 17 and 18 OFDM frames + * so include the field for any non-CCK frame. For CCK it + * cannot work, since the LENGTH field for them is 16-bit + * and the radiotap field only has 12 bits. + */ + if (format == RATE_MCS_MOD_TYPE_CCK) + return; + + lsig_len = le32_get_bits(phy_data->ntfy->legacy_sig.ofdm, + OFDM_RX_LEGACY_LENGTH); + rate = le32_get_bits(phy_data->ntfy->legacy_sig.ofdm, OFDM_RX_RATE); + + lsig = skb_put(skb, sizeof(*lsig)); + lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN) | + cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_RATE_KNOWN); + lsig->data2 = le16_encode_bits(lsig_len, + IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH) | + le16_encode_bits(rate, IEEE80211_RADIOTAP_LSIG_DATA2_RATE); + rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; } /* Put a TLV on the skb and return data pointer @@ -667,209 +680,144 @@ iwl_mld_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len) (_usig)->value |= LE32_DEC_ENC(in_value, dec_bits, _enc_bits); \ } while (0) -#define __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ - eht->data[(rt_data)] |= \ - (cpu_to_le32 \ - (IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru ## _KNOWN) | \ - LE32_DEC_ENC(data ## fw_data, \ - IWL_RX_PHY_DATA ## fw_data ## _EHT_MU_EXT_RU_ALLOC_ ## fw_ru, \ - IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru)) +static void iwl_mld_decode_eht_usig_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.eht_tb.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.eht_tb.usig_a2_eht; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_PPDU_TYPE, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_TRIG_SPATIAL_REUSE_1, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_TRIG_SPATIAL_REUSE_2, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_TRIG_USIG2_DISREGARD, + IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD); +} -#define _IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ - __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) +static void iwl_mld_decode_eht_usig_non_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.eht.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.eht.usig_a2_eht; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_VALIDATE, + IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_PPDU_TYPE, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_PUNC_CHANNEL, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B8, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_SIG_MCS, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_EHT_SIG_SYM_NUM, + IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS); +} -#define IEEE80211_RADIOTAP_RU_DATA_1_1_1 1 -#define IEEE80211_RADIOTAP_RU_DATA_2_1_1 2 -#define IEEE80211_RADIOTAP_RU_DATA_1_1_2 2 -#define IEEE80211_RADIOTAP_RU_DATA_2_1_2 2 -#define IEEE80211_RADIOTAP_RU_DATA_1_2_1 3 -#define IEEE80211_RADIOTAP_RU_DATA_2_2_1 3 -#define IEEE80211_RADIOTAP_RU_DATA_1_2_2 3 -#define IEEE80211_RADIOTAP_RU_DATA_2_2_2 4 +static void iwl_mld_decode_eht_usig(struct iwl_mld_rx_phy_data *phy_data, + struct sk_buff *skb) +{ + u32 he_type = phy_data->rate_n_flags & RATE_MCS_HE_TYPE_MSK; + __le32 usig_a1 = phy_data->ntfy->sigs.eht.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.eht.usig_a2_eht; + struct ieee80211_radiotap_eht_usig *usig; + u32 bw; -#define IWL_RX_RU_DATA_A1 2 -#define IWL_RX_RU_DATA_A2 2 -#define IWL_RX_RU_DATA_B1 2 -#define IWL_RX_RU_DATA_B2 4 -#define IWL_RX_RU_DATA_C1 3 -#define IWL_RX_RU_DATA_C2 3 -#define IWL_RX_RU_DATA_D1 4 -#define IWL_RX_RU_DATA_D2 4 + usig = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG, + sizeof(*usig)); -#define IWL_MLD_ENC_EHT_RU(rt_ru, fw_ru) \ - _IWL_MLD_ENC_EHT_RU(IEEE80211_RADIOTAP_RU_DATA_ ## rt_ru, \ - rt_ru, \ - IWL_RX_RU_DATA_ ## fw_ru, \ - fw_ru) + BUILD_BUG_ON(offsetof(union iwl_sigs, eht.usig_a1) != + offsetof(union iwl_sigs, eht_tb.usig_a1)); + BUILD_BUG_ON(offsetof(union iwl_sigs, eht.usig_a2_eht) != + offsetof(union iwl_sigs, eht_tb.usig_a2_eht)); -static void iwl_mld_decode_eht_ext_mu(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht, - struct ieee80211_radiotap_eht_usig *usig) -{ - if (phy_data->with_data) { - __le32 data1 = phy_data->data1; - __le32 data2 = phy_data->data2; - __le32 data3 = phy_data->data3; - __le32 data4 = phy_data->eht_data4; - __le32 data5 = phy_data->data5; - u32 phy_bw = phy_data->rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_MU_PUNC_CH_CODE, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data4, - IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS); - IWL_MLD_ENC_USIG_VALUE_MASK - (usig, data1, IWL_RX_PHY_DATA1_EHT_MU_NUM_SIG_SYM_USIGA2, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS); + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN); - eht->user_info[0] |= - cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) | - LE32_DEC_ENC(data5, IWL_RX_PHY_DATA5_EHT_MU_STA_ID_USR, - IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID); +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_ ## bw ## _VAL) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + BUILD_BUG_ON(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_320MHZ_1 != + RATE_MCS_CHAN_WIDTH_320_VAL); + bw = u32_get_bits(phy_data->rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK); + /* specific handling for 320MHz-1/320MHz-2 */ + if (bw == RATE_MCS_CHAN_WIDTH_320_VAL) + bw += le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_BW320_SLOT); + usig->common |= le32_encode_bits(bw, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW); - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M); - eht->data[7] |= LE32_DEC_ENC - (data5, IWL_RX_PHY_DATA5_EHT_MU_NUM_USR_NON_OFDMA, - IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS); + usig->common |= LE32_DEC_ENC(usig_a1, OFDM_RX_FRAME_ENHANCED_WIFI_UL_FLAG, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); + usig->common |= LE32_DEC_ENC(usig_a1, OFDM_RX_FRAME_ENHANCED_WIFI_BSS_COLOR, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); - /* - * Hardware labels the content channels/RU allocation values - * as follows: - * Content Channel 1 Content Channel 2 - * 20 MHz: A1 - * 40 MHz: A1 B1 - * 80 MHz: A1 C1 B1 D1 - * 160 MHz: A1 C1 A2 C2 B1 D1 B2 D2 - * 320 MHz: A1 C1 A2 C2 A3 C3 A4 C4 B1 D1 B2 D2 B3 D3 B4 D4 - * - * However firmware can only give us A1-D2, so the higher - * frequencies are missing. - */ + if (le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_USIG1_VALIDATE) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B2) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_EHT_USIG2_VALIDATE_B8)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); - switch (phy_bw) { - case RATE_MCS_CHAN_WIDTH_320: - /* additional values are missing in RX metadata */ - fallthrough; - case RATE_MCS_CHAN_WIDTH_160: - /* content channel 1 */ - IWL_MLD_ENC_EHT_RU(1_2_1, A2); - IWL_MLD_ENC_EHT_RU(1_2_2, C2); - /* content channel 2 */ - IWL_MLD_ENC_EHT_RU(2_2_1, B2); - IWL_MLD_ENC_EHT_RU(2_2_2, D2); - fallthrough; - case RATE_MCS_CHAN_WIDTH_80: - /* content channel 1 */ - IWL_MLD_ENC_EHT_RU(1_1_2, C1); - /* content channel 2 */ - IWL_MLD_ENC_EHT_RU(2_1_2, D1); - fallthrough; - case RATE_MCS_CHAN_WIDTH_40: - /* content channel 2 */ - IWL_MLD_ENC_EHT_RU(2_1_1, B1); - fallthrough; - case RATE_MCS_CHAN_WIDTH_20: - IWL_MLD_ENC_EHT_RU(1_1_1, A1); - break; - } - } else { - __le32 usig_a1 = phy_data->rx_vec[0]; - __le32 usig_a2 = phy_data->rx_vec[1]; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - IWL_RX_USIG_A1_DISREGARD, - IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - IWL_RX_USIG_A1_VALIDATE, - IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_PPDU_TYPE, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_PUNC_CHANNEL, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B8, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_SIG_MCS, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS); - IWL_MLD_ENC_USIG_VALUE_MASK - (usig, usig_a2, IWL_RX_USIG_A2_EHT_SIG_SYM_NUM, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_CRC_OK, - IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC); - } -} + usig->common |= LE32_DEC_ENC(usig_a1, + OFDM_RX_FRAME_ENHANCED_WIFI_TXOP_DURATION, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); -static void iwl_mld_decode_eht_ext_tb(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht, - struct ieee80211_radiotap_eht_usig *usig) -{ - if (phy_data->with_data) { - __le32 data5 = phy_data->data5; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE1, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1); - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, data5, - IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE2, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2); - } else { - __le32 usig_a1 = phy_data->rx_vec[0]; - __le32 usig_a2 = phy_data->rx_vec[1]; - - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - IWL_RX_USIG_A1_DISREGARD, - IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_PPDU_TYPE, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_1, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_2, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_TRIG_USIG2_DISREGARD, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD); - IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, - IWL_RX_USIG_A2_EHT_CRC_OK, - IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC); - } + if (!le32_get_bits(usig_a2, OFDM_RX_USIG_CRC_OK)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); + + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN); + usig->common |= LE32_DEC_ENC(usig_a1, + OFDM_RX_FRAME_ENHANCED_WIFI_VER_ID, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER); + + if (he_type == RATE_MCS_HE_TYPE_TRIG) + iwl_mld_decode_eht_usig_tb(phy_data, usig); + else + iwl_mld_decode_eht_usig_non_tb(phy_data, usig); } -static void iwl_mld_decode_eht_ru(struct iwl_mld *mld, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht) +static void +iwl_mld_eht_set_ru_alloc(struct ieee80211_rx_status *rx_status, + u32 ru_with_p80) { - u32 ru = le32_get_bits(eht->data[8], - IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); enum nl80211_eht_ru_alloc nl_ru; + u32 ru = ru_with_p80 >> 1; - /* Using D1.5 Table 9-53a - Encoding of PS160 and RU Allocation subfields - * in an EHT variant User Info field + /* + * HW always uses trigger frame format: + * + * Draft PIEEE802.11be D7.0 Table 9-46l - Encoding of the PS160 and + * RU Allocation subfields in an EHT variant User Info field */ switch (ru) { @@ -929,135 +877,228 @@ static void iwl_mld_decode_eht_ru(struct iwl_mld *mld, rx_status->eht.ru = nl_ru; } -static void iwl_mld_decode_eht_phy_data(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status, - struct ieee80211_radiotap_eht *eht, - struct ieee80211_radiotap_eht_usig *usig) - +static void iwl_mld_decode_eht_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht *eht) { - __le32 data0 = phy_data->data0; - __le32 data1 = phy_data->data1; - __le32 usig_a1 = phy_data->rx_vec[0]; - u8 info_type = phy_data->info_type; - - /* Not in EHT range */ - if (info_type < IWL_RX_PHY_INFO_TYPE_EHT_MU || - info_type > IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT) + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_TB_RX)) return; - usig->common |= cpu_to_le32 - (IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN | - IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN); - if (phy_data->with_data) { - usig->common |= LE32_DEC_ENC(data0, - IWL_RX_PHY_DATA0_EHT_UPLINK, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); - usig->common |= LE32_DEC_ENC(data0, - IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); - } else { - usig->common |= LE32_DEC_ENC(usig_a1, - IWL_RX_USIG_A1_UL_FLAG, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); - usig->common |= LE32_DEC_ENC(usig_a1, - IWL_RX_USIG_A1_BSS_COLOR, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); - } - - usig->common |= - cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED); - usig->common |= - LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_VALIDATE, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); - - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE); - eht->data[0] |= LE32_DEC_ENC(data0, - IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK, - IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE); + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT | + IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF | + IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80); - /* All RU allocating size/index is in TB format */ - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT); - eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160, + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx0, + OFDM_UCODE_TRIG_BASE_PS160, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0, - IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7, + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU, + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0 | IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PE_DISAMBIG, + IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF); + eht->data[1] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht_tb.tb_rx0, + OFDM_UCODE_TRIG_BASE_RX_RU_P80, + IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); - iwl_mld_decode_eht_ru(mld, rx_status, eht); - - /* We only get here in case of IWL_RX_MPDU_PHY_TSF_OVERLOAD is set - * which is on only in case of monitor mode so no need to check monitor - * mode - */ - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80); - eht->data[1] |= - le32_encode_bits(mld->monitor.p80, - IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); - - usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN); - if (phy_data->with_data) - usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_TXOP_DUR_MASK, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); - else - usig->common |= LE32_DEC_ENC(usig_a1, IWL_RX_USIG_A1_TXOP_DURATION, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); + iwl_mld_eht_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU)); +} - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM); - eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_LDPC_EXT_SYM, - IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM); +static void iwl_mld_eht_decode_user_ru(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht *eht) +{ + u32 phy_bw = phy_data->rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM); - eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PRE_FEC_PAD_MASK, - IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM); + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU)) + return; - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM); - eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PE_DISAMBIG, - IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM); +#define __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ + eht->data[(rt_data)] |= \ + (cpu_to_le32(IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru ## _KNOWN) | \ + LE32_DEC_ENC(phy_data->ntfy->sigs.eht.cmn[fw_data], \ + OFDM_RX_FRAME_EHT_RU_ALLOC_ ## fw_data ## _ ## fw_ru, \ + IEEE80211_RADIOTAP_EHT_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru)) - /* TODO: what about IWL_RX_PHY_DATA0_EHT_BW320_SLOT */ +#define _IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) \ + __IWL_MLD_ENC_EHT_RU(rt_data, rt_ru, fw_data, fw_ru) - if (!le32_get_bits(data0, IWL_RX_PHY_DATA0_EHT_SIGA_CRC_OK)) - usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); +#define IEEE80211_RADIOTAP_RU_DATA_1_1_1 1 +#define IEEE80211_RADIOTAP_RU_DATA_2_1_1 2 +#define IEEE80211_RADIOTAP_RU_DATA_1_1_2 2 +#define IEEE80211_RADIOTAP_RU_DATA_2_1_2 2 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_1 3 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_1 3 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_2 3 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_2 4 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_3 4 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_3 4 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_4 5 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_4 5 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_5 5 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_5 6 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_6 6 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_6 6 + +#define IWL_RX_RU_DATA_A1 0 +#define IWL_RX_RU_DATA_A2 0 +#define IWL_RX_RU_DATA_A3 0 +#define IWL_RX_RU_DATA_A4 4 +#define IWL_RX_RU_DATA_B1 1 +#define IWL_RX_RU_DATA_B2 1 +#define IWL_RX_RU_DATA_B3 1 +#define IWL_RX_RU_DATA_B4 4 +#define IWL_RX_RU_DATA_C1 2 +#define IWL_RX_RU_DATA_C2 2 +#define IWL_RX_RU_DATA_C3 2 +#define IWL_RX_RU_DATA_C4 5 +#define IWL_RX_RU_DATA_D1 3 +#define IWL_RX_RU_DATA_D2 3 +#define IWL_RX_RU_DATA_D3 3 +#define IWL_RX_RU_DATA_D4 5 - usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN); - usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PHY_VER, - IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER); +#define IWL_MLD_ENC_EHT_RU(rt_ru, fw_ru) \ + _IWL_MLD_ENC_EHT_RU(IEEE80211_RADIOTAP_RU_DATA_ ## rt_ru, \ + rt_ru, \ + IWL_RX_RU_DATA_ ## fw_ru, \ + fw_ru) /* - * TODO: what about TB - IWL_RX_PHY_DATA1_EHT_TB_PILOT_TYPE, - * IWL_RX_PHY_DATA1_EHT_TB_LOW_SS + * Hardware labels the content channels/RU allocation values + * as follows: + * + * Content Channel 1 Content Channel 2 + * 20 MHz: A1 + * 40 MHz: A1 B1 + * 80 MHz: A1 C1 B1 D1 + * 160 MHz: A1 C1 A2 C2 B1 D1 B2 D2 + * 320 MHz: A1 C1 A2 C2 A3 C3 A4 C4 B1 D1 B2 D2 B3 D3 B4 D4 */ - eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF); - eht->data[0] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM, + switch (phy_bw) { + case RATE_MCS_CHAN_WIDTH_320: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_2_3, A3); + IWL_MLD_ENC_EHT_RU(1_2_4, C3); + IWL_MLD_ENC_EHT_RU(1_2_5, A4); + IWL_MLD_ENC_EHT_RU(1_2_6, C4); + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_2_3, B3); + IWL_MLD_ENC_EHT_RU(2_2_4, D3); + IWL_MLD_ENC_EHT_RU(2_2_5, B4); + IWL_MLD_ENC_EHT_RU(2_2_6, D4); + fallthrough; + case RATE_MCS_CHAN_WIDTH_160: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_2_1, A2); + IWL_MLD_ENC_EHT_RU(1_2_2, C2); + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_2_1, B2); + IWL_MLD_ENC_EHT_RU(2_2_2, D2); + fallthrough; + case RATE_MCS_CHAN_WIDTH_80: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_1_2, C1); + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_1_2, D1); + fallthrough; + case RATE_MCS_CHAN_WIDTH_40: + /* content channel 2 */ + IWL_MLD_ENC_EHT_RU(2_1_1, B1); + fallthrough; + case RATE_MCS_CHAN_WIDTH_20: + /* content channel 1 */ + IWL_MLD_ENC_EHT_RU(1_1_1, A1); + break; + } +} + +static void iwl_mld_decode_eht_non_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht *eht) +{ + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE | + /* All RU allocating size/index is in TB format */ + IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT | + IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PRE_PADD_FACOR_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_PE_DISAMBIGUITY_OM | + IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF | + IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80 | + IEEE80211_RADIOTAP_EHT_KNOWN_NR_NON_OFDMA_USERS_M); + + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_SPATIAL_REUSE, + IEEE80211_RADIOTAP_EHT_DATA0_SPATIAL_REUSE); + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU_PS160, + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160); + eht->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU, + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0 | + IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_EHT_DATA0_PRE_PADD_FACOR_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_PE_DISAMBIG, + IEEE80211_RADIOTAP_EHT_DATA0_PE_DISAMBIGUITY_OM); + eht->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_NUM_OF_LTF_SYM, IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF); + eht->data[1] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU_P80, + IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); + eht->data[7] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_NUM_OF_USERS, + IEEE80211_RADIOTAP_EHT_DATA7_NUM_OF_NON_OFDMA_USERS); + + iwl_mld_eht_decode_user_ru(phy_data, eht); + + iwl_mld_eht_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU)); +} - if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT || - info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB) - iwl_mld_decode_eht_ext_tb(mld, phy_data, rx_status, eht, usig); +static void iwl_mld_decode_eht_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht *eht) +{ + u32 he_type = phy_data->rate_n_flags & RATE_MCS_HE_TYPE_MSK; - if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT || - info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU) - iwl_mld_decode_eht_ext_mu(mld, phy_data, rx_status, eht, usig); + if (he_type == RATE_MCS_HE_TYPE_TRIG) + iwl_mld_decode_eht_tb(phy_data, rx_status, eht); + else + iwl_mld_decode_eht_non_tb(phy_data, rx_status, eht); } static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data, - int queue) + struct iwl_mld_rx_phy_data *phy_data) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_eht *eht; - struct ieee80211_radiotap_eht_usig *usig; size_t eht_len = sizeof(*eht); - u32 rate_n_flags = phy_data->rate_n_flags; u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; /* EHT and HE have the same values for LTF */ u8 ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN; - u16 phy_info = phy_data->phy_info; - u32 bw; /* u32 for 1 user_info */ if (phy_data->with_data) @@ -1065,50 +1106,7 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, eht = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len); - usig = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG, - sizeof(*usig)); rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; - usig->common |= - cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN); - - /* specific handling for 320MHz */ - bw = u32_get_bits(rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK); - if (bw == RATE_MCS_CHAN_WIDTH_320_VAL) - bw += le32_get_bits(phy_data->data0, - IWL_RX_PHY_DATA0_EHT_BW320_SLOT); - - usig->common |= cpu_to_le32 - (FIELD_PREP(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW, bw)); - - /* report the AMPDU-EOF bit on single frames */ - if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { - rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & - cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && - (phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) { - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (phy_data->data0 & - cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) - iwl_mld_decode_eht_phy_data(mld, phy_data, rx_status, eht, usig); - -#define CHECK_TYPE(F) \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ - (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS)) - - CHECK_TYPE(SU); - CHECK_TYPE(EXT_SU); - CHECK_TYPE(MU); - CHECK_TYPE(TRIG); switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { case 0: @@ -1144,20 +1142,18 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, if (ltf != IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN) { eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI); - eht->data[0] |= cpu_to_le32 - (FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_LTF, - ltf) | - FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_GI, - rx_status->eht.gi)); + eht->data[0] |= le32_encode_bits(ltf, + IEEE80211_RADIOTAP_EHT_DATA0_LTF) | + le32_encode_bits(rx_status->eht.gi, + IEEE80211_RADIOTAP_EHT_DATA0_GI); } if (!phy_data->with_data) { eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_NSS_S | IEEE80211_RADIOTAP_EHT_KNOWN_BEAMFORMED_S); - eht->data[7] |= - le32_encode_bits(le32_get_bits(phy_data->rx_vec[2], - RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK), - IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); + eht->data[7] |= LE32_DEC_ENC(phy_data->ntfy->sigs.eht.b1, + OFDM_RX_FRAME_EHT_NSTS, + IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); if (rate_n_flags & RATE_MCS_BF_MSK) eht->data[7] |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_DATA7_BEAMFORMED_S); @@ -1177,14 +1173,28 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, eht->user_info[0] |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_CODING); - eht->user_info[0] |= cpu_to_le32 - (FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS, - u32_get_bits(rate_n_flags, - RATE_VHT_MCS_RATE_CODE_MSK)) | - FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O, - u32_get_bits(rate_n_flags, - RATE_MCS_NSS_MSK))); + eht->user_info[0] |= + le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_VHT_MCS_RATE_CODE_MSK), + IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) | + le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_MCS_NSS_MSK), + IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O); } + + if (likely(!phy_data->ntfy)) + return; + + if (phy_data->with_data) { + eht->user_info[0] |= + cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) | + LE32_DEC_ENC(phy_data->ntfy->sigs.eht.user_id, + OFDM_RX_FRAME_EHT_USER_FIELD_ID, + IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID); + } + + iwl_mld_decode_eht_usig(phy_data, skb); + iwl_mld_decode_eht_phy_data(phy_data, rx_status, eht); } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1207,8 +1217,9 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, radiotap->oui[0] = 0xf6; radiotap->oui[1] = 0x54; radiotap->oui[2] = 0x25; - /* radiotap sniffer config sub-namespace */ + /* Intel OUI default radiotap subtype */ radiotap->oui_subtype = 1; + /* Sniffer config element type */ radiotap->vendor_type = 0; /* fill the data now */ @@ -1219,34 +1230,58 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, } #endif -/* Note: hdr can be NULL */ -static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, - struct ieee80211_hdr *hdr, - struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data, - int queue) +static void iwl_mld_add_rtap_sniffer_phy_data(struct iwl_mld *mld, + struct sk_buff *skb, + struct iwl_rx_phy_air_sniffer_ntfy *ntfy) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - u32 format = phy_data->rate_n_flags & RATE_MCS_MOD_TYPE_MSK; - u32 rate_n_flags = phy_data->rate_n_flags; - u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); - bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; + struct ieee80211_radiotap_vendor_content *radiotap; + const u16 vendor_data_len = sizeof(*ntfy); - phy_data->info_type = IWL_RX_PHY_INFO_TYPE_NONE; + radiotap = + iwl_mld_radiotap_put_tlv(skb, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE, + sizeof(*radiotap) + vendor_data_len); - if (phy_data->phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) - phy_data->info_type = - le32_get_bits(phy_data->data1, - IWL_RX_PHY_DATA1_INFO_TYPE_MASK); + /* Intel OUI */ + radiotap->oui[0] = 0xf6; + radiotap->oui[1] = 0x54; + radiotap->oui[2] = 0x25; + /* Intel OUI default radiotap subtype */ + radiotap->oui_subtype = 1; + /* PHY data element type */ + radiotap->vendor_type = cpu_to_le16(1); - /* set the preamble flag if appropriate */ - if (format == RATE_MCS_MOD_TYPE_CCK && - phy_data->phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) - rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + /* fill the data now */ + memcpy(radiotap->data, ntfy, vendor_data_len); - iwl_mld_fill_signal(mld, link_id, hdr, rx_status, phy_data); + rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; +} + +static void +iwl_mld_set_rx_nonlegacy_rate_info(u32 rate_n_flags, + struct ieee80211_rx_status *rx_status) +{ + u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); + + /* NSS may be overridden by PHY ntfy with full value */ + rx_status->nss = u32_get_bits(rate_n_flags, RATE_MCS_NSS_MSK) + 1; + rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK; + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + if (rate_n_flags & RATE_MCS_LDPC_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_LDPC; +} + +static void iwl_mld_set_rx_rate(struct iwl_mld *mld, + struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status) +{ + u32 rate_n_flags = phy_data->rate_n_flags; + u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); + u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; + bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; - /* This may be overridden by iwl_mld_rx_he() to HE_RU */ + /* bandwidth may be overridden to RU by PHY ntfy */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; @@ -1264,17 +1299,93 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, break; } - /* must be before L-SIG data */ - if (format == RATE_MCS_MOD_TYPE_HE) - iwl_mld_rx_he(mld, skb, phy_data, queue); + switch (format) { + case RATE_MCS_MOD_TYPE_CCK: + if (phy_data->phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) + rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + fallthrough; + case RATE_MCS_MOD_TYPE_LEGACY_OFDM: { + int rate = + iwl_mld_legacy_hw_idx_to_mac80211_idx(rate_n_flags, + rx_status->band); - iwl_mld_decode_lsig(skb, phy_data); + /* override BW - it could be DUP and indicate the wrong BW */ + rx_status->bw = RATE_INFO_BW_20; + + /* valid rate */ + if (rate >= 0 && rate <= 0xFF) { + rx_status->rate_idx = rate; + break; + } + + /* invalid rate */ + rx_status->rate_idx = 0; + + /* + * In monitor mode we can see CCK frames on 5 or 6 GHz, usually + * just the (possibly malformed) PHY header by accident, since + * the decoder doesn't seem to turn off CCK. We cannot correctly + * encode the rate to mac80211 (and therefore not in radiotap) + * since we give the per-band index which doesn't cover those + * rates. + */ + if (!mld->monitor.on && net_ratelimit()) + IWL_ERR(mld, "invalid rate_n_flags=0x%x, band=%d\n", + rate_n_flags, rx_status->band); + break; + } + case RATE_MCS_MOD_TYPE_HT: + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags); + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + break; + case RATE_MCS_MOD_TYPE_VHT: + rx_status->encoding = RX_ENC_VHT; + iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); + break; + case RATE_MCS_MOD_TYPE_HE: + rx_status->encoding = RX_ENC_HE; + rx_status->he_dcm = + !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); + iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); + break; + case RATE_MCS_MOD_TYPE_EHT: + rx_status->encoding = RX_ENC_EHT; + iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); + break; + default: + WARN_ON_ONCE(1); + } + + if (format != RATE_MCS_MOD_TYPE_CCK && is_sgi) + rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; +} + +/* Note: hdr can be NULL */ +static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, + struct ieee80211_hdr *hdr, + struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u32 rate_n_flags = phy_data->rate_n_flags; + u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; + + iwl_mld_fill_signal(mld, link_id, hdr, rx_status, phy_data); rx_status->device_timestamp = phy_data->gp2_on_air_rise; - /* using TLV format and must be after all fixed len fields */ + iwl_mld_set_rx_rate(mld, phy_data, rx_status); + + /* must be before L-SIG data (radiotap field order) */ + if (format == RATE_MCS_MOD_TYPE_HE) + iwl_mld_rx_he(skb, phy_data); + + iwl_mld_decode_lsig(skb, phy_data); + + /* TLVs - must be after radiotap fixed fields */ if (format == RATE_MCS_MOD_TYPE_EHT) - iwl_mld_rx_eht(mld, skb, phy_data, queue); + iwl_mld_rx_eht(mld, skb, phy_data); #ifdef CONFIG_IWLWIFI_DEBUGFS if (unlikely(mld->monitor.on)) { @@ -1282,9 +1393,9 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, if (mld->monitor.ptp_time) { u64 adj_time = - iwl_mld_ptp_get_adj_time(mld, - phy_data->gp2_on_air_rise * - NSEC_PER_USEC); + iwl_mld_ptp_get_adj_time(mld, + phy_data->gp2_on_air_rise * + NSEC_PER_USEC); rx_status->mactime = div64_u64(adj_time, NSEC_PER_USEC); rx_status->flag |= RX_FLAG_MACTIME_IS_RTAP_TS64; @@ -1293,56 +1404,8 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, } #endif - if (format != RATE_MCS_MOD_TYPE_CCK && is_sgi) - rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - - if (rate_n_flags & RATE_MCS_LDPC_MSK) - rx_status->enc_flags |= RX_ENC_FLAG_LDPC; - - switch (format) { - case RATE_MCS_MOD_TYPE_HT: - rx_status->encoding = RX_ENC_HT; - rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags); - rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; - break; - case RATE_MCS_MOD_TYPE_VHT: - case RATE_MCS_MOD_TYPE_HE: - case RATE_MCS_MOD_TYPE_EHT: - if (format == RATE_MCS_MOD_TYPE_VHT) { - rx_status->encoding = RX_ENC_VHT; - } else if (format == RATE_MCS_MOD_TYPE_HE) { - rx_status->encoding = RX_ENC_HE; - rx_status->he_dcm = - !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); - } else if (format == RATE_MCS_MOD_TYPE_EHT) { - rx_status->encoding = RX_ENC_EHT; - } - - rx_status->nss = u32_get_bits(rate_n_flags, - RATE_MCS_NSS_MSK) + 1; - rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK; - rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; - break; - default: { - int rate = - iwl_mld_legacy_hw_idx_to_mac80211_idx(rate_n_flags, - rx_status->band); - - /* valid rate */ - if (rate >= 0 && rate <= 0xFF) { - rx_status->rate_idx = rate; - break; - } - - /* invalid rate */ - rx_status->rate_idx = 0; - - if (net_ratelimit()) - IWL_ERR(mld, "invalid rate_n_flags=0x%x, band=%d\n", - rate_n_flags, rx_status->band); - break; - } - } + if (phy_data->ntfy) + iwl_mld_add_rtap_sniffer_phy_data(mld, skb, phy_data->ntfy); } /* iwl_mld_create_skb adds the rxb to a new skb */ @@ -1763,13 +1826,36 @@ static int iwl_mld_rx_crypto(struct iwl_mld *mld, return 0; } -static void iwl_mld_rx_update_ampdu_ref(struct iwl_mld *mld, - struct iwl_mld_rx_phy_data *phy_data, - struct ieee80211_rx_status *rx_status) +static void iwl_mld_rx_update_ampdu_data(struct iwl_mld *mld, + struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status) { + u32 format = phy_data->rate_n_flags & RATE_MCS_MOD_TYPE_MSK; bool toggle_bit = phy_data->phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; + switch (format) { + case RATE_MCS_MOD_TYPE_CCK: + case RATE_MCS_MOD_TYPE_LEGACY_OFDM: + /* no aggregation possible */ + return; + case RATE_MCS_MOD_TYPE_HT: + case RATE_MCS_MOD_TYPE_VHT: + /* single frames are not A-MPDU format */ + if (!(phy_data->phy_info & IWL_RX_MPDU_PHY_AMPDU)) + return; + break; + default: + /* HE/EHT/UHR have A-MPDU format for single frames */ + if (!(phy_data->phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->phy_info & IWL_RX_MPDU_PHY_EOF_INDICATION) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; + return; + } + } + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; /* Toggle is switched whenever new aggregation starts. Make * sure ampdu_reference is never 0 so we can later use it to @@ -1781,6 +1867,11 @@ static void iwl_mld_rx_update_ampdu_ref(struct iwl_mld *mld, mld->monitor.ampdu_ref++; mld->monitor.ampdu_toggle = toggle_bit; phy_data->first_subframe = true; + + /* report EOF bit on the first subframe */ + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->phy_info & IWL_RX_MPDU_PHY_EOF_INDICATION) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } rx_status->ampdu_reference = mld->monitor.ampdu_ref; } @@ -1810,6 +1901,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, u32 mpdu_len; enum iwl_mld_reorder_result reorder_res; struct ieee80211_rx_status *rx_status; + unsigned int alloc_size = 128; if (unlikely(mld->fw_status.in_hw_restart)) return; @@ -1824,10 +1916,17 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, "FW lied about packet len (%d)\n", pkt_len)) return; + iwl_mld_fill_phy_data_from_mpdu(mld, mpdu_desc, &phy_data); + /* Don't use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. + * + * For monitor mode we need more space to include the full PHY + * notification data. */ - skb = alloc_skb(128, GFP_ATOMIC); + if (unlikely(mld->monitor.on) && phy_data.ntfy) + alloc_size += sizeof(struct iwl_rx_phy_air_sniffer_ntfy); + skb = alloc_skb(alloc_size, GFP_ATOMIC); if (!skb) { IWL_ERR(mld, "alloc_skb failed\n"); return; @@ -1835,8 +1934,6 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, hdr = (void *)(pkt->data + mpdu_desc_size); - iwl_mld_fill_phy_data(mld, mpdu_desc, &phy_data); - if (mpdu_desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { /* If the device inserted padding it means that (it thought) * the 802.11 header wasn't a multiple of 4 bytes long. In @@ -1861,9 +1958,8 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, if (drop) goto drop; - /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_data.phy_info & IWL_RX_MPDU_PHY_AMPDU)) - iwl_mld_rx_update_ampdu_ref(mld, &phy_data, rx_status); + if (unlikely(mld->monitor.on)) + iwl_mld_rx_update_ampdu_data(mld, &phy_data, rx_status); /* Keep packets with CRC errors (and with overrun) for monitor mode * (otherwise the firmware discards them) but mark them as bad. @@ -1897,7 +1993,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, link_id = u8_get_bits(mpdu_desc->mac_phy_band, IWL_RX_MPDU_MAC_PHY_BAND_LINK_MASK); - iwl_mld_rx_fill_status(mld, link_id, hdr, skb, &phy_data, queue); + iwl_mld_rx_fill_status(mld, link_id, hdr, skb, &phy_data); if (iwl_mld_rx_crypto(mld, sta, hdr, rx_status, mpdu_desc, queue, le32_to_cpu(pkt->len_n_flags), &crypto_len)) @@ -2031,87 +2127,65 @@ void iwl_mld_handle_rx_queues_sync_notif(struct iwl_mld *mld, wake_up(&mld->rxq_sync.waitq); } -void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, - struct iwl_rx_packet *pkt, int queue) +static void iwl_mld_no_data_rx(struct iwl_mld *mld, + struct napi_struct *napi, + struct iwl_rx_phy_air_sniffer_ntfy *ntfy) { - struct iwl_rx_no_data_ver_3 *desc; - struct iwl_mld_rx_phy_data phy_data; struct ieee80211_rx_status *rx_status; + struct iwl_mld_rx_phy_data phy_data = { + .ntfy = ntfy, + .phy_info = 0, /* short preamble set below */ + .rate_n_flags = le32_to_cpu(ntfy->rate), + .gp2_on_air_rise = le32_to_cpu(ntfy->on_air_rise_time), + .energy_a = ntfy->rssi_a, + .energy_b = ntfy->rssi_b, + }; + u32 format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; struct sk_buff *skb; - u32 format, rssi; - u8 channel; - - if (unlikely(mld->fw_status.in_hw_restart)) - return; - - if (IWL_FW_CHECK(mld, iwl_rx_packet_payload_len(pkt) < sizeof(*desc), - "Bad RX_NO_DATA_NOTIF size (%d)\n", - iwl_rx_packet_payload_len(pkt))) - return; - - desc = (void *)pkt->data; - - rssi = le32_to_cpu(desc->rssi); - channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK); - - phy_data.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK); - phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK); - phy_data.data0 = desc->phy_info[0]; - phy_data.data1 = desc->phy_info[1]; - phy_data.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD; - phy_data.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time); - phy_data.rate_n_flags = iwl_v3_rate_from_v2_v3(desc->rate, - mld->fw_rates_ver_3); - phy_data.with_data = false; - - BUILD_BUG_ON(sizeof(phy_data.rx_vec) != sizeof(desc->rx_vec)); - memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec)); - format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; - - /* Don't use dev_alloc_skb(), we'll have enough headroom once - * ieee80211_hdr pulled. - */ - skb = alloc_skb(128, GFP_ATOMIC); - if (!skb) { - IWL_ERR(mld, "alloc_skb failed\n"); + skb = alloc_skb(128 + sizeof(struct iwl_rx_phy_air_sniffer_ntfy), + GFP_ATOMIC); + if (!skb) return; - } rx_status = IEEE80211_SKB_RXCB(skb); /* 0-length PSDU */ rx_status->flag |= RX_FLAG_NO_PSDU; - /* mark as failed PLCP on any errors to skip checks in mac80211 */ - if (le32_get_bits(desc->info, RX_NO_DATA_INFO_ERR_MSK) != - RX_NO_DATA_INFO_ERR_NONE) - rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; - - switch (le32_get_bits(desc->info, RX_NO_DATA_INFO_TYPE_MSK)) { - case RX_NO_DATA_INFO_TYPE_NDP: + switch (ntfy->status) { + case IWL_SNIF_STAT_PLCP_RX_OK: + /* we only get here with sounding PPDUs */ rx_status->zero_length_psdu_type = IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; break; - case RX_NO_DATA_INFO_TYPE_MU_UNMATCHED: - case RX_NO_DATA_INFO_TYPE_TB_UNMATCHED: + case IWL_SNIF_STAT_AID_NOT_FOR_US: rx_status->zero_length_psdu_type = IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED; break; + case IWL_SNIF_STAT_PLCP_RX_LSIG_ERR: + case IWL_SNIF_STAT_PLCP_RX_SIGA_ERR: + case IWL_SNIF_STAT_PLCP_RX_SIGB_ERR: + case IWL_SNIF_STAT_UNKNOWN_ERROR: default: + rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; + fallthrough; + case IWL_SNIF_STAT_UNEXPECTED_TB: + case IWL_SNIF_STAT_UNSUPPORTED_RATE: rx_status->zero_length_psdu_type = IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR; - break; + /* we could include the real reason in a vendor TLV */ } - rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : - NL80211_BAND_2GHZ; + if (format == RATE_MCS_MOD_TYPE_CCK && + ntfy->legacy_sig.cck & cpu_to_le32(CCK_CRFR_SHORT_PREAMBLE)) + phy_data.phy_info |= IWL_RX_MPDU_PHY_SHORT_PREAMBLE; - rx_status->freq = ieee80211_channel_to_frequency(channel, - rx_status->band); + iwl_mld_fill_rx_status_band_freq(IEEE80211_SKB_RXCB(skb), + ntfy->band, ntfy->channel); /* link ID is ignored for NULL header */ - iwl_mld_rx_fill_status(mld, -1, NULL, skb, &phy_data, queue); + iwl_mld_rx_fill_status(mld, -1, NULL, skb, &phy_data); /* No more radiotap info should be added after this point. * Mark it as mac header for upper layers to know where @@ -2119,29 +2193,72 @@ void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, */ skb_set_mac_header(skb, skb->len); - /* Override the nss from the rx_vec since the rate_n_flags has - * only 1 bit for the nss which gives a max of 2 ss but there - * may be up to 8 spatial streams. - */ - switch (format) { + /* pass the packet to mac80211 */ + rcu_read_lock(); + ieee80211_rx_napi(mld->hw, NULL, skb, napi); + rcu_read_unlock(); +} + +void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld, + struct napi_struct *napi, + struct iwl_rx_packet *pkt) +{ + struct iwl_rx_phy_air_sniffer_ntfy *ntfy = (void *)pkt->data; + bool is_ndp = false; + u32 he_type; + + if (IWL_FW_CHECK(mld, iwl_rx_packet_payload_len(pkt) < sizeof(*ntfy), + "invalid air sniffer notification size\n")) + return; + + /* check if there's an old one to release as errored */ + if (mld->monitor.phy.valid && !mld->monitor.phy.used) { + /* didn't capture data, so override status */ + mld->monitor.phy.data.status = IWL_SNIF_STAT_AID_NOT_FOR_US; + iwl_mld_no_data_rx(mld, napi, &mld->monitor.phy.data); + } + + /* old data is no longer valid now */ + mld->monitor.phy.valid = false; + + he_type = le32_to_cpu(ntfy->rate) & RATE_MCS_HE_TYPE_MSK; + + switch (le32_to_cpu(ntfy->rate) & RATE_MCS_MOD_TYPE_MSK) { + case RATE_MCS_MOD_TYPE_HT: + is_ndp = !le32_get_bits(ntfy->sigs.ht.a1, + OFDM_RX_FRAME_HT_LENGTH); + break; case RATE_MCS_MOD_TYPE_VHT: - rx_status->nss = - le32_get_bits(desc->rx_vec[0], - RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1; + is_ndp = le32_get_bits(ntfy->sigs.vht.a0, + OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM_VALID) && + !le32_get_bits(ntfy->sigs.vht.a0, + OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM); break; case RATE_MCS_MOD_TYPE_HE: - rx_status->nss = - le32_get_bits(desc->rx_vec[0], - RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + break; + is_ndp = le32_get_bits(ntfy->sigs.he.a3, + OFDM_RX_FRAME_HE_NUM_OF_DATA_SYM_VALID) && + !le32_get_bits(ntfy->sigs.he.a3, + OFDM_RX_FRAME_HE_NUM_OF_DATA_SYM); break; case RATE_MCS_MOD_TYPE_EHT: - rx_status->nss = - le32_get_bits(desc->rx_vec[2], - RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK) + 1; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + break; + is_ndp = le32_get_bits(ntfy->sigs.eht.sig2, + OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM_VALID) && + !le32_get_bits(ntfy->sigs.eht.sig2, + OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM); + break; } - /* pass the packet to mac80211 */ - rcu_read_lock(); - ieee80211_rx_napi(mld->hw, NULL, skb, napi); - rcu_read_unlock(); + if (ntfy->status != IWL_SNIF_STAT_PLCP_RX_OK || is_ndp) { + iwl_mld_no_data_rx(mld, napi, ntfy); + return; + } + + /* hang on to it for the RX_MPDU data packet(s) */ + mld->monitor.phy.data = *ntfy; + mld->monitor.phy.valid = true; + mld->monitor.phy.used = false; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.h b/drivers/net/wireless/intel/iwlwifi/mld/rx.h index 2beabd7e70b1..09dddbd40f55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.h @@ -66,7 +66,8 @@ void iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld, struct sk_buff *skb, int queue, struct ieee80211_sta *sta); -void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, - struct iwl_rx_packet *pkt, int queue); +void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld, + struct napi_struct *napi, + struct iwl_rx_packet *pkt); #endif /* __iwl_mld_agg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 5cdbfa29a202..61ecc33116cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -890,7 +890,7 @@ static void iwl_mld_count_mpdu(struct ieee80211_link_sta *link_sta, int queue, sizeof(queue_counter->per_link)); queue_counter->window_start_time = jiffies; - IWL_DEBUG_INFO(mld, "MPDU counters are cleared\n"); + IWL_DEBUG_EHT(mld, "MPDU counters are cleared\n"); } link_counter = &queue_counter->per_link[mld_link->fw_id]; |
