diff options
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r-- | net/mac80211/status.c | 51 |
1 files changed, 45 insertions, 6 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3153c19893b8..38a797217a91 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -157,6 +157,15 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) | |||
157 | } | 157 | } |
158 | } | 158 | } |
159 | 159 | ||
160 | /* | ||
161 | * Use a static threshold for now, best value to be determined | ||
162 | * by testing ... | ||
163 | * Should it depend on: | ||
164 | * - on # of retransmissions | ||
165 | * - current throughput (higher value for higher tpt)? | ||
166 | */ | ||
167 | #define STA_LOST_PKT_THRESHOLD 50 | ||
168 | |||
160 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | 169 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) |
161 | { | 170 | { |
162 | struct sk_buff *skb2; | 171 | struct sk_buff *skb2; |
@@ -173,6 +182,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
173 | int retry_count = -1, i; | 182 | int retry_count = -1, i; |
174 | int rates_idx = -1; | 183 | int rates_idx = -1; |
175 | bool send_to_cooked; | 184 | bool send_to_cooked; |
185 | bool acked; | ||
176 | 186 | ||
177 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 187 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
178 | /* the HW cannot have attempted that rate */ | 188 | /* the HW cannot have attempted that rate */ |
@@ -198,8 +208,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
198 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) | 208 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) |
199 | continue; | 209 | continue; |
200 | 210 | ||
201 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 211 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); |
202 | test_sta_flags(sta, WLAN_STA_PS_STA)) { | 212 | if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) { |
203 | /* | 213 | /* |
204 | * The STA is in power save mode, so assume | 214 | * The STA is in power save mode, so assume |
205 | * that this TX packet failed because of that. | 215 | * that this TX packet failed because of that. |
@@ -231,7 +241,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
231 | rcu_read_unlock(); | 241 | rcu_read_unlock(); |
232 | return; | 242 | return; |
233 | } else { | 243 | } else { |
234 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) | 244 | if (!acked) |
235 | sta->tx_retry_failed++; | 245 | sta->tx_retry_failed++; |
236 | sta->tx_retry_count += retry_count; | 246 | sta->tx_retry_count += retry_count; |
237 | } | 247 | } |
@@ -240,9 +250,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
240 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 250 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
241 | ieee80211s_update_metric(local, sta, skb); | 251 | ieee80211s_update_metric(local, sta, skb); |
242 | 252 | ||
243 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && | 253 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) |
244 | (info->flags & IEEE80211_TX_STAT_ACK)) | ||
245 | ieee80211_frame_acked(sta, skb); | 254 | ieee80211_frame_acked(sta, skb); |
255 | |||
256 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && | ||
257 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | ||
258 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); | ||
259 | |||
260 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
261 | if (info->flags & IEEE80211_TX_STAT_ACK) { | ||
262 | if (sta->lost_packets) | ||
263 | sta->lost_packets = 0; | ||
264 | } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) { | ||
265 | cfg80211_cqm_pktloss_notify(sta->sdata->dev, | ||
266 | sta->sta.addr, | ||
267 | sta->lost_packets, | ||
268 | GFP_ATOMIC); | ||
269 | sta->lost_packets = 0; | ||
270 | } | ||
271 | } | ||
246 | } | 272 | } |
247 | 273 | ||
248 | rcu_read_unlock(); | 274 | rcu_read_unlock(); |
@@ -295,10 +321,23 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
295 | msecs_to_jiffies(10)); | 321 | msecs_to_jiffies(10)); |
296 | } | 322 | } |
297 | 323 | ||
298 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) | 324 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { |
325 | struct ieee80211_work *wk; | ||
326 | |||
327 | rcu_read_lock(); | ||
328 | list_for_each_entry_rcu(wk, &local->work_list, list) { | ||
329 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) | ||
330 | continue; | ||
331 | if (wk->offchan_tx.frame != skb) | ||
332 | continue; | ||
333 | wk->offchan_tx.frame = NULL; | ||
334 | break; | ||
335 | } | ||
336 | rcu_read_unlock(); | ||
299 | cfg80211_mgmt_tx_status( | 337 | cfg80211_mgmt_tx_status( |
300 | skb->dev, (unsigned long) skb, skb->data, skb->len, | 338 | skb->dev, (unsigned long) skb, skb->data, skb->len, |
301 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | 339 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); |
340 | } | ||
302 | 341 | ||
303 | /* this was a transmitted frame, but now we want to reuse it */ | 342 | /* this was a transmitted frame, but now we want to reuse it */ |
304 | skb_orphan(skb); | 343 | skb_orphan(skb); |