diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-07-03 07:34:02 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-07-16 02:57:59 -0400 |
commit | a144f378a489b5900c028425cb0d0a7a3fc8c1c1 (patch) | |
tree | 0d3cdf6bf60bf0b740c7ab3d303251f7a2bc8fc6 /net/mac80211 | |
parent | ad24b0da9ecec433091f74596843703e4cf5da77 (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.c | 69 |
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) |