aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c71
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 @@
40static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, 40static 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
75static int 80static int
76ieee80211_rx_radiotap_len(struct ieee80211_local *local, 81ieee80211_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))