aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-11-06 16:56:36 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-11-10 04:30:43 -0500
commit1f7bba79af57ceecf25c2b7d3e6a484efefe340f (patch)
tree1394dde23980c4436bd41aca4e6a251e42055e42 /net/mac80211
parentd04b5ac9e70b2056a8a12f768f4b46773576025e (diff)
mac80211: add back support for radiotap vendor namespace data
Radiotap vendor namespace data might still be useful, but we reverted it because it used too much space in the RX status. Put it back, but address the space problem by using a single bit only and putting everything else into the skb->data. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/rx.c100
1 files changed, 82 insertions, 18 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index bc63aa0c5401..f57af5c7c12a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -39,7 +39,8 @@
39 * only useful for monitoring. 39 * only useful for monitoring.
40 */ 40 */
41static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, 41static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
42 struct sk_buff *skb) 42 struct sk_buff *skb,
43 unsigned int rtap_vendor_space)
43{ 44{
44 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { 45 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
45 if (likely(skb->len > FCS_LEN)) 46 if (likely(skb->len > FCS_LEN))
@@ -52,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
52 } 53 }
53 } 54 }
54 55
56 __pskb_pull(skb, rtap_vendor_space);
57
55 return skb; 58 return skb;
56} 59}
57 60
58static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) 61static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
62 unsigned int rtap_vendor_space)
59{ 63{
60 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 64 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
61 struct ieee80211_hdr *hdr = (void *)skb->data; 65 struct ieee80211_hdr *hdr;
66
67 hdr = (void *)(skb->data + rtap_vendor_space);
62 68
63 if (status->flag & (RX_FLAG_FAILED_FCS_CRC | 69 if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
64 RX_FLAG_FAILED_PLCP_CRC | 70 RX_FLAG_FAILED_PLCP_CRC |
65 RX_FLAG_AMPDU_IS_ZEROLEN)) 71 RX_FLAG_AMPDU_IS_ZEROLEN))
66 return true; 72 return true;
67 73
68 if (unlikely(skb->len < 16 + present_fcs_len)) 74 if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space))
69 return true; 75 return true;
70 76
71 if (ieee80211_is_ctl(hdr->frame_control) && 77 if (ieee80211_is_ctl(hdr->frame_control) &&
@@ -77,8 +83,9 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len)
77} 83}
78 84
79static int 85static int
80ieee80211_rx_radiotap_space(struct ieee80211_local *local, 86ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
81 struct ieee80211_rx_status *status) 87 struct ieee80211_rx_status *status,
88 struct sk_buff *skb)
82{ 89{
83 int len; 90 int len;
84 91
@@ -121,6 +128,21 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
121 len += 2 * hweight8(status->chains); 128 len += 2 * hweight8(status->chains);
122 } 129 }
123 130
131 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
132 struct ieee80211_vendor_radiotap *rtap = (void *)skb->data;
133
134 /* vendor presence bitmap */
135 len += 4;
136 /* alignment for fixed 6-byte vendor data header */
137 len = ALIGN(len, 2);
138 /* vendor data header */
139 len += 6;
140 if (WARN_ON(rtap->align == 0))
141 rtap->align = 1;
142 len = ALIGN(len, rtap->align);
143 len += rtap->len + rtap->pad;
144 }
145
124 return len; 146 return len;
125} 147}
126 148
@@ -144,13 +166,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
144 u16 channel_flags = 0; 166 u16 channel_flags = 0;
145 int mpdulen, chain; 167 int mpdulen, chain;
146 unsigned long chains = status->chains; 168 unsigned long chains = status->chains;
169 struct ieee80211_vendor_radiotap rtap = {};
170
171 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
172 rtap = *(struct ieee80211_vendor_radiotap *)skb->data;
173 /* rtap.len and rtap.pad are undone immediately */
174 skb_pull(skb, sizeof(rtap) + rtap.len + rtap.pad);
175 }
147 176
148 mpdulen = skb->len; 177 mpdulen = skb->len;
149 if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) 178 if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
150 mpdulen += FCS_LEN; 179 mpdulen += FCS_LEN;
151 180
152 rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); 181 rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
153 memset(rthdr, 0, rtap_len); 182 memset(rthdr, 0, rtap_len - rtap.len - rtap.pad);
154 it_present = &rthdr->it_present; 183 it_present = &rthdr->it_present;
155 184
156 /* radiotap header, set always present flags */ 185 /* radiotap header, set always present flags */
@@ -172,6 +201,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
172 BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); 201 BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
173 } 202 }
174 203
204 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
205 it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
206 BIT(IEEE80211_RADIOTAP_EXT);
207 put_unaligned_le32(it_present_val, it_present);
208 it_present++;
209 it_present_val = rtap.present;
210 }
211
175 put_unaligned_le32(it_present_val, it_present); 212 put_unaligned_le32(it_present_val, it_present);
176 213
177 pos = (void *)(it_present + 1); 214 pos = (void *)(it_present + 1);
@@ -366,6 +403,22 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
366 *pos++ = status->chain_signal[chain]; 403 *pos++ = status->chain_signal[chain];
367 *pos++ = chain; 404 *pos++ = chain;
368 } 405 }
406
407 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
408 /* ensure 2 byte alignment for the vendor field as required */
409 if ((pos - (u8 *)rthdr) & 1)
410 *pos++ = 0;
411 *pos++ = rtap.oui[0];
412 *pos++ = rtap.oui[1];
413 *pos++ = rtap.oui[2];
414 *pos++ = rtap.subns;
415 put_unaligned_le16(rtap.len, pos);
416 pos += 2;
417 /* align the actual payload as requested */
418 while ((pos - (u8 *)rthdr) & (rtap.align - 1))
419 *pos++ = 0;
420 /* data (and possible padding) already follows */
421 }
369} 422}
370 423
371/* 424/*
@@ -379,10 +432,17 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
379{ 432{
380 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); 433 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
381 struct ieee80211_sub_if_data *sdata; 434 struct ieee80211_sub_if_data *sdata;
382 int needed_headroom; 435 int rt_hdrlen, needed_headroom;
383 struct sk_buff *skb, *skb2; 436 struct sk_buff *skb, *skb2;
384 struct net_device *prev_dev = NULL; 437 struct net_device *prev_dev = NULL;
385 int present_fcs_len = 0; 438 int present_fcs_len = 0;
439 unsigned int rtap_vendor_space = 0;
440
441 if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
442 struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data;
443
444 rtap_vendor_space = sizeof(*rtap) + rtap->len + rtap->pad;
445 }
386 446
387 /* 447 /*
388 * First, we may need to make a copy of the skb because 448 * First, we may need to make a copy of the skb because
@@ -396,25 +456,27 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
396 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) 456 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
397 present_fcs_len = FCS_LEN; 457 present_fcs_len = FCS_LEN;
398 458
399 /* ensure hdr->frame_control is in skb head */ 459 /* ensure hdr->frame_control and vendor radiotap data are in skb head */
400 if (!pskb_may_pull(origskb, 2)) { 460 if (!pskb_may_pull(origskb, 2 + rtap_vendor_space)) {
401 dev_kfree_skb(origskb); 461 dev_kfree_skb(origskb);
402 return NULL; 462 return NULL;
403 } 463 }
404 464
405 if (!local->monitors) { 465 if (!local->monitors) {
406 if (should_drop_frame(origskb, present_fcs_len)) { 466 if (should_drop_frame(origskb, present_fcs_len,
467 rtap_vendor_space)) {
407 dev_kfree_skb(origskb); 468 dev_kfree_skb(origskb);
408 return NULL; 469 return NULL;
409 } 470 }
410 471
411 return remove_monitor_info(local, origskb); 472 return remove_monitor_info(local, origskb, rtap_vendor_space);
412 } 473 }
413 474
414 /* room for the radiotap header based on driver features */ 475 /* room for the radiotap header based on driver features */
415 needed_headroom = ieee80211_rx_radiotap_space(local, status); 476 rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, origskb);
477 needed_headroom = rt_hdrlen - rtap_vendor_space;
416 478
417 if (should_drop_frame(origskb, present_fcs_len)) { 479 if (should_drop_frame(origskb, present_fcs_len, rtap_vendor_space)) {
418 /* only need to expand headroom if necessary */ 480 /* only need to expand headroom if necessary */
419 skb = origskb; 481 skb = origskb;
420 origskb = NULL; 482 origskb = NULL;
@@ -438,15 +500,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
438 */ 500 */
439 skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); 501 skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);
440 502
441 origskb = remove_monitor_info(local, origskb); 503 origskb = remove_monitor_info(local, origskb,
504 rtap_vendor_space);
442 505
443 if (!skb) 506 if (!skb)
444 return origskb; 507 return origskb;
445 } 508 }
446 509
447 /* prepend radiotap information */ 510 /* prepend radiotap information */
448 ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, 511 ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true);
449 true);
450 512
451 skb_reset_mac_header(skb); 513 skb_reset_mac_header(skb);
452 skb->ip_summed = CHECKSUM_UNNECESSARY; 514 skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2892,8 +2954,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
2892 if (!local->cooked_mntrs) 2954 if (!local->cooked_mntrs)
2893 goto out_free_skb; 2955 goto out_free_skb;
2894 2956
2957 /* vendor data is long removed here */
2958 status->flag &= ~RX_FLAG_RADIOTAP_VENDOR_DATA;
2895 /* room for the radiotap header based on driver features */ 2959 /* room for the radiotap header based on driver features */
2896 needed_headroom = ieee80211_rx_radiotap_space(local, status); 2960 needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb);
2897 2961
2898 if (skb_headroom(skb) < needed_headroom && 2962 if (skb_headroom(skb) < needed_headroom &&
2899 pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) 2963 pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))