Commit 4334ec85 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: fix TX status cookie in HW offload case

When the off-channel TX is done with remain-on-channel
offloaded to hardware, the reported cookie is wrong as
in that case we shouldn't use the SKB as the cookie but
need to instead use the corresponding r-o-c cookie
(XOR'ed with 2 to prevent API mismatches).

Fix this by keeping track of the hw_roc_skb pointer
just for the status processing and use the correct
cookie to report in this case. We can't use the
hw_roc_skb pointer itself because it is NULL'ed when
the frame is transmitted to prevent it being used
twice.

This fixes a bug where the P2P state machine in the
supplicant gets stuck because it never gets a correct
result for its transmitted frame.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ff458edc
...@@ -1822,6 +1822,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, ...@@ -1822,6 +1822,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
*cookie ^= 2; *cookie ^= 2;
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
local->hw_roc_skb = skb; local->hw_roc_skb = skb;
local->hw_roc_skb_for_status = skb;
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
return 0; return 0;
...@@ -1875,6 +1876,7 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ...@@ -1875,6 +1876,7 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
if (ret == 0) { if (ret == 0) {
kfree_skb(local->hw_roc_skb); kfree_skb(local->hw_roc_skb);
local->hw_roc_skb = NULL; local->hw_roc_skb = NULL;
local->hw_roc_skb_for_status = NULL;
} }
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
......
...@@ -953,7 +953,7 @@ struct ieee80211_local { ...@@ -953,7 +953,7 @@ struct ieee80211_local {
struct ieee80211_channel *hw_roc_channel; struct ieee80211_channel *hw_roc_channel;
struct net_device *hw_roc_dev; struct net_device *hw_roc_dev;
struct sk_buff *hw_roc_skb; struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
struct work_struct hw_roc_start, hw_roc_done; struct work_struct hw_roc_start, hw_roc_done;
enum nl80211_channel_type hw_roc_channel_type; enum nl80211_channel_type hw_roc_channel_type;
unsigned int hw_roc_duration; unsigned int hw_roc_duration;
......
...@@ -323,6 +323,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -323,6 +323,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
struct ieee80211_work *wk; struct ieee80211_work *wk;
u64 cookie = (unsigned long)skb;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(wk, &local->work_list, list) { list_for_each_entry_rcu(wk, &local->work_list, list) {
...@@ -334,8 +335,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -334,8 +335,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
break; break;
} }
rcu_read_unlock(); rcu_read_unlock();
if (local->hw_roc_skb_for_status == skb) {
cookie = local->hw_roc_cookie ^ 2;
local->hw_roc_skb_for_status = NULL;
}
cfg80211_mgmt_tx_status( cfg80211_mgmt_tx_status(
skb->dev, (unsigned long) skb, skb->data, skb->len, skb->dev, cookie, skb->data, skb->len,
!!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
} }
......
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