aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c33
-rw-r--r--include/net/mac80211.h12
-rw-r--r--net/mac80211/rx.c71
3 files changed, 103 insertions, 13 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ce522aa93af..c242f5a9b8b 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 b484a6569ea..dd08fbb3cf2 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 */
793struct ieee80211_rx_status { 800struct 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 8480bbf1a70..ec15a4929f7 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))