Commit f4d291b4 authored by Sven Eckelmann's avatar Sven Eckelmann Committed by Kalle Valo

ath11k: Don't cast ath11k_skb_cb to ieee80211_tx_info.control

The driver_data area of ieee80211_tx_info is used in ath11k for
ath11k_skb_cb. The first function in the TX patch which rewrites it to
ath11k_skb_cb is already ath11k_mac_op_tx. No one else in the code path
must use it for something else before it reinitializes it. Otherwise the
data has to be considered uninitialized or corrupt.

But the ieee80211_tx_info.control shares exactly the same area as
ieee80211_tx_info.driver_data and ath11k is still using it. This results in
best case in a

  ath11k c000000.wifi1: no vif found for mgmt frame, flags 0x0

or (slightly worse) in a kernel oops.

Instead, the interesting data must be moved first into the ath11k_skb_cb
and ieee80211_tx_info.control must then not be used anymore.

Tested-on: IPQ8074 hw2.0 WLAN.HK.2.4.0.1.r1-00026-QCAHKSWPL_SILICONZ-2

Fixes: d5c65159 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20201119154235.263250-1-sven@narfation.org
parent fae0385b
...@@ -75,12 +75,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid) ...@@ -75,12 +75,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
enum ath11k_skb_flags { enum ath11k_skb_flags {
ATH11K_SKB_HW_80211_ENCAP = BIT(0), ATH11K_SKB_HW_80211_ENCAP = BIT(0),
ATH11K_SKB_CIPHER_SET = BIT(1),
}; };
struct ath11k_skb_cb { struct ath11k_skb_cb {
dma_addr_t paddr; dma_addr_t paddr;
u8 eid; u8 eid;
u8 flags; u8 flags;
u32 cipher;
struct ath11k *ar; struct ath11k *ar;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
} __packed; } __packed;
......
...@@ -84,7 +84,6 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -84,7 +84,6 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
struct ath11k_dp *dp = &ab->dp; struct ath11k_dp *dp = &ab->dp;
struct hal_tx_info ti = {0}; struct hal_tx_info ti = {0};
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
struct hal_srng *tcl_ring; struct hal_srng *tcl_ring;
struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_hdr *hdr = (void *)skb->data;
...@@ -149,9 +148,9 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -149,9 +148,9 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
ti.meta_data_flags = arvif->tcl_metadata; ti.meta_data_flags = arvif->tcl_metadata;
if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) {
if (key) { if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) {
ti.encrypt_type = ti.encrypt_type =
ath11k_dp_tx_get_encrypt_type(key->cipher); ath11k_dp_tx_get_encrypt_type(skb_cb->cipher);
if (ieee80211_has_protected(hdr->frame_control)) if (ieee80211_has_protected(hdr->frame_control))
skb_put(skb, IEEE80211_CCMP_MIC_LEN); skb_put(skb, IEEE80211_CCMP_MIC_LEN);
......
...@@ -3997,21 +3997,20 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar) ...@@ -3997,21 +3997,20 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
{ {
struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work); struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work);
struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb;
struct ath11k_vif *arvif; struct ath11k_vif *arvif;
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) { while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) {
info = IEEE80211_SKB_CB(skb); skb_cb = ATH11K_SKB_CB(skb);
if (!info->control.vif) { if (!skb_cb->vif) {
ath11k_warn(ar->ab, "no vif found for mgmt frame, flags 0x%x\n", ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
info->control.flags);
ieee80211_free_txskb(ar->hw, skb); ieee80211_free_txskb(ar->hw, skb);
continue; continue;
} }
arvif = ath11k_vif_to_arvif(info->control.vif); arvif = ath11k_vif_to_arvif(skb_cb->vif);
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
arvif->is_started) { arvif->is_started) {
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
...@@ -4024,8 +4023,8 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) ...@@ -4024,8 +4023,8 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
} }
} else { } else {
ath11k_warn(ar->ab, ath11k_warn(ar->ab,
"dropping mgmt frame for vdev %d, flags 0x%x is_started %d\n", "dropping mgmt frame for vdev %d, is_started %d\n",
arvif->vdev_id, info->control.flags, arvif->vdev_id,
arvif->is_started); arvif->is_started);
ieee80211_free_txskb(ar->hw, skb); ieee80211_free_txskb(ar->hw, skb);
} }
...@@ -4073,10 +4072,19 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw, ...@@ -4073,10 +4072,19 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif = info->control.vif; struct ieee80211_vif *vif = info->control.vif;
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key_conf *key = info->control.hw_key;
u32 info_flags = info->flags;
bool is_prb_rsp; bool is_prb_rsp;
int ret; int ret;
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { skb_cb->vif = vif;
if (key) {
skb_cb->cipher = key->cipher;
skb_cb->flags |= ATH11K_SKB_CIPHER_SET;
}
if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP; skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
} else if (ieee80211_is_mgmt(hdr->frame_control)) { } else if (ieee80211_is_mgmt(hdr->frame_control)) {
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment