diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 71 |
1 files changed, 59 insertions, 12 deletions
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)) |