diff options
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 33 | ||||
-rw-r--r-- | include/net/mac80211.h | 12 | ||||
-rw-r--r-- | net/mac80211/rx.c | 71 |
3 files changed, 103 insertions, 13 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index ce522aa93af7..c242f5a9b8bc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -751,7 +751,11 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
751 | continue; | 751 | continue; |
752 | } | 752 | } |
753 | 753 | ||
754 | nskb = skb_copy(skb, GFP_ATOMIC); | 754 | /* |
755 | * reserve some space for our vendor and the normal | ||
756 | * radiotap header, since we're copying anyway | ||
757 | */ | ||
758 | nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC); | ||
755 | if (nskb == NULL) | 759 | if (nskb == NULL) |
756 | continue; | 760 | continue; |
757 | 761 | ||
@@ -769,6 +773,33 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
769 | (data->tsf_offset - data2->tsf_offset) + | 773 | (data->tsf_offset - data2->tsf_offset) + |
770 | 24 * 8 * 10 / txrate->bitrate); | 774 | 24 * 8 * 10 / txrate->bitrate); |
771 | 775 | ||
776 | #if 0 | ||
777 | /* | ||
778 | * Don't enable this code by default as the OUI 00:00:00 | ||
779 | * is registered to Xerox so we shouldn't use it here, it | ||
780 | * might find its way into pcap files. | ||
781 | * Note that this code requires the headroom in the SKB | ||
782 | * that was allocated earlier. | ||
783 | */ | ||
784 | rx_status.vendor_radiotap_oui[0] = 0x00; | ||
785 | rx_status.vendor_radiotap_oui[1] = 0x00; | ||
786 | rx_status.vendor_radiotap_oui[2] = 0x00; | ||
787 | rx_status.vendor_radiotap_subns = 127; | ||
788 | /* | ||
789 | * Radiotap vendor namespaces can (and should) also be | ||
790 | * split into fields by using the standard radiotap | ||
791 | * presence bitmap mechanism. Use just BIT(0) here for | ||
792 | * the presence bitmap. | ||
793 | */ | ||
794 | rx_status.vendor_radiotap_bitmap = BIT(0); | ||
795 | /* We have 8 bytes of (dummy) data */ | ||
796 | rx_status.vendor_radiotap_len = 8; | ||
797 | /* For testing, also require it to be aligned */ | ||
798 | rx_status.vendor_radiotap_align = 8; | ||
799 | /* push the data */ | ||
800 | memcpy(skb_push(nskb, 8), "ABCDEFGH", 8); | ||
801 | #endif | ||
802 | |||
772 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); | 803 | memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); |
773 | ieee80211_rx_irqsafe(data2->hw, nskb); | 804 | ieee80211_rx_irqsafe(data2->hw, nskb); |
774 | } | 805 | } |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b484a6569eac..dd08fbb3cf28 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -789,12 +789,21 @@ enum mac80211_rx_flags { | |||
789 | * @ampdu_reference: A-MPDU reference number, must be a different value for | 789 | * @ampdu_reference: A-MPDU reference number, must be a different value for |
790 | * each A-MPDU but the same for each subframe within one A-MPDU | 790 | * each A-MPDU but the same for each subframe within one A-MPDU |
791 | * @ampdu_delimiter_crc: A-MPDU delimiter CRC | 791 | * @ampdu_delimiter_crc: A-MPDU delimiter CRC |
792 | * @vendor_radiotap_bitmap: radiotap vendor namespace presence bitmap | ||
793 | * @vendor_radiotap_len: radiotap vendor namespace length | ||
794 | * @vendor_radiotap_align: radiotap vendor namespace alignment. Note | ||
795 | * that the actual data must be at the start of the SKB data | ||
796 | * already. | ||
797 | * @vendor_radiotap_oui: radiotap vendor namespace OUI | ||
798 | * @vendor_radiotap_subns: radiotap vendor sub namespace | ||
792 | */ | 799 | */ |
793 | struct ieee80211_rx_status { | 800 | struct ieee80211_rx_status { |
794 | u64 mactime; | 801 | u64 mactime; |
795 | u32 device_timestamp; | 802 | u32 device_timestamp; |
796 | u32 ampdu_reference; | 803 | u32 ampdu_reference; |
797 | u32 flag; | 804 | u32 flag; |
805 | u32 vendor_radiotap_bitmap; | ||
806 | u16 vendor_radiotap_len; | ||
798 | u16 freq; | 807 | u16 freq; |
799 | u8 rate_idx; | 808 | u8 rate_idx; |
800 | u8 rx_flags; | 809 | u8 rx_flags; |
@@ -802,6 +811,9 @@ struct ieee80211_rx_status { | |||
802 | u8 antenna; | 811 | u8 antenna; |
803 | s8 signal; | 812 | s8 signal; |
804 | u8 ampdu_delimiter_crc; | 813 | u8 ampdu_delimiter_crc; |
814 | u8 vendor_radiotap_align; | ||
815 | u8 vendor_radiotap_oui[3]; | ||
816 | u8 vendor_radiotap_subns; | ||
805 | }; | 817 | }; |
806 | 818 | ||
807 | /** | 819 | /** |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8480bbf1a707..ec15a4929f7a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -40,6 +40,8 @@ | |||
40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
41 | struct sk_buff *skb) | 41 | struct sk_buff *skb) |
42 | { | 42 | { |
43 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
44 | |||
43 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
44 | if (likely(skb->len > FCS_LEN)) | 46 | if (likely(skb->len > FCS_LEN)) |
45 | __pskb_trim(skb, skb->len - FCS_LEN); | 47 | __pskb_trim(skb, skb->len - FCS_LEN); |
@@ -51,6 +53,9 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
51 | } | 53 | } |
52 | } | 54 | } |
53 | 55 | ||
56 | if (status->vendor_radiotap_len) | ||
57 | __pskb_pull(skb, status->vendor_radiotap_len); | ||
58 | |||
54 | return skb; | 59 | return skb; |
55 | } | 60 | } |
56 | 61 | ||
@@ -73,32 +78,48 @@ static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) | |||
73 | } | 78 | } |
74 | 79 | ||
75 | static int | 80 | static int |
76 | ieee80211_rx_radiotap_len(struct ieee80211_local *local, | 81 | ieee80211_rx_radiotap_space(struct ieee80211_local *local, |
77 | struct ieee80211_rx_status *status) | 82 | struct ieee80211_rx_status *status) |
78 | { | 83 | { |
79 | int len; | 84 | int len; |
80 | 85 | ||
81 | /* always present fields */ | 86 | /* always present fields */ |
82 | len = sizeof(struct ieee80211_radiotap_header) + 9; | 87 | len = sizeof(struct ieee80211_radiotap_header) + 9; |
83 | 88 | ||
84 | if (ieee80211_have_rx_timestamp(status)) | 89 | /* allocate extra bitmap */ |
90 | if (status->vendor_radiotap_len) | ||
91 | len += 4; | ||
92 | |||
93 | if (ieee80211_have_rx_timestamp(status)) { | ||
94 | len = ALIGN(len, 8); | ||
85 | len += 8; | 95 | len += 8; |
96 | } | ||
86 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 97 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
87 | len += 1; | 98 | len += 1; |
88 | 99 | ||
89 | if (len & 1) /* padding for RX_FLAGS if necessary */ | 100 | /* padding for RX_FLAGS if necessary */ |
90 | len++; | 101 | len = ALIGN(len, 2); |
91 | 102 | ||
92 | if (status->flag & RX_FLAG_HT) /* HT info */ | 103 | if (status->flag & RX_FLAG_HT) /* HT info */ |
93 | len += 3; | 104 | len += 3; |
94 | 105 | ||
95 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { | 106 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { |
96 | /* padding */ | 107 | len = ALIGN(len, 4); |
97 | while (len & 3) | ||
98 | len++; | ||
99 | len += 8; | 108 | len += 8; |
100 | } | 109 | } |
101 | 110 | ||
111 | if (status->vendor_radiotap_len) { | ||
112 | if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) | ||
113 | status->vendor_radiotap_align = 1; | ||
114 | /* align standard part of vendor namespace */ | ||
115 | len = ALIGN(len, 2); | ||
116 | /* allocate standard part of vendor namespace */ | ||
117 | len += 6; | ||
118 | /* align vendor-defined part */ | ||
119 | len = ALIGN(len, status->vendor_radiotap_align); | ||
120 | /* vendor-defined part is already in skb */ | ||
121 | } | ||
122 | |||
102 | return len; | 123 | return len; |
103 | } | 124 | } |
104 | 125 | ||
@@ -132,14 +153,25 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
132 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | 153 | (1 << IEEE80211_RADIOTAP_CHANNEL) | |
133 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | 154 | (1 << IEEE80211_RADIOTAP_ANTENNA) | |
134 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | 155 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); |
135 | rthdr->it_len = cpu_to_le16(rtap_len); | 156 | rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); |
136 | 157 | ||
137 | pos = (unsigned char *)(rthdr + 1); | 158 | pos = (unsigned char *)(rthdr + 1); |
138 | 159 | ||
160 | if (status->vendor_radiotap_len) { | ||
161 | rthdr->it_present |= | ||
162 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | | ||
163 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); | ||
164 | put_unaligned_le32(status->vendor_radiotap_bitmap, pos); | ||
165 | pos += 4; | ||
166 | } | ||
167 | |||
139 | /* the order of the following fields is important */ | 168 | /* the order of the following fields is important */ |
140 | 169 | ||
141 | /* IEEE80211_RADIOTAP_TSFT */ | 170 | /* IEEE80211_RADIOTAP_TSFT */ |
142 | if (ieee80211_have_rx_timestamp(status)) { | 171 | if (ieee80211_have_rx_timestamp(status)) { |
172 | /* padding */ | ||
173 | while ((pos - (u8 *)rthdr) & 7) | ||
174 | *pos++ = 0; | ||
143 | put_unaligned_le64( | 175 | put_unaligned_le64( |
144 | ieee80211_calculate_rx_timestamp(local, status, | 176 | ieee80211_calculate_rx_timestamp(local, status, |
145 | mpdulen, 0), | 177 | mpdulen, 0), |
@@ -211,7 +243,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
211 | /* IEEE80211_RADIOTAP_RX_FLAGS */ | 243 | /* IEEE80211_RADIOTAP_RX_FLAGS */ |
212 | /* ensure 2 byte alignment for the 2 byte field as required */ | 244 | /* ensure 2 byte alignment for the 2 byte field as required */ |
213 | if ((pos - (u8 *)rthdr) & 1) | 245 | if ((pos - (u8 *)rthdr) & 1) |
214 | pos++; | 246 | *pos++ = 0; |
215 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) | 247 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) |
216 | rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; | 248 | rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; |
217 | put_unaligned_le16(rx_flags, pos); | 249 | put_unaligned_le16(rx_flags, pos); |
@@ -261,6 +293,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
261 | *pos++ = 0; | 293 | *pos++ = 0; |
262 | *pos++ = 0; | 294 | *pos++ = 0; |
263 | } | 295 | } |
296 | |||
297 | if (status->vendor_radiotap_len) { | ||
298 | /* ensure 2 byte alignment for the vendor field as required */ | ||
299 | if ((pos - (u8 *)rthdr) & 1) | ||
300 | *pos++ = 0; | ||
301 | *pos++ = status->vendor_radiotap_oui[0]; | ||
302 | *pos++ = status->vendor_radiotap_oui[1]; | ||
303 | *pos++ = status->vendor_radiotap_oui[2]; | ||
304 | *pos++ = status->vendor_radiotap_subns; | ||
305 | put_unaligned_le16(status->vendor_radiotap_len, pos); | ||
306 | pos += 2; | ||
307 | /* align the actual payload as requested */ | ||
308 | while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) | ||
309 | *pos++ = 0; | ||
310 | } | ||
264 | } | 311 | } |
265 | 312 | ||
266 | /* | 313 | /* |
@@ -289,7 +336,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
289 | */ | 336 | */ |
290 | 337 | ||
291 | /* room for the radiotap header based on driver features */ | 338 | /* room for the radiotap header based on driver features */ |
292 | needed_headroom = ieee80211_rx_radiotap_len(local, status); | 339 | needed_headroom = ieee80211_rx_radiotap_space(local, status); |
293 | 340 | ||
294 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 341 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
295 | present_fcs_len = FCS_LEN; | 342 | present_fcs_len = FCS_LEN; |
@@ -2593,7 +2640,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2593 | goto out_free_skb; | 2640 | goto out_free_skb; |
2594 | 2641 | ||
2595 | /* room for the radiotap header based on driver features */ | 2642 | /* room for the radiotap header based on driver features */ |
2596 | needed_headroom = ieee80211_rx_radiotap_len(local, status); | 2643 | needed_headroom = ieee80211_rx_radiotap_space(local, status); |
2597 | 2644 | ||
2598 | if (skb_headroom(skb) < needed_headroom && | 2645 | if (skb_headroom(skb) < needed_headroom && |
2599 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) | 2646 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) |