diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-07-05 05:34:31 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-08-20 07:53:22 -0400 |
commit | 4c29867790131c281ef96af507d85e3e5f829408 (patch) | |
tree | 9278b0314ba0108b5e9a8ab7db3c9120022be84e | |
parent | 48613ece3d6a2613caa376f51477435cc080f3cd (diff) |
mac80211: support A-MPDU status reporting
Support getting A-MPDU status information from the
drivers and reporting it to userspace via radiotap
in the standard fields.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/mac80211.h | 53 | ||||
-rw-r--r-- | net/mac80211/rx.c | 42 |
2 files changed, 80 insertions, 15 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d9cef31f4cbf..edc235c51a68 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -676,21 +676,41 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | |||
676 | * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if | 676 | * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if |
677 | * the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT | 677 | * the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT |
678 | * to hw.radiotap_mcs_details to advertise that fact | 678 | * to hw.radiotap_mcs_details to advertise that fact |
679 | * @RX_FLAG_AMPDU_DETAILS: A-MPDU details are known, in particular the reference | ||
680 | * number (@ampdu_reference) must be populated and be a distinct number for | ||
681 | * each A-MPDU | ||
682 | * @RX_FLAG_AMPDU_REPORT_ZEROLEN: driver reports 0-length subframes | ||
683 | * @RX_FLAG_AMPDU_IS_ZEROLEN: This is a zero-length subframe, for | ||
684 | * monitoring purposes only | ||
685 | * @RX_FLAG_AMPDU_LAST_KNOWN: last subframe is known, should be set on all | ||
686 | * subframes of a single A-MPDU | ||
687 | * @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU | ||
688 | * @RX_FLAG_AMPDU_DELIM_CRC_ERROR: A delimiter CRC error has been detected | ||
689 | * on this subframe | ||
690 | * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC | ||
691 | * is stored in the @ampdu_delimiter_crc field) | ||
679 | */ | 692 | */ |
680 | enum mac80211_rx_flags { | 693 | enum mac80211_rx_flags { |
681 | RX_FLAG_MMIC_ERROR = 1<<0, | 694 | RX_FLAG_MMIC_ERROR = BIT(0), |
682 | RX_FLAG_DECRYPTED = 1<<1, | 695 | RX_FLAG_DECRYPTED = BIT(1), |
683 | RX_FLAG_MMIC_STRIPPED = 1<<3, | 696 | RX_FLAG_MMIC_STRIPPED = BIT(3), |
684 | RX_FLAG_IV_STRIPPED = 1<<4, | 697 | RX_FLAG_IV_STRIPPED = BIT(4), |
685 | RX_FLAG_FAILED_FCS_CRC = 1<<5, | 698 | RX_FLAG_FAILED_FCS_CRC = BIT(5), |
686 | RX_FLAG_FAILED_PLCP_CRC = 1<<6, | 699 | RX_FLAG_FAILED_PLCP_CRC = BIT(6), |
687 | RX_FLAG_MACTIME_MPDU = 1<<7, | 700 | RX_FLAG_MACTIME_MPDU = BIT(7), |
688 | RX_FLAG_SHORTPRE = 1<<8, | 701 | RX_FLAG_SHORTPRE = BIT(8), |
689 | RX_FLAG_HT = 1<<9, | 702 | RX_FLAG_HT = BIT(9), |
690 | RX_FLAG_40MHZ = 1<<10, | 703 | RX_FLAG_40MHZ = BIT(10), |
691 | RX_FLAG_SHORT_GI = 1<<11, | 704 | RX_FLAG_SHORT_GI = BIT(11), |
692 | RX_FLAG_NO_SIGNAL_VAL = 1<<12, | 705 | RX_FLAG_NO_SIGNAL_VAL = BIT(12), |
693 | RX_FLAG_HT_GF = 1<<13, | 706 | RX_FLAG_HT_GF = BIT(13), |
707 | RX_FLAG_AMPDU_DETAILS = BIT(14), | ||
708 | RX_FLAG_AMPDU_REPORT_ZEROLEN = BIT(15), | ||
709 | RX_FLAG_AMPDU_IS_ZEROLEN = BIT(16), | ||
710 | RX_FLAG_AMPDU_LAST_KNOWN = BIT(17), | ||
711 | RX_FLAG_AMPDU_IS_LAST = BIT(18), | ||
712 | RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19), | ||
713 | RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(20), | ||
694 | }; | 714 | }; |
695 | 715 | ||
696 | /** | 716 | /** |
@@ -714,17 +734,22 @@ enum mac80211_rx_flags { | |||
714 | * HT rates are use (RX_FLAG_HT) | 734 | * HT rates are use (RX_FLAG_HT) |
715 | * @flag: %RX_FLAG_* | 735 | * @flag: %RX_FLAG_* |
716 | * @rx_flags: internal RX flags for mac80211 | 736 | * @rx_flags: internal RX flags for mac80211 |
737 | * @ampdu_reference: A-MPDU reference number, must be a different value for | ||
738 | * each A-MPDU but the same for each subframe within one A-MPDU | ||
739 | * @ampdu_delimiter_crc: A-MPDU delimiter CRC | ||
717 | */ | 740 | */ |
718 | struct ieee80211_rx_status { | 741 | struct ieee80211_rx_status { |
719 | u64 mactime; | 742 | u64 mactime; |
720 | u32 device_timestamp; | 743 | u32 device_timestamp; |
721 | u16 flag; | 744 | u32 ampdu_reference; |
745 | u32 flag; | ||
722 | u16 freq; | 746 | u16 freq; |
723 | u8 rate_idx; | 747 | u8 rate_idx; |
724 | u8 rx_flags; | 748 | u8 rx_flags; |
725 | u8 band; | 749 | u8 band; |
726 | u8 antenna; | 750 | u8 antenna; |
727 | s8 signal; | 751 | s8 signal; |
752 | u8 ampdu_delimiter_crc; | ||
728 | }; | 753 | }; |
729 | 754 | ||
730 | /** | 755 | /** |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0cb4edee6af5..78bf6c7e80c8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -60,7 +60,9 @@ static inline int should_drop_frame(struct sk_buff *skb, | |||
60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
61 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 61 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
62 | 62 | ||
63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | 63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
64 | RX_FLAG_FAILED_PLCP_CRC | | ||
65 | RX_FLAG_AMPDU_IS_ZEROLEN)) | ||
64 | return 1; | 66 | return 1; |
65 | if (unlikely(skb->len < 16 + present_fcs_len)) | 67 | if (unlikely(skb->len < 16 + present_fcs_len)) |
66 | return 1; | 68 | return 1; |
@@ -91,6 +93,13 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | |||
91 | if (status->flag & RX_FLAG_HT) /* HT info */ | 93 | if (status->flag & RX_FLAG_HT) /* HT info */ |
92 | len += 3; | 94 | len += 3; |
93 | 95 | ||
96 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { | ||
97 | /* padding */ | ||
98 | while (len & 3) | ||
99 | len++; | ||
100 | len += 8; | ||
101 | } | ||
102 | |||
94 | return len; | 103 | return len; |
95 | } | 104 | } |
96 | 105 | ||
@@ -215,6 +224,37 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
215 | pos++; | 224 | pos++; |
216 | *pos++ = status->rate_idx; | 225 | *pos++ = status->rate_idx; |
217 | } | 226 | } |
227 | |||
228 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { | ||
229 | u16 flags = 0; | ||
230 | |||
231 | /* ensure 4 byte alignment */ | ||
232 | while ((pos - (u8 *)rthdr) & 3) | ||
233 | pos++; | ||
234 | rthdr->it_present |= | ||
235 | cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS); | ||
236 | put_unaligned_le32(status->ampdu_reference, pos); | ||
237 | pos += 4; | ||
238 | if (status->flag & RX_FLAG_AMPDU_REPORT_ZEROLEN) | ||
239 | flags |= IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN; | ||
240 | if (status->flag & RX_FLAG_AMPDU_IS_ZEROLEN) | ||
241 | flags |= IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN; | ||
242 | if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN) | ||
243 | flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN; | ||
244 | if (status->flag & RX_FLAG_AMPDU_IS_LAST) | ||
245 | flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST; | ||
246 | if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR) | ||
247 | flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR; | ||
248 | if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) | ||
249 | flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN; | ||
250 | put_unaligned_le16(flags, pos); | ||
251 | pos += 2; | ||
252 | if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN) | ||
253 | *pos++ = status->ampdu_delimiter_crc; | ||
254 | else | ||
255 | *pos++ = 0; | ||
256 | *pos++ = 0; | ||
257 | } | ||
218 | } | 258 | } |
219 | 259 | ||
220 | /* | 260 | /* |