wifi: ath12k: Fix the QoS control field offset to build QoS header
authorRamasamy Kaliappan <quic_rkaliapp@quicinc.com>
Tue, 15 Apr 2025 18:41:02 +0000 (00:11 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Thu, 17 Apr 2025 22:49:34 +0000 (15:49 -0700)
Currently, in the mac80211 layer, received EAPOL packets are dropped
when the HT control field is present in the QoS header. This issue
arises due to an incorrect QoS control field offset used to build
the QoS header in the MSDU data, leading to a corrupted header in the
mac80211 layer. This issue also applies to other frames that contain
the QoS control field, such as QoS data or Null frames. To resolve
this, use ieee80211_get_qos_ctl() to obtain the correct QoS control
offset from the MSDU data. Additionally, ensure the QoS control header
is copied in little-endian format within the MSDU data.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Signed-off-by: Ramasamy Kaliappan <quic_rkaliapp@quicinc.com>
Signed-off-by: Nithyanantham Paramasivam <nithyanantham.paramasivam@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250415184102.2707300-1-nithyanantham.paramasivam@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/dp_rx.c

index 3e4dd9d..8193f95 100644 (file)
@@ -2137,7 +2137,7 @@ static void ath12k_get_dot11_hdr_from_rx_desc(struct ath12k *ar,
        struct ath12k_base *ab = ar->ab;
        size_t hdr_len, crypto_len;
        struct ieee80211_hdr hdr;
-       u16 qos_ctl;
+       __le16 qos_ctl;
        u8 *crypto_hdr, mesh_ctrl;
 
        ath12k_dp_rx_desc_get_dot11_hdr(ab, rx_desc, &hdr);
@@ -2158,13 +2158,13 @@ static void ath12k_get_dot11_hdr_from_rx_desc(struct ath12k *ar,
 
        /* Add QOS header */
        if (ieee80211_is_data_qos(hdr.frame_control)) {
-               qos_ctl = rxcb->tid;
+               struct ieee80211_hdr *qos_ptr = (struct ieee80211_hdr *)msdu->data;
+
+               qos_ctl = cpu_to_le16(rxcb->tid & IEEE80211_QOS_CTL_TID_MASK);
                if (mesh_ctrl)
-                       qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT;
+                       qos_ctl |= cpu_to_le16(IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT);
 
-               /* TODO: Add other QoS ctl fields when required */
-               memcpy(msdu->data + (hdr_len - IEEE80211_QOS_CTL_LEN),
-                      &qos_ctl, IEEE80211_QOS_CTL_LEN);
+               memcpy(ieee80211_get_qos_ctl(qos_ptr), &qos_ctl, IEEE80211_QOS_CTL_LEN);
        }
 }