summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c10
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c59
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c72
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h9
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_mon.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c13
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/hal.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h25
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c228
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.c11
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c3
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c95
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c41
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c16
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c16
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c16
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hw.c48
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c47
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.h17
27 files changed, 642 insertions, 115 deletions
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 3f6f4db5b7ee..8dacc878c006 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -267,7 +267,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
- .num_vdevs = 2 + 1,
+ .num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
@@ -445,7 +445,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
- .num_vdevs = 2 + 1,
+ .num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
@@ -535,7 +535,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
- .num_vdevs = 2 + 1,
+ .num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
@@ -797,7 +797,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
- .num_vdevs = 2 + 1,
+ .num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
@@ -886,7 +886,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
- .num_vdevs = 2 + 1,
+ .num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 2a413e3a07a7..9e90d8e3f155 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -2503,6 +2503,29 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
ieee80211_rx_napi(ar->hw, pubsta, msdu, napi);
}
+static bool ath11k_dp_rx_check_nwifi_hdr_len_valid(struct ath11k_base *ab,
+ struct hal_rx_desc *rx_desc,
+ struct sk_buff *msdu)
+{
+ struct ieee80211_hdr *hdr;
+ u8 decap_type;
+ u32 hdr_len;
+
+ decap_type = ath11k_dp_rx_h_msdu_start_decap_type(ab, rx_desc);
+ if (decap_type != DP_RX_DECAP_TYPE_NATIVE_WIFI)
+ return true;
+
+ hdr = (struct ieee80211_hdr *)msdu->data;
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+ if (likely(hdr_len <= DP_MAX_NWIFI_HDR_LEN))
+ return true;
+
+ ab->soc_stats.invalid_rbm++;
+ WARN_ON_ONCE(1);
+ return false;
+}
+
static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
struct sk_buff *msdu,
struct sk_buff_head *msdu_list,
@@ -2573,6 +2596,11 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
}
}
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
+ ret = -EINVAL;
+ goto free_out;
+ }
+
ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status);
@@ -3262,6 +3290,12 @@ mic_fail:
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
skb_pull(msdu, hal_rx_desc_sz);
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ar->ab, rx_desc,
+ msdu))) {
+ dev_kfree_skb_any(msdu);
+ return -EINVAL;
+ }
+
ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
@@ -3954,6 +3988,10 @@ static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
}
+
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ar->ab, desc, msdu)))
+ return -EINVAL;
+
ath11k_dp_rx_h_ppdu(ar, desc, status);
ath11k_dp_rx_h_mpdu(ar, msdu, desc, status);
@@ -3998,7 +4036,7 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu,
return drop;
}
-static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
+static bool ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
struct ieee80211_rx_status *status)
{
u16 msdu_len;
@@ -4006,15 +4044,28 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
u8 l3pad_bytes;
struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
+ struct ath11k_base *ab = ar->ab;
rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc);
rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc);
l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc);
msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc);
+
+ if (unlikely(hal_rx_desc_sz + l3pad_bytes + msdu_len > DP_RX_BUFFER_SIZE)) {
+ ath11k_dbg(ab, ATH11K_DBG_DATA,
+ "invalid msdu len in tkip mic err %u\n", msdu_len);
+ ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", desc,
+ sizeof(*desc));
+ return true;
+ }
+
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
+ if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
+ return true;
+
ath11k_dp_rx_h_ppdu(ar, desc, status);
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
@@ -4022,19 +4073,21 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
ath11k_dp_rx_h_undecap(ar, msdu, desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
+
+ return false;
}
static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu,
struct ieee80211_rx_status *status)
{
struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
- bool drop = false;
+ bool drop;
ar->ab->soc_stats.rxdma_error[rxcb->err_code]++;
switch (rxcb->err_code) {
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
- ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
+ drop = ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
break;
default:
/* TODO: Review other rxdma error code to check if anything is
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index a48b6bf1f29a..2d55cdc4d165 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4227,13 +4227,14 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
if (ret)
goto exit;
- arg = kzalloc_obj(*arg);
+ arg = kzalloc_flex(*arg, chan_list, req->n_channels);
if (!arg) {
ret = -ENOMEM;
goto exit;
}
+ arg->num_chan = req->n_channels;
ath11k_wmi_start_scan_init(ar, arg);
arg->vdev_id = arvif->vdev_id;
arg->scan_id = ATH11K_SCAN_ID;
@@ -4261,38 +4262,27 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
arg->scan_f_passive = 1;
}
- if (req->n_channels) {
- arg->num_chan = req->n_channels;
- arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
- GFP_KERNEL);
+ for (i = 0; i < arg->num_chan; i++) {
+ if (test_bit(WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL,
+ ar->ab->wmi_ab.svc_map)) {
+ arg->chan_list[i] =
+ u32_encode_bits(req->channels[i]->center_freq,
+ WMI_SCAN_CONFIG_PER_CHANNEL_MASK);
- if (!arg->chan_list) {
- ret = -ENOMEM;
- goto exit;
- }
-
- for (i = 0; i < arg->num_chan; i++) {
- if (test_bit(WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL,
- ar->ab->wmi_ab.svc_map)) {
- arg->chan_list[i] =
- u32_encode_bits(req->channels[i]->center_freq,
- WMI_SCAN_CONFIG_PER_CHANNEL_MASK);
-
- /* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is set in scan
- * flags, then scan all PSC channels in 6 GHz band and
- * those non-PSC channels where RNR IE is found during
- * the legacy 2.4/5 GHz scan.
- * If NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set,
- * then all channels in 6 GHz will be scanned.
- */
- if (req->channels[i]->band == NL80211_BAND_6GHZ &&
- req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ &&
- !cfg80211_channel_is_psc(req->channels[i]))
- arg->chan_list[i] |=
- WMI_SCAN_CH_FLAG_SCAN_ONLY_IF_RNR_FOUND;
- } else {
- arg->chan_list[i] = req->channels[i]->center_freq;
- }
+ /* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is set in scan
+ * flags, then scan all PSC channels in 6 GHz band and
+ * those non-PSC channels where RNR IE is found during
+ * the legacy 2.4/5 GHz scan.
+ * If NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set,
+ * then all channels in 6 GHz will be scanned.
+ */
+ if (req->channels[i]->band == NL80211_BAND_6GHZ &&
+ req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ &&
+ !cfg80211_channel_is_psc(req->channels[i]))
+ arg->chan_list[i] |=
+ WMI_SCAN_CH_FLAG_SCAN_ONLY_IF_RNR_FOUND;
+ } else {
+ arg->chan_list[i] = req->channels[i]->center_freq;
}
}
@@ -4335,7 +4325,6 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
exit:
if (arg) {
- kfree(arg->chan_list);
kfree(arg->extraie.ptr);
kfree(arg);
}
@@ -9735,19 +9724,14 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
- arg = kzalloc_obj(*arg);
+ arg = kzalloc_flex(*arg, chan_list, 1);
if (!arg) {
ret = -ENOMEM;
goto exit;
}
- ath11k_wmi_start_scan_init(ar, arg);
+
arg->num_chan = 1;
- arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
- GFP_KERNEL);
- if (!arg->chan_list) {
- ret = -ENOMEM;
- goto free_arg;
- }
+ ath11k_wmi_start_scan_init(ar, arg);
arg->vdev_id = arvif->vdev_id;
arg->scan_id = ATH11K_SCAN_ID;
@@ -9768,7 +9752,7 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
spin_lock_bh(&ar->data_lock);
ar->scan.state = ATH11K_SCAN_IDLE;
spin_unlock_bh(&ar->data_lock);
- goto free_chan_list;
+ goto free_arg;
}
ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
@@ -9778,7 +9762,7 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
if (ret)
ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret);
ret = -ETIMEDOUT;
- goto free_chan_list;
+ goto free_arg;
}
ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
@@ -9786,8 +9770,6 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
ret = 0;
-free_chan_list:
- kfree(arg->chan_list);
free_arg:
kfree(arg);
exit:
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index baed501b640b..b2dade0516ac 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -3423,7 +3423,6 @@ struct scan_req_params {
u32 num_bssid;
u32 num_ssids;
u32 n_probes;
- u32 *chan_list;
u32 notify_scan_events;
struct wlan_ssid ssid[WLAN_SCAN_PARAMS_MAX_SSID];
struct wmi_mac_addr bssid_list[WLAN_SCAN_PARAMS_MAX_BSSID];
@@ -3436,6 +3435,7 @@ struct scan_req_params {
struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID];
struct wmi_mac_addr mac_addr;
struct wmi_mac_addr mac_mask;
+ u32 chan_list[] __counted_by(num_chan);
};
struct wmi_ssid_arg {
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index f6d8ec9ef7b0..fc5127b5c1a3 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -353,6 +353,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 {
@@ -492,6 +495,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;
@@ -527,6 +534,8 @@ struct ath12k_sta {
u16 free_logical_link_idx_map;
enum ieee80211_sta_state state;
+
+ bool enable_4addr;
};
#define ATH12K_HALF_20MHZ_BW 10
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 737287a9aa46..44c5cff75f16 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -115,13 +115,14 @@ ath12k_dp_mon_fill_rx_rate(struct ath12k_pdev_dp *dp_pdev,
bool is_cck;
pkt_type = ppdu_info->preamble_type;
- rate_mcs = ppdu_info->rate;
+ rate_mcs = ppdu_info->mcs;
nss = ppdu_info->nss;
sgi = ppdu_info->gi;
switch (pkt_type) {
case RX_MSDU_START_PKT_TYPE_11A:
case RX_MSDU_START_PKT_TYPE_11B:
+ rate_mcs = ppdu_info->rate;
is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B);
if (rx_status->band < NUM_NL80211_BANDS) {
struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
@@ -471,13 +472,10 @@ void ath12k_dp_mon_update_radiotap(struct ath12k_pdev_dp *dp_pdev,
rxs->encoding = RX_ENC_HE;
ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he));
ath12k_dp_mon_rx_update_radiotap_he(ppduinfo, ptr);
- rxs->rate_idx = ppduinfo->rate;
} else if (ppduinfo->vht_flags) {
rxs->encoding = RX_ENC_VHT;
- rxs->rate_idx = ppduinfo->rate;
} else if (ppduinfo->ht_flags) {
rxs->encoding = RX_ENC_HT;
- rxs->rate_idx = ppduinfo->rate;
} else {
struct ath12k *ar;
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c
index a1100782d45e..47d009a0d61f 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.c
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
@@ -419,7 +419,7 @@ struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_p
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"ath12k dp peer find by peerid index called without rcu lock");
- if (!peer_id || peer_id >= ATH12K_DP_PEER_ID_INVALID)
+ if (peer_id >= ATH12K_DP_PEER_ID_INVALID)
return NULL;
index = ath12k_dp_peer_get_peerid_index(dp, peer_id);
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h
index 113b8040010f..f5067e66f1e1 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.h
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.h
@@ -143,6 +143,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 a68b28aa1f4b..06e74124e57e 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1142,7 +1142,8 @@ 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;
@@ -1166,6 +1167,13 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu
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.
*/
@@ -1202,8 +1210,7 @@ ath12k_dp_rx_h_find_link_peer(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *ms
lockdep_assert_held(&dp->dp_lock);
- if (rxcb->peer_id)
- peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
+ peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
if (peer)
return peer;
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index 55a31e669b3b..0660db070e92 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -190,7 +190,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 bf4f7dbae866..21c551d8b248 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/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index a9888e0521a1..d135b2936378 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -19,14 +19,28 @@
#define TARGET_NUM_VDEVS(ab) ((ab)->profile_param->num_vdevs)
/* Max num of stations for Single Radio mode */
-#define TARGET_NUM_STATIONS_SINGLE(ab) ((ab)->profile_param->max_client_single)
+#define TARGET_NUM_STATIONS_SINGLE(ab) \
+({ \
+ typeof(ab) _ab = (ab); \
+ min_not_zero(_ab->hw_params->client.max_client_single, \
+ _ab->profile_param->max_client_single); \
+})
/* Max num of stations for DBS */
-#define TARGET_NUM_STATIONS_DBS(ab) ((ab)->profile_param->max_client_dbs)
+#define TARGET_NUM_STATIONS_DBS(ab) \
+({ \
+ typeof(ab) _ab = (ab); \
+ min_not_zero(_ab->hw_params->client.max_client_dbs, \
+ _ab->profile_param->max_client_dbs); \
+})
/* Max num of stations for DBS_SBS */
#define TARGET_NUM_STATIONS_DBS_SBS(ab) \
- ((ab)->profile_param->max_client_dbs_sbs)
+({ \
+ typeof(ab) _ab = (ab); \
+ min_not_zero(_ab->hw_params->client.max_client_dbs_sbs, \
+ _ab->profile_param->max_client_dbs_sbs); \
+})
#define TARGET_NUM_STATIONS(ab, x) TARGET_NUM_STATIONS_##x(ab)
@@ -213,6 +227,11 @@ struct ath12k_hw_params {
/* setup REO queue, frag etc only for primary link peer */
bool dp_primary_link_only:1;
+ struct {
+ u32 max_client_single;
+ u32 max_client_dbs;
+ u32 max_client_dbs_sbs;
+ } client;
};
struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 87b27f7cff5d..a6e4b660da81 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6571,6 +6571,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;
@@ -7865,6 +7938,28 @@ out:
}
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,
@@ -8049,16 +8144,16 @@ int ath12k_mac_op_change_sta_links(struct ieee80211_hw *hw,
continue;
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
- arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id);
+ if (!arvif || !arvif->is_created)
+ continue;
- if (!arvif || !arsta) {
+ arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id);
+ if (!arsta) {
ath12k_hw_warn(ah, "Failed to alloc/assign link sta");
continue;
}
ar = arvif->ar;
- if (!ar)
- continue;
ret = ath12k_mac_station_add(ar, arvif, arsta);
if (ret) {
@@ -10020,12 +10115,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);
@@ -10235,6 +10332,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;
@@ -10302,7 +10400,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
if (ret) {
ath12k_warn(ab, "failed to create WMI vdev %d: %d\n",
arvif->vdev_id, ret);
- return ret;
+ goto err;
}
ar->num_created_vdevs++;
@@ -10403,6 +10501,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) {
@@ -10449,13 +10567,13 @@ err_peer_del:
if (ret) {
ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
arvif->vdev_id, arvif->bssid);
- goto err;
+ goto err_dp_peer_del;
}
ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id,
arvif->bssid);
if (ret)
- goto err_vdev_del;
+ goto err_dp_peer_del;
ar->num_peers--;
}
@@ -10472,8 +10590,6 @@ err_vdev_del:
ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
ar->num_created_vdevs--;
- arvif->is_created = false;
- arvif->ar = NULL;
ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
ab->free_vdev_map |= 1LL << arvif->vdev_id;
ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
@@ -10482,6 +10598,7 @@ err_vdev_del:
spin_unlock_bh(&ar->data_lock);
err:
+ arvif->is_created = false;
arvif->ar = NULL;
return ret;
}
@@ -11480,6 +11597,9 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
continue;
}
+ if (WARN_ON(!arvif))
+ continue;
+
ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n",
arvif->vdev_id,
@@ -12271,23 +12391,85 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
- struct ath12k *ar;
+ struct ath12k *curr_ar, *new_ar, *group_ar;
+ struct ieee80211_vif_chanctx_switch *v;
+ int i, j, count = 0;
lockdep_assert_wiphy(hw->wiphy);
- ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
- if (!ar)
- return -EINVAL;
+ if (n_vifs == 0)
+ return 0;
- /* Switching channels across radio is not allowed */
- if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx))
- return -EINVAL;
+ struct ath12k **ar_map __free(kfree) = kzalloc_objs(*ar_map, n_vifs);
- ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
- "mac chanctx switch n_vifs %d mode %d\n",
- n_vifs, mode);
- ath12k_mac_update_vif_chan(ar, vifs, n_vifs);
+ if (!ar_map)
+ return -ENOMEM;
+
+ for (i = 0; i < n_vifs; i++) {
+ v = &vifs[i];
+
+ if (v->old_ctx->def.chan->band != v->new_ctx->def.chan->band) {
+ ath12k_generic_dbg(ATH12K_DBG_MAC,
+ "mac chanctx switch band change not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ curr_ar = ath12k_get_ar_by_ctx(hw, v->old_ctx);
+ new_ar = ath12k_get_ar_by_ctx(hw, v->new_ctx);
+
+ if (!curr_ar || !new_ar) {
+ ath12k_generic_dbg(ATH12K_DBG_MAC,
+ "unable to determine device for the passed channel ctx\n");
+ ath12k_generic_dbg(ATH12K_DBG_MAC,
+ "Old freq %d MHz (device %s) to new freq %d MHz (device %s)\n",
+ v->old_ctx->def.chan->center_freq,
+ curr_ar ? "valid" : "invalid",
+ v->new_ctx->def.chan->center_freq,
+ new_ar ? "valid" : "invalid");
+ return -EINVAL;
+ }
+
+ /* Switching a vif between two radios is not allowed */
+ if (curr_ar != new_ar) {
+ ath12k_dbg(curr_ar->ab, ATH12K_DBG_MAC,
+ "mac chanctx switch to another radio not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ar_map[i] = curr_ar;
+ }
+
+ /* Group vifs by radio (ar) and process each group independently. */
+ bool *processed __free(kfree) = kzalloc_objs(*processed, n_vifs);
+
+ if (!processed)
+ return -ENOMEM;
+ struct ieee80211_vif_chanctx_switch *group_vifs __free(kfree) =
+ kzalloc_objs(*group_vifs, n_vifs);
+
+ if (!group_vifs)
+ return -ENOMEM;
+
+ for (i = 0; i < n_vifs; i++) {
+ if (processed[i])
+ continue;
+
+ group_ar = ar_map[i];
+
+ count = 0;
+ for (j = 0; j < n_vifs; j++) {
+ if (!processed[j] && ar_map[j] == group_ar) {
+ group_vifs[count++] = vifs[j];
+ processed[j] = true;
+ }
+ }
+
+ ath12k_dbg(group_ar->ab, ATH12K_DBG_MAC,
+ "mac chanctx switch n_vifs %d mode %d\n",
+ count, mode);
+ ath12k_mac_update_vif_chan(group_ar, group_vifs, count);
+ }
return 0;
}
EXPORT_SYMBOL(ath12k_mac_op_switch_vif_chanctx);
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 7b50c5976384..aba98afd4365 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 2e875176baaa..c222bdaa333c 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -218,7 +218,13 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
ahsta = ath12k_sta_to_ahsta(sta);
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 */
@@ -249,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_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
index 77f5d23be78d..7dd4a49d64d5 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
@@ -1779,8 +1779,7 @@ ath12k_wifi7_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev,
info[1] = __le32_to_cpu(mpdu_start->info1);
peer_id = u32_get_bits(info[1], HAL_RX_MPDU_START_INFO1_PEERID);
- if (peer_id)
- ppdu_info->peer_id = peer_id;
+ ppdu_info->peer_id = peer_id;
ppdu_info->mpdu_len += u32_get_bits(info[1],
HAL_RX_MPDU_START_INFO2_MPDU_LEN);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index 945680b3ebdf..cb9dd8cb28b6 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,
@@ -554,7 +569,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;
@@ -1028,12 +1045,14 @@ mic_fail:
skb_pull(msdu, hal_rx_desc_sz);
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu,
- rx_info)))
+ rx_info))) {
+ dev_kfree_skb_any(msdu);
return -EINVAL;
+ }
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;
}
@@ -1588,6 +1607,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 */
@@ -1632,7 +1652,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;
@@ -1678,7 +1700,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;
}
@@ -1693,6 +1765,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 629084aa36d8..d2749de44553 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 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
@@ -124,6 +130,19 @@ tcl_ring_sel:
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 (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);
+ }
if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) {
@@ -140,7 +159,7 @@ tcl_ring_sel:
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.
*/
@@ -148,6 +167,14 @@ tcl_ring_sel:
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);
@@ -158,11 +185,13 @@ tcl_ring_sel:
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 24cf7972d41b..86bc813878c0 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 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 1eefb931a853..8cebb229ebed 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 ba9ce1e718e8..9d5180ef83b4 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
@@ -700,6 +700,20 @@ u8 ath12k_hal_rx_desc_get_mpdu_tid_qcn9274(struct hal_rx_desc *desc)
}
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)
{
return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.sw_peer_id);
@@ -914,6 +928,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 02d3cadf03fe..eeabe9db776e 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 9d2b1552c2f5..c548a0fbf1bb 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 e64e512cac7d..efbbc1cbd3e4 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c
@@ -281,6 +281,20 @@ u8 ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(struct hal_rx_desc *desc)
}
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)
{
return !!le32_get_bits(desc->u.wcn7850.mpdu_start.info4,
@@ -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 cb3185850439..3d59fa452ec0 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -434,6 +434,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = false,
.dp_primary_link_only = true,
+ .client = {
+ .max_client_single = 512,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ },
},
{
.name = "wcn7850 hw2.0",
@@ -520,6 +525,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = true,
.dp_primary_link_only = false,
+ .client = {
+ .max_client_single = 512,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ },
},
{
.name = "qcn9274 hw2.0",
@@ -602,6 +612,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = false,
.dp_primary_link_only = true,
+ .client = {
+ .max_client_single = 512,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ },
},
{
.name = "ipq5332 hw1.0",
@@ -677,6 +692,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.bdf_addr_offset = 0xC00000,
.dp_primary_link_only = true,
+ .client = {
+ .max_client_single = 256,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ },
},
{
.name = "qcc2072 hw1.0",
@@ -764,6 +784,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = true,
.dp_primary_link_only = false,
+ .client = {
+ .max_client_single = 512,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ },
},
{
.name = "ipq5424 hw1.0",
@@ -843,6 +868,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = false,
.dp_primary_link_only = true,
+ .client = {
+ .max_client_single = 512,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ },
},
};
@@ -859,7 +889,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_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;
@@ -941,6 +973,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);
@@ -961,7 +999,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, 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);
@@ -999,6 +1037,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;
@@ -1030,7 +1073,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,
+ ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, arsta,
msdu_copied, true, mcbc_gsn, is_mcast);
if (unlikely(ret)) {
if (ret == -ENOMEM) {
@@ -1075,6 +1118,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 18f91051199c..84a31b953db8 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -4192,7 +4192,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,
@@ -4402,6 +4407,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;
@@ -7223,7 +7231,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;
@@ -7298,6 +7310,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.
@@ -7321,6 +7365,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 14b8dcdf881d..c452e3d57a29 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2278,6 +2278,7 @@ enum wmi_tlv_service {
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,
@@ -2334,6 +2335,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,
@@ -2498,6 +2512,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 {
@@ -2554,6 +2569,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 {