diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 5a4d04a8bd2cf..c9bf3d844acde 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -352,6 +352,9 @@ struct ath12k_link_vif { u16 num_stations; bool is_csa_in_progress; struct wiphy_work bcn_tx_work; + + bool set_wds_vdev_param; + bool nawds_enabled; }; struct ath12k_vif { @@ -491,6 +494,10 @@ struct ath12k_link_sta { /* link address similar to ieee80211_link_sta */ u8 addr[ETH_ALEN]; + u16 tcl_metadata; + u16 ast_hash; + u16 ast_idx; + /* the following are protected by ar->data_lock */ u32 changed; /* IEEE80211_RC_* */ u32 bw; @@ -526,7 +533,8 @@ struct ath12k_sta { u16 free_logical_link_idx_map; enum ieee80211_sta_state state; - u16 tcl_metadata; + + bool enable_4addr; }; #define ATH12K_HALF_20MHZ_BW 10 diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h index 20294ff095131..4c63232fba402 100644 --- a/drivers/net/wireless/ath/ath12k/dp_peer.h +++ b/drivers/net/wireless/ath/ath12k/dp_peer.h @@ -144,6 +144,8 @@ struct ath12k_dp_peer { struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS]; struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1]; struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1]; + + bool use_4addr; }; struct ath12k_dp_link_peer * diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index e54df61d6fa04..78d61f7a98ac4 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1095,7 +1095,8 @@ static void ath12k_get_dot11_hdr_from_rx_desc(struct ath12k_pdev_dp *dp_pdev, static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, enum hal_encrypt_type enctype, - struct hal_rx_desc_data *rx_info) + struct hal_rx_desc_data *rx_info, + enum ath12k_dp_rx_decap_type decap_type) { struct ieee80211_hdr *hdr; struct ethhdr *eth; @@ -1103,12 +1104,24 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev, u8 sa[ETH_ALEN]; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); struct ath12k_dp_rx_rfc1042_hdr rfc = {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}}; + struct ath12k_dp_rx_rfc1042_hdr *llc; eth = (struct ethhdr *)msdu->data; ether_addr_copy(da, eth->h_dest); ether_addr_copy(sa, eth->h_source); - rfc.snap_type = eth->h_proto; - skb_pull(msdu, sizeof(*eth)); + if (decap_type == DP_RX_DECAP_TYPE_8023) { + /* + * For 802.3 frames, eth->h_proto carries a length field, not + * an EtherType. The actual EtherType is in the LLC/SNAP header + * that follows the Ethernet header. + */ + llc = (struct ath12k_dp_rx_rfc1042_hdr *)(msdu->data + sizeof(*eth)); + rfc.snap_type = llc->snap_type; + skb_pull(msdu, sizeof(*eth) + sizeof(*llc)); + } else { + rfc.snap_type = eth->h_proto; + skb_pull(msdu, sizeof(*eth)); + } memcpy(skb_push(msdu, sizeof(rfc)), &rfc, sizeof(rfc)); ath12k_get_dot11_hdr_from_rx_desc(dp_pdev, msdu, rxcb, enctype, rx_info); @@ -1124,11 +1137,13 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev, void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, enum hal_encrypt_type enctype, bool decrypted, - struct hal_rx_desc_data *rx_info) + struct hal_rx_desc_data *rx_info, + struct ath12k_dp_peer *peer) { + enum ath12k_dp_rx_decap_type decap_type = rx_info->decap_type; struct ethhdr *ehdr; - switch (rx_info->decap_type) { + switch (decap_type) { case DP_RX_DECAP_TYPE_NATIVE_WIFI: ath12k_dp_rx_h_undecap_nwifi(dp_pdev, msdu, enctype, rx_info); break; @@ -1142,19 +1157,40 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu /* mac80211 allows fast path only for authorized STA */ if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { ATH12K_SKB_RXCB(msdu)->is_eapol = true; - ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info); + ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info, + decap_type); + break; + } + + if (peer && !peer->use_4addr && + rx_info->is_from_ds && rx_info->is_to_ds) { + ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info, + decap_type); break; } /* PN for mcast packets will be validated in mac80211; * remove eth header and add 802.11 header. */ - if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted) - ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info); + if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted) { + ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info, + decap_type); + break; + } + + rx_info->rx_status->flag |= RX_FLAG_8023; break; case DP_RX_DECAP_TYPE_8023: - /* TODO: Handle undecap for these formats */ - break; + /* + * Note that ethernet decap format indicates that the decapped + * packet is either Ethernet 2 (DIX) or 802.3 (uses SNAP/LLC). + */ + if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted) { + ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info, + decap_type); + break; + } + rx_info->rx_status->flag |= RX_FLAG_8023; } } EXPORT_SYMBOL(ath12k_dp_rx_h_undecap); @@ -1336,9 +1372,7 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc struct ath12k_dp_peer *peer; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); struct ieee80211_rx_status *status = rx_info->rx_status; - u8 decap = rx_info->decap_type; bool is_mcbc = rxcb->is_mcbc; - bool is_eapol = rxcb->is_eapol; peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id); @@ -1383,15 +1417,6 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc /* TODO: trace rx packet */ - /* PN for multicast packets are not validate in HW, - * so skip 802.3 rx path - * Also, fast_rx expects the STA to be authorized, hence - * eapol packets are sent in slow path. - */ - if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && - !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) - rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), pubsta, msdu, napi); } EXPORT_SYMBOL(ath12k_dp_rx_deliver_msdu); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index e1054d72bbda5..4541d5d4c5ae7 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -202,7 +202,8 @@ void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal, void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu, enum hal_encrypt_type enctype, bool decrypted, - struct hal_rx_desc_data *rx_info); + struct hal_rx_desc_data *rx_info, + struct ath12k_dp_peer *peer); void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struct *napi, struct sk_buff *msdu, struct hal_rx_desc_data *rx_info); diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 9bc548bb158d3..305d0410ac6fa 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -738,7 +738,9 @@ struct hal_rx_desc_data { addr2_present:1, is_mcbc:1, seq_ctl_valid:1, - fc_valid:1; + fc_valid:1, + is_to_ds:1, + is_from_ds:1; u16 msdu_len; u16 peer_id; u16 seq_no; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f5f72dafe8d81..cb965f001bed0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6582,6 +6582,79 @@ static int ath12k_mac_station_disassoc(struct ath12k *ar, return 0; } +static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahsta) +{ + struct ath12k_dp_link_peer *peer; + struct ath12k_link_vif *arvif; + struct ath12k_link_sta *arsta; + struct ath12k_vif *ahvif; + struct ath12k_dp *dp; + unsigned long links; + struct ath12k *ar; + u8 link_id; + int ret; + + links = ahsta->links_map; + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arsta = wiphy_dereference(wiphy, ahsta->link[link_id]); + if (!arsta) + continue; + + arvif = arsta->arvif; + ahvif = arvif->ahvif; + ar = arvif->ar; + + if (arvif->set_wds_vdev_param) + goto skip_nawds; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "setting USE_4ADDR for peer %pM\n", arsta->addr); + + ret = ath12k_wmi_set_peer_param(ar, arsta->addr, + arvif->vdev_id, + WMI_PEER_USE_4ADDR, + WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME); + if (ret) { + ath12k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n", + arsta->addr, ret); + return ret; + } + + if (ahvif->dp_vif.tx_encap_type != ATH12K_HW_TXRX_ETHERNET) + goto skip_nawds; + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_AP_ENABLE_NAWDS, + WDS_EXT_ENABLE); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d nawds parameter: %d\n", + arvif->vdev_id, ret); + return ret; + } + + arvif->nawds_enabled = true; + +skip_nawds: + dp = ath12k_ab_to_dp(ar->ab); + spin_lock_bh(&dp->dp_lock); + peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id, + arsta->addr); + if (peer && peer->dp_peer) { + peer->dp_peer->ucast_ra_only = true; + peer->dp_peer->use_4addr = true; + } else { + spin_unlock_bh(&dp->dp_lock); + ath12k_warn(ar->ab, "failed to find DP peer for %pM\n", + arsta->addr); + return -ENOENT; + } + + spin_unlock_bh(&dp->dp_lock); + } + + return 0; +} + static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) { struct ieee80211_link_sta *link_sta; @@ -7073,10 +7146,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, ath12k_dbg(ab, ATH12K_DBG_MAC, "Added peer: %pM for VDEV: %d\n", arsta->addr, arvif->vdev_id); - /* ------------------------------ - FORCE WDS / 4-ADDRESS MODE - ----------------------------- */ - // if (ieee80211_vif_is_mesh(vif)) { + if (ieee80211_vif_is_mesh(vif)) { ret = ath12k_wmi_set_peer_param(ar, arsta->addr, arvif->vdev_id, WMI_PEER_USE_4ADDR, 1); @@ -7085,7 +7155,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, arsta->addr, ret); goto free_peer; } - //} + } ret = ath12k_dp_peer_setup(ar, arvif->vdev_id, arsta->addr); if (ret) { @@ -7894,6 +7964,28 @@ int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ath12k_mac_op_sta_set_txpwr); +void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enabled) +{ + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + + lockdep_assert_wiphy(hw->wiphy); + + /* + * 4-address mode disabled option is available only for station + * interface from mac80211, and we have wds_vdev_param for station + * interface and target will not allow to disable the wds_vdev_param + * during run time. So, add support only for enable case, for + * disable case station interface needs to be reconnect. + */ + if (enabled && !ahsta->enable_4addr) { + if (!ath12k_mac_sta_set_4addr(hw->wiphy, ahsta)) + ahsta->enable_4addr = true; + } +} +EXPORT_SYMBOL(ath12k_mac_op_sta_set_4addr); + void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, @@ -10033,12 +10125,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif) vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED | IEEE80211_OFFLOAD_DECAP_ENABLED); - if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) + if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) { ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_ETHERNET; - else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) + vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; + } else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_RAW; - else + } else { ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI; + } ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, ahvif->dp_vif.tx_encap_type); @@ -10248,6 +10342,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) struct ieee80211_hw *hw = ah->hw; struct ath12k_vif *ahvif = arvif->ahvif; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); struct ath12k_wmi_vdev_create_arg vdev_arg = {}; struct ath12k_wmi_peer_create_arg peer_param = {}; struct ieee80211_bss_conf *link_conf = NULL; @@ -10416,6 +10511,26 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) goto err_peer_del; } + /* + * There could be race condition in firmware for the station + * interface between enabling 4-address peer WMI param and + * sending 4-address frame (NULL or EAPOL via TCL). + * Make the station as WDS while bringup itself + * to avoid the race condition + */ + if (vif->type == NL80211_IFTYPE_STATION && + (wdev && wdev->use_4addr)) { + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_WDS, + 1); + if (ret) { + ath12k_warn(ar->ab, "failed to set WDS vdev param: %d\n", + ret); + goto err_peer_del; + } + arvif->set_wds_vdev_param = true; + } + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) && ahvif->vdev_type == WMI_VDEV_TYPE_STA && ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 7b50c59763840..aba98afd4365c 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -255,6 +255,9 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enabled); void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index e7eea27cd8daf..3db1ee6a1c208 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -216,16 +216,15 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, if (sta) { ahsta = ath12k_sta_to_ahsta(sta); - ahsta->tcl_metadata |= u32_encode_bits(0, HTT_TCL_META_DATA_TYPE) | - u32_encode_bits(peer->peer_id, - HTT_TCL_META_DATA_PEER_ID); - - /* set HTT extension valid bit to 0 by default */ - ahsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT; - arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy, ahsta->link[link_id]); - + /* TODO: Split DP related field usage to DP peer structure */ + arsta->tcl_metadata = u16_encode_bits(0, HTT_TCL_META_DATA_TYPE) | + u16_encode_bits(peer->peer_id, + HTT_TCL_META_DATA_PEER_ID) | + u16_encode_bits(0, HTT_TCL_META_DATA_VALID_HTT); + arsta->ast_hash = peer->ast_hash; + arsta->ast_idx = peer->hw_peer_id; peer->link_id = arsta->link_id; /* Fill ML info into created peer */ @@ -256,6 +255,9 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, ar->hw_link_id); } + if (vif->type == NL80211_IFTYPE_AP && peer->dp_peer) + peer->dp_peer->ucast_ra_only = true; + return ret; } diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c index ddc8ec64748dc..c4211169cb7bd 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c @@ -323,9 +323,9 @@ static void ath12k_wifi7_dp_rx_h_csum_offload(struct sk_buff *msdu, CHECKSUM_NONE : CHECKSUM_UNNECESSARY; } -static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev, - struct sk_buff *msdu, - struct hal_rx_desc_data *rx_info) +static int ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev, + struct sk_buff *msdu, + struct hal_rx_desc_data *rx_info) { struct ath12k_skb_rxcb *rxcb; enum hal_encrypt_type enctype; @@ -347,6 +347,18 @@ static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev, peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id); if (peer) { + /* + * Drop the 3-address multicast packet from 4-address + * peer To avoid receiving the duplicate multicast packet + * Specifically from AP interface in 3-address format + */ + if (rxcb->is_mcbc && + rx_info->decap_type == DP_RX_DECAP_TYPE_ETHERNET2_DIX) { + if (peer->use_4addr && + !(rx_info->is_from_ds && rx_info->is_to_ds)) + return -EINVAL; + } + /* resetting mcbc bit because mcbc packets are unicast * packets only for AP as STA sends unicast packets. */ @@ -387,15 +399,18 @@ static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev, } ath12k_wifi7_dp_rx_h_csum_offload(msdu, rx_info); - ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info); + ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info, + peer); if (!is_decrypted || rx_info->is_mcbc) - return; + return 0; if (rx_info->decap_type != DP_RX_DECAP_TYPE_ETHERNET2_DIX) { hdr = (void *)msdu->data; hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); } + + return 0; } static int ath12k_wifi7_dp_rx_msdu_coalesce(struct ath12k_hal *hal, @@ -557,7 +572,9 @@ static int ath12k_wifi7_dp_rx_process_msdu(struct ath12k_pdev_dp *dp_pdev, } ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); - ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info); + ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info); + if (ret) + goto free_out; rx_info->rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; @@ -1094,7 +1111,7 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev, ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, true, - rx_info); + rx_info, NULL); ieee80211_rx(ath12k_pdev_dp_to_hw(dp_pdev), msdu); return -EINVAL; } @@ -1650,6 +1667,7 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev, u8 l3pad_bytes = rx_info->l3_pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); u32 hal_rx_desc_sz = dp->ab->hal.hal_desc_sz; + int ret; if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) { /* First buffer will be freed by the caller, so deduct it's length */ @@ -1696,7 +1714,9 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev, return -EINVAL; ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); - ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info); + ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info); + if (ret) + return ret; rxcb->tid = rx_info->tid; @@ -1742,7 +1762,57 @@ static bool ath12k_wifi7_dp_rx_h_tkip_mic_err(struct ath12k_pdev_dp *dp_pdev, RX_FLAG_DECRYPTED); ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, false, - rx_info); + rx_info, NULL); + return false; +} + +static bool ath12k_wifi7_dp_rx_h_unauth_wds_err(struct ath12k_pdev_dp *dp_pdev, + struct sk_buff *msdu, + struct hal_rx_desc_data *rx_info) +{ + struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); + struct ath12k_dp *dp = dp_pdev->dp; + u32 hdr_len, hal_rx_desc_sz = dp->ab->hal.hal_desc_sz; + u8 l3pad_bytes = rx_info->l3_pad_bytes; + struct ath12k_dp_rx_rfc1042_hdr *llc; + u16 msdu_len = rx_info->msdu_len; + struct ath12k_dp_peer *peer; + struct ieee80211_hdr *hdr; + int ret; + + guard(rcu)(); + peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id); + if (!peer) { + ath12k_dbg(dp->ab, ATH12K_DBG_DATA, + "failed to find the peer to process unauth wds err handling peer_id %d\n", + rxcb->peer_id); + return true; + } + + if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) + return true; + + skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); + skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); + + if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu, + rx_info))) + return true; + + ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); + + ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info); + if (ret) + return true; + + rxcb->tid = rx_info->tid; + + hdr = (struct ieee80211_hdr *)msdu->data; + hdr_len = ieee80211_hdrlen(hdr->frame_control); + llc = (struct ath12k_dp_rx_rfc1042_hdr *)(msdu->data + hdr_len); + if (llc->snap_type != cpu_to_be16(ETH_P_PAE)) + return true; + return false; } @@ -1757,6 +1827,9 @@ static bool ath12k_wifi7_dp_rx_h_rxdma_err(struct ath12k_pdev_dp *dp_pdev, dp->device_stats.rxdma_error[rxcb->err_code]++; switch (rxcb->err_code) { + case HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR: + drop = ath12k_wifi7_dp_rx_h_unauth_wds_err(dp_pdev, msdu, rx_info); + break; case HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR: case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR: if (rx_info->err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) { diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c index e29c6b8e8e6c8..d2749de445534 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c @@ -57,10 +57,12 @@ static int ath12k_wifi7_dp_prepare_htt_metadata(struct sk_buff *skb) return 0; } +#define ATH12K_AST_HASH_MASK 0xF + /* TODO: Remove the export once this file is built with wifi7 ko */ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif, - struct ath12k_sta *ahsta, struct sk_buff *skb, bool gsn_valid, int mcbc_gsn, - bool is_mcast) + struct ath12k_link_sta *arsta, struct sk_buff *skb, + bool gsn_valid, int mcbc_gsn, bool is_mcast) { struct ath12k_dp *dp = dp_pdev->dp; struct ath12k_hal *hal = dp->hal; @@ -78,6 +80,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a struct ath12k_dp_vif *dp_vif = &ahvif->dp_vif; struct ath12k_dp_link_vif *dp_link_vif; struct dp_tx_ring *tx_ring; + struct ethhdr *eth = NULL; u8 pool_id; u8 hal_ring_id; int ret; @@ -96,6 +99,9 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a !ieee80211_is_data(hdr->frame_control)) return -EOPNOTSUPP; + if (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) + eth = (struct ethhdr *)skb->data; + pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1); /* Let the default ring selection be based on current processor @@ -123,13 +129,19 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, arvif->link_id); ti.bank_id = dp_link_vif->bank_id; + ti.meta_data_flags = dp_link_vif->tcl_metadata; + ti.bss_ast_hash = dp_link_vif->ast_hash; + ti.bss_ast_idx = dp_link_vif->ast_idx; - if (ieee80211_has_a4(hdr->frame_control) && - is_multicast_ether_addr(hdr->addr3) && ahsta) { - ti.meta_data_flags = ahsta->tcl_metadata; + if (eth && is_multicast_ether_addr(eth->h_dest) && arsta) { + ti.meta_data_flags = arsta->tcl_metadata; + ti.bss_ast_hash = arsta->ast_hash & ATH12K_AST_HASH_MASK; + ti.bss_ast_idx = arsta->ast_idx; + ti.lookup_override = true; + } else if (!eth && ieee80211_has_a4(hdr->frame_control) && + is_multicast_ether_addr(hdr->addr3) && arsta) { + ti.meta_data_flags = arsta->tcl_metadata; ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW); - } else { - ti.meta_data_flags = dp_link_vif->tcl_metadata; } if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && @@ -147,7 +159,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a msdu_ext_desc = true; } - if (gsn_valid) { + if (gsn_valid && !ti.lookup_override) { /* Reset and Initialize meta_data_flags with Global Sequence * Number (GSN) info. */ @@ -155,6 +167,14 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a u32_encode_bits(HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM, HTT_TCL_META_DATA_TYPE) | u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM); + + /* + * Since NAWDS enabled for this vdev firmware expects + * this flag to be set for sending 3-address multicast frame. + */ + ti.meta_data_flags |= + u32_encode_bits(arvif->nawds_enabled, + HTT_TCL_META_DATA_GLOBAL_SEQ_HOST_INSPECTED); } ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb); @@ -165,11 +185,13 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a ti.lmac_id = dp_link_vif->lmac_id; ti.vdev_id = dp_link_vif->vdev_id; - if (gsn_valid) + + if (gsn_valid && !ti.lookup_override) ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID; + else if (arvif->nawds_enabled && is_mcast && !ti.lookup_override) + ti.meta_data_flags |= + u32_encode_bits(1, HTT_TCL_META_DATA_HOST_INSPECTED_MISSION); - ti.bss_ast_hash = dp_link_vif->ast_hash; - ti.bss_ast_idx = dp_link_vif->ast_idx; ti.dscp_tid_tbl_idx = 0; if (skb->ip_summed == CHECKSUM_PARTIAL && diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h index a3fe4e7cbfdff..86bc813878c07 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h @@ -8,8 +8,8 @@ #define ATH12K_DP_TX_WIFI7_H int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif, - struct ath12k_sta *ahsta, struct sk_buff *skb, bool gsn_valid, int mcbc_gsn, - bool is_mcast); + struct ath12k_link_sta *arsta, struct sk_buff *skb, + bool gsn_valid, int mcbc_gsn, bool is_mcast); void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id); u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_link_vif *arvif); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c index 1eefb931a853e..8cebb229ebed8 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c @@ -184,6 +184,20 @@ static u8 ath12k_hal_rx_desc_get_l3_pad_bytes_qcc2072(struct hal_rx_desc *desc) RX_MSDU_END_INFO5_L3_HDR_PADDING); } +static inline +u8 ath12k_wifi7_hal_rx_h_from_ds_qcc2072(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_FROM_DS); +} + +static inline +u8 ath12k_wifi7_hal_rx_h_to_ds_qcc2072(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_TO_DS); +} + static u32 ath12k_hal_rx_desc_get_mpdu_start_tag_qcc2072(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.qcc2072.mpdu_start_tag, @@ -397,6 +411,8 @@ static void ath12k_hal_extract_rx_desc_data_qcc2072(struct hal_rx_desc_data *rx_ rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcc2072(rx_desc); rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcc2072(ldesc); rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcc2072(rx_desc); + rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_qcc2072(rx_desc); + rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_qcc2072(rx_desc); rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_qcc2072(rx_desc); rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_qcc2072(rx_desc); rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_qcc2072(rx_desc); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c index 41c918eb17673..f10ab7fc1d660 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c @@ -611,6 +611,20 @@ u8 ath12k_hal_rx_desc_get_mpdu_tid_qcn9274(struct hal_rx_desc *desc) RX_MSDU_END_INFO5_TID); } +static inline +u8 ath12k_wifi7_hal_rx_h_from_ds_qcn9274(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_FROM_DS); +} + +static inline +u8 ath12k_wifi7_hal_rx_h_to_ds_qcn9274(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_TO_DS); +} + static inline u16 ath12k_hal_rx_desc_get_mpdu_peer_id_qcn9274(struct hal_rx_desc *desc) { @@ -826,6 +840,8 @@ void ath12k_hal_extract_rx_desc_data_qcn9274(struct hal_rx_desc_data *rx_desc_da rx_desc_data->seq_ctl_valid = ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_qcn9274(rx_desc); rx_desc_data->fc_valid = ath12k_hal_rx_desc_get_mpdu_fc_valid_qcn9274(rx_desc); + rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_qcn9274(rx_desc); + rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_qcn9274(rx_desc); rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcn9274(rx_desc); rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcn9274(ldesc); rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcn9274(rx_desc); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c index 02d3cadf03fea..eeabe9db776eb 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c @@ -59,7 +59,9 @@ void ath12k_wifi7_hal_tx_cmd_desc_setup(struct ath12k_base *ab, le32_encode_bits(ti->lmac_id, HAL_TCL_DATA_CMD_INFO3_PMAC_ID) | le32_encode_bits(ti->vdev_id, HAL_TCL_DATA_CMD_INFO3_VDEV_ID); - tcl_cmd->info4 = le32_encode_bits(ti->bss_ast_idx, + tcl_cmd->info4 = le32_encode_bits(ti->lookup_override, + HAL_TCL_DATA_CMD_INFO4_IDX_LOOKUP_OVERRIDE) | + le32_encode_bits(ti->bss_ast_idx, HAL_TCL_DATA_CMD_INFO4_SEARCH_INDEX) | le32_encode_bits(ti->bss_ast_hash, HAL_TCL_DATA_CMD_INFO4_CACHE_SET_NUM); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h index 9d2b1552c2f51..c548a0fbf1bba 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h @@ -34,6 +34,7 @@ struct hal_tx_info { u8 dscp_tid_tbl_idx; bool enable_mesh; int bank_id; + bool lookup_override; }; /* TODO: Check if the actual desc macros can be used instead */ diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c index e64e512cac7df..efbbc1cbd3e42 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c @@ -280,6 +280,20 @@ u8 ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(struct hal_rx_desc *desc) RX_MSDU_END_INFO5_L3_HDR_PADDING); } +static inline +u8 ath12k_wifi7_hal_rx_h_from_ds_wcn7850(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.wcn7850.msdu_end.info5, + RX_MSDU_END_INFO5_FROM_DS); +} + +static inline +u8 ath12k_wifi7_hal_rx_h_to_ds_wcn7850(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.wcn7850.msdu_end.info5, + RX_MSDU_END_INFO5_TO_DS); +} + static inline bool ath12k_hal_rx_desc_encrypt_valid_wcn7850(struct hal_rx_desc *desc) { @@ -599,6 +613,8 @@ void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_da rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_wcn7850(rx_desc); rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_wcn7850(ldesc); rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_wcn7850(rx_desc); + rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_wcn7850(rx_desc); + rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_wcn7850(rx_desc); rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_wcn7850(rx_desc); rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_wcn7850(rx_desc); rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_wcn7850(rx_desc); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c index 9ab4ddb9c287e..589116909c502 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c @@ -768,8 +768,9 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_sta *sta = control->sta; - struct ath12k_sta *ahsta = sta ? ath12k_sta_to_ahsta(sta) : NULL; + struct ath12k_link_sta *arsta = NULL; struct ath12k_link_vif *tmp_arvif; + struct ath12k_sta *ahsta = NULL; u32 info_flags = info->flags; struct sk_buff *msdu_copied; struct ath12k *ar, *tmp_ar; @@ -851,6 +852,12 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw, if (!(info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) is_mcast = is_multicast_ether_addr(hdr->addr1); + if (sta) { + ahsta = ath12k_sta_to_ahsta(control->sta); + if (ahsta && ahsta->enable_4addr) + arsta = rcu_dereference(ahsta->link[link_id]); + } + /* This is case only for P2P_GO */ if (vif->type == NL80211_IFTYPE_AP && vif->p2p) ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp); @@ -871,7 +878,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw, if (!vif->valid_links || !is_mcast || is_dvlan || (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) || test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) { - ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, ahsta, skb, false, 0, is_mcast); + ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast); if (unlikely(ret)) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); ieee80211_free_txskb(ar->ah->hw, skb); @@ -909,6 +916,11 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw, skb_cb->vif = vif; skb_cb->ar = tmp_ar; + if (ahsta && ahsta->enable_4addr) + arsta = rcu_dereference(ahsta->link[link_id]); + else + arsta = NULL; + /* For open mode, skip peer find logic */ if (unlikely(!ahvif->dp_vif.key_cipher)) goto skip_peer_find; @@ -940,7 +952,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw, spin_unlock_bh(&tmp_dp->dp_lock); skip_peer_find: - ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, NULL, + ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, arsta, msdu_copied, true, mcbc_gsn, is_mcast); if (unlikely(ret)) { if (ret == -ENOMEM) { @@ -985,6 +997,7 @@ static const struct ieee80211_ops ath12k_ops_wifi7 = { .sta_state = ath12k_mac_op_sta_state, .sta_set_txpwr = ath12k_mac_op_sta_set_txpwr, .link_sta_rc_update = ath12k_mac_op_link_sta_rc_update, + .sta_set_4addr = ath12k_mac_op_sta_set_4addr, .conf_tx = ath12k_mac_op_conf_tx, .set_antenna = ath12k_mac_op_set_antenna, .get_antenna = ath12k_mac_op_get_antenna, diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index be35c5476f239..58702903c797c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4067,7 +4067,12 @@ ath12k_wmi_copy_resource_config(struct ath12k_base *ab, cpu_to_le32(1 << WMI_RSRC_CFG_HOST_SVC_FLAG_REO_QREF_SUPPORT_BIT); wmi_cfg->ema_max_vap_cnt = cpu_to_le32(tg_cfg->ema_max_vap_cnt); wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period); - wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET); + wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET | + WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE); + + if (tg_cfg->is_wds_null_frame_supported) + wmi_cfg->flags2 |= + cpu_to_le32(WMI_RSRC_CFG_FLAGS2_WDS_NULL_FRAME_SUPPORT); } static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, @@ -4280,6 +4285,9 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab) ab->wmi_ab.svc_map)) arg.res_cfg.is_reg_cc_ext_event_supported = true; + if (test_bit(WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT, ab->wmi_ab.svc_map)) + arg.res_cfg.is_wds_null_frame_supported = true; + ab->hw_params->wmi_init(ab, &arg.res_cfg); ab->wow.wmi_conf_rx_decap_mode = arg.res_cfg.rx_decap_mode; @@ -7149,7 +7157,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) struct ath12k_wmi_mgmt_rx_arg rx_ev = {}; struct ath12k *ar; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_sta *pubsta = NULL; + struct ath12k_dp_link_peer *peer; struct ieee80211_hdr *hdr; + bool is_4addr_null_pkt; + struct ath12k_dp *dp; u16 fc; struct ieee80211_supported_band *sband; s32 noise_floor; @@ -7224,6 +7236,38 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control); + is_4addr_null_pkt = (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) && + ieee80211_has_a4(hdr->frame_control); + + /* + * Add check to drop frames other than 4-address NULL frame. Since + * firmware sends all NULL frames in this path (3-address and 4-address) + */ + if (ieee80211_is_data(hdr->frame_control) && !is_4addr_null_pkt) { + dev_kfree_skb(skb); + goto exit; + } + + if (is_4addr_null_pkt) { + dp = ath12k_ab_to_dp(ar->ab); + spin_lock_bh(&dp->dp_lock); + peer = ath12k_dp_link_peer_find_by_pdev_and_addr(dp, ar->pdev_idx, + hdr->addr2); + if (!peer) { + spin_unlock_bh(&dp->dp_lock); + dev_kfree_skb(skb); + goto exit; + } + pubsta = peer->sta; + if (pubsta && pubsta->valid_links) { + status->link_valid = 1; + status->link_id = peer->link_id; + } + spin_unlock_bh(&dp->dp_lock); + goto send_rx; + } + /* Firmware is guaranteed to report all essential management frames via * WMI while it can deliver some extra via HTT. Since there can be * duplicates split the reporting wrt monitor/sniffing. @@ -7247,6 +7291,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) if (ieee80211_is_beacon(hdr->frame_control)) ath12k_mac_handle_beacon(ar, skb); +send_rx: ath12k_dbg(ab, ATH12K_DBG_MGMT, "event mgmt rx skb %p len %d ftype %02x stype %02x\n", skb, skb->len, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index c0a7b21b25ea4..45cd3d5bff3eb 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2273,6 +2273,11 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_TLV_SERVICE_THERM_THROT_POUT_REDUCTION = 410, + WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT = 421, + WMI_TLV_SERVICE_IS_TARGET_IPA = 425, + WMI_TLV_SERVICE_THERM_THROT_TX_CHAIN_MASK = 426, + WMI_TLV_SERVICE_THERM_THROT_5_LEVELS = 429, WMI_TLV_SERVICE_ETH_OFFLOAD = 461, WMI_MAX_EXT2_SERVICE, @@ -2326,6 +2331,19 @@ enum wmi_preamble { WMI_VDEV_PREAMBLE_SHORT = 2, }; +/* + * This will be used to set for WMI_VDEV_PARAM_AP_ENABLE_NAWDS + * whenever 4addr station connects in wds offload case. + * This is for enabling multicast to unicast conversion support in + * firmware + */ +#define WDS_EXT_ENABLE 1 + +enum wmi_peer_4addr_allow_frame { + WMI_PEER_4ADDR_ALLOW_DATA_FRAME = 1, + WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME = 2, +}; + enum wmi_peer_smps_state { WMI_PEER_SMPS_PS_NONE = 0, WMI_PEER_SMPS_STATIC = 1, @@ -2490,6 +2508,7 @@ struct ath12k_wmi_resource_config_arg { u32 ema_max_vap_cnt; u32 ema_max_profile_period; bool is_reg_cc_ext_event_supported; + bool is_wds_null_frame_supported; }; struct ath12k_wmi_init_cmd_arg { @@ -2546,6 +2565,8 @@ struct wmi_init_cmd { #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) #define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9) +#define WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE BIT(18) +#define WMI_RSRC_CFG_FLAGS2_WDS_NULL_FRAME_SUPPORT BIT(22) #define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) struct ath12k_wmi_resource_config_params {