mirror of https://gitee.com/openkylin/linux.git
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: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
ff458edc0c
commit
4334ec8518
|
@ -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,
|
||||||
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 {
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue