aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-16 04:09:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2012-11-19 09:45:46 -0500
commit90b9e446fbb64630c72cab48c007d7081aec2533 (patch)
treea0e6c4e1d69ac776103ec234bcca312dddbb1e8d /net/mac80211/rx.c
parent5a306f5887d5fd840beb8ea872897fa89e8fcdef (diff)
mac80211: support radiotap vendor namespace RX data
In some cases, in particular for experimentation, it can be useful to be able to add vendor namespace data to received frames in addition to the normal radiotap data. Allow doing this through mac80211 by adding fields to the RX status descriptor that describe the data while the data itself is prepended to the frame. Also add some example code to hwsim, but don't enable it because it doesn't use a proper OUI identifier. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
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))