--- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2370,6 +2370,25 @@ static inline int ieee80211_sta_ps_trans void ieee80211_sta_set_tim(struct ieee80211_sta *sta); /** + * ieee80211_tx_status_sta - transmit status callback + * + * Call this function for all transmitted frames after they have been + * transmitted. It is permissible to not call this function for + * multicast frames but this can affect statistics. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls + * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe() + * may not be mixed for a single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + * @sta: station for which the tx status is provided + */ +void ieee80211_tx_status_sta(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_sta *sta); + +/** * ieee80211_tx_status - transmit status callback * * Call this function for all transmitted frames after they have been @@ -2384,8 +2403,11 @@ void ieee80211_sta_set_tim(struct ieee80 * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call */ -void ieee80211_tx_status(struct ieee80211_hw *hw, - struct sk_buff *skb); +static inline void ieee80211_tx_status(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + ieee80211_tx_status_sta(hw, skb, NULL); +} /** * ieee80211_tx_status_ni - transmit status callback (in process context) --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -202,7 +202,8 @@ static void ieee80211_set_bar_pending(st */ #define STA_LOST_PKT_THRESHOLD 50 -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_tx_status_sta(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_sta *pubsta) { struct sk_buff *skb2; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -214,7 +215,7 @@ void ieee80211_tx_status(struct ieee8021 struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - struct sta_info *sta, *tmp; + struct sta_info *sta = NULL, *tmp, *tmp2; int retry_count = -1, i; int rates_idx = -1; bool send_to_cooked; @@ -244,11 +245,19 @@ void ieee80211_tx_status(struct ieee8021 sband = local->hw.wiphy->bands[info->band]; fc = hdr->frame_control; - for_each_sta_info(local, hdr->addr1, sta, tmp) { - /* skip wrong virtual interface */ - if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) - continue; + if (!pubsta) { + for_each_sta_info(local, hdr->addr1, tmp, tmp2) { + /* skip wrong virtual interface */ + if (memcmp(hdr->addr2, tmp->sdata->vif.addr, ETH_ALEN)) + continue; + + sta = tmp; + } + } else { + sta = container_of(pubsta, struct sta_info, sta); + } + if (sta) { acked = !!(info->flags & IEEE80211_TX_STAT_ACK); if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) { /* @@ -497,7 +506,7 @@ void ieee80211_tx_status(struct ieee8021 rcu_read_unlock(); dev_kfree_skb(skb); } -EXPORT_SYMBOL(ieee80211_tx_status); +EXPORT_SYMBOL(ieee80211_tx_status_sta); void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) {