aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-07-03 07:34:02 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-07-16 02:57:59 -0400
commita144f378a489b5900c028425cb0d0a7a3fc8c1c1 (patch)
tree0d3cdf6bf60bf0b740c7ab3d303251f7a2bc8fc6 /net/mac80211
parentad24b0da9ecec433091f74596843703e4cf5da77 (diff)
mac80211: add per-chain signal information to radiotap
When per-chain signal information is available, don't add the antenna field once but instead add a radiotap namespace for each chain containing the chain/antenna number and the signal strength on that chain. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/rx.c69
1 files changed, 52 insertions, 17 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 23dbcfc69b3b..c9f2ca43856a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -87,11 +87,13 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
87 int len; 87 int len;
88 88
89 /* always present fields */ 89 /* always present fields */
90 len = sizeof(struct ieee80211_radiotap_header) + 9; 90 len = sizeof(struct ieee80211_radiotap_header) + 8;
91 91
92 /* allocate extra bitmap */ 92 /* allocate extra bitmaps */
93 if (status->vendor_radiotap_len) 93 if (status->vendor_radiotap_len)
94 len += 4; 94 len += 4;
95 if (status->chains)
96 len += 4 * hweight8(status->chains);
95 97
96 if (ieee80211_have_rx_timestamp(status)) { 98 if (ieee80211_have_rx_timestamp(status)) {
97 len = ALIGN(len, 8); 99 len = ALIGN(len, 8);
@@ -100,6 +102,10 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
100 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) 102 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
101 len += 1; 103 len += 1;
102 104
105 /* antenna field, if we don't have per-chain info */
106 if (!status->chains)
107 len += 1;
108
103 /* padding for RX_FLAGS if necessary */ 109 /* padding for RX_FLAGS if necessary */
104 len = ALIGN(len, 2); 110 len = ALIGN(len, 2);
105 111
@@ -116,6 +122,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
116 len += 12; 122 len += 12;
117 } 123 }
118 124
125 if (status->chains) {
126 /* antenna and antenna signal fields */
127 len += 2 * hweight8(status->chains);
128 }
129
119 if (status->vendor_radiotap_len) { 130 if (status->vendor_radiotap_len) {
120 if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) 131 if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
121 status->vendor_radiotap_align = 1; 132 status->vendor_radiotap_align = 1;
@@ -145,8 +156,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
145 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 156 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
146 struct ieee80211_radiotap_header *rthdr; 157 struct ieee80211_radiotap_header *rthdr;
147 unsigned char *pos; 158 unsigned char *pos;
159 __le32 *it_present;
160 u32 it_present_val;
148 u16 rx_flags = 0; 161 u16 rx_flags = 0;
149 int mpdulen; 162 int mpdulen, chain;
163 unsigned long chains = status->chains;
150 164
151 mpdulen = skb->len; 165 mpdulen = skb->len;
152 if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) 166 if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
@@ -154,25 +168,39 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
154 168
155 rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); 169 rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
156 memset(rthdr, 0, rtap_len); 170 memset(rthdr, 0, rtap_len);
171 it_present = &rthdr->it_present;
157 172
158 /* radiotap header, set always present flags */ 173 /* radiotap header, set always present flags */
159 rthdr->it_present =
160 cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
161 (1 << IEEE80211_RADIOTAP_CHANNEL) |
162 (1 << IEEE80211_RADIOTAP_ANTENNA) |
163 (1 << IEEE80211_RADIOTAP_RX_FLAGS));
164 rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); 174 rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
175 it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
176 BIT(IEEE80211_RADIOTAP_CHANNEL) |
177 BIT(IEEE80211_RADIOTAP_RX_FLAGS);
178
179 if (!status->chains)
180 it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA);
165 181
166 pos = (unsigned char *)(rthdr + 1); 182 for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
183 it_present_val |=
184 BIT(IEEE80211_RADIOTAP_EXT) |
185 BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE);
186 put_unaligned_le32(it_present_val, it_present);
187 it_present++;
188 it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) |
189 BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
190 }
167 191
168 if (status->vendor_radiotap_len) { 192 if (status->vendor_radiotap_len) {
169 rthdr->it_present |= 193 it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
170 cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | 194 BIT(IEEE80211_RADIOTAP_EXT);
171 cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); 195 put_unaligned_le32(it_present_val, it_present);
172 put_unaligned_le32(status->vendor_radiotap_bitmap, pos); 196 it_present++;
173 pos += 4; 197 it_present_val = status->vendor_radiotap_bitmap;
174 } 198 }
175 199
200 put_unaligned_le32(it_present_val, it_present);
201
202 pos = (void *)(it_present + 1);
203
176 /* the order of the following fields is important */ 204 /* the order of the following fields is important */
177 205
178 /* IEEE80211_RADIOTAP_TSFT */ 206 /* IEEE80211_RADIOTAP_TSFT */
@@ -242,9 +270,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
242 270
243 /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ 271 /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
244 272
245 /* IEEE80211_RADIOTAP_ANTENNA */ 273 if (!status->chains) {
246 *pos = status->antenna; 274 /* IEEE80211_RADIOTAP_ANTENNA */
247 pos++; 275 *pos = status->antenna;
276 pos++;
277 }
248 278
249 /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ 279 /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
250 280
@@ -341,6 +371,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
341 pos += 2; 371 pos += 2;
342 } 372 }
343 373
374 for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
375 *pos++ = status->chain_signal[chain];
376 *pos++ = chain;
377 }
378
344 if (status->vendor_radiotap_len) { 379 if (status->vendor_radiotap_len) {
345 /* ensure 2 byte alignment for the vendor field as required */ 380 /* ensure 2 byte alignment for the vendor field as required */
346 if ((pos - (u8 *)rthdr) & 1) 381 if ((pos - (u8 *)rthdr) & 1)