aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c112
1 files changed, 77 insertions, 35 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index f3d710705e76..f97fa0a54cf6 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -228,6 +228,79 @@ static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
228 tid_tx->bar_pending = true; 228 tid_tx->bar_pending = true;
229} 229}
230 230
231static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
232{
233 int len = sizeof(struct ieee80211_radiotap_header);
234
235 /* IEEE80211_RADIOTAP_RATE rate */
236 if (info->status.rates[0].idx >= 0 &&
237 !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
238 len += 2;
239
240 /* IEEE80211_RADIOTAP_TX_FLAGS */
241 len += 2;
242
243 /* IEEE80211_RADIOTAP_DATA_RETRIES */
244 len += 1;
245
246 return len;
247}
248
249static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
250 *sband, struct sk_buff *skb,
251 int retry_count, int rtap_len)
252{
253 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
254 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
255 struct ieee80211_radiotap_header *rthdr;
256 unsigned char *pos;
257 __le16 txflags;
258
259 rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len);
260
261 memset(rthdr, 0, rtap_len);
262 rthdr->it_len = cpu_to_le16(rtap_len);
263 rthdr->it_present =
264 cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
265 (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
266 pos = (unsigned char *)(rthdr + 1);
267
268 /*
269 * XXX: Once radiotap gets the bitmap reset thing the vendor
270 * extensions proposal contains, we can actually report
271 * the whole set of tries we did.
272 */
273
274 /* IEEE80211_RADIOTAP_RATE */
275 if (info->status.rates[0].idx >= 0 &&
276 !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
277 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
278 *pos = sband->bitrates[info->status.rates[0].idx].bitrate / 5;
279 /* padding for tx flags */
280 pos += 2;
281 }
282
283 /* IEEE80211_RADIOTAP_TX_FLAGS */
284 txflags = 0;
285 if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
286 !is_multicast_ether_addr(hdr->addr1))
287 txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
288
289 if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
290 (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
291 txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
292 else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
293 txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
294
295 put_unaligned_le16(txflags, pos);
296 pos += 2;
297
298 /* IEEE80211_RADIOTAP_DATA_RETRIES */
299 /* for now report the total retry_count */
300 *pos = retry_count;
301 pos++;
302}
303
231/* 304/*
232 * Use a static threshold for now, best value to be determined 305 * Use a static threshold for now, best value to be determined
233 * by testing ... 306 * by testing ...
@@ -246,7 +319,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
246 u16 frag, type; 319 u16 frag, type;
247 __le16 fc; 320 __le16 fc;
248 struct ieee80211_supported_band *sband; 321 struct ieee80211_supported_band *sband;
249 struct ieee80211_tx_status_rtap_hdr *rthdr;
250 struct ieee80211_sub_if_data *sdata; 322 struct ieee80211_sub_if_data *sdata;
251 struct net_device *prev_dev = NULL; 323 struct net_device *prev_dev = NULL;
252 struct sta_info *sta, *tmp; 324 struct sta_info *sta, *tmp;
@@ -256,6 +328,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
256 bool acked; 328 bool acked;
257 struct ieee80211_bar *bar; 329 struct ieee80211_bar *bar;
258 u16 tid; 330 u16 tid;
331 int rtap_len;
259 332
260 for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 333 for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
261 if (info->status.rates[i].idx < 0) { 334 if (info->status.rates[i].idx < 0) {
@@ -460,44 +533,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
460 } 533 }
461 534
462 /* send frame to monitor interfaces now */ 535 /* send frame to monitor interfaces now */
463 536 rtap_len = ieee80211_tx_radiotap_len(info);
464 if (skb_headroom(skb) < sizeof(*rthdr)) { 537 if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
465 printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); 538 printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
466 dev_kfree_skb(skb); 539 dev_kfree_skb(skb);
467 return; 540 return;
468 } 541 }
469 542 ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len);
470 rthdr = (struct ieee80211_tx_status_rtap_hdr *)
471 skb_push(skb, sizeof(*rthdr));
472
473 memset(rthdr, 0, sizeof(*rthdr));
474 rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
475 rthdr->hdr.it_present =
476 cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
477 (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
478 (1 << IEEE80211_RADIOTAP_RATE));
479
480 if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
481 !is_multicast_ether_addr(hdr->addr1))
482 rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
483
484 /*
485 * XXX: Once radiotap gets the bitmap reset thing the vendor
486 * extensions proposal contains, we can actually report
487 * the whole set of tries we did.
488 */
489 if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
490 (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
491 rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
492 else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
493 rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
494 if (info->status.rates[0].idx >= 0 &&
495 !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
496 rthdr->rate = sband->bitrates[
497 info->status.rates[0].idx].bitrate / 5;
498
499 /* for now report the total retry_count */
500 rthdr->data_retries = retry_count;
501 543
502 /* XXX: is this sufficient for BPF? */ 544 /* XXX: is this sufficient for BPF? */
503 skb_set_mac_header(skb, 0); 545 skb_set_mac_header(skb, 0);