diff options
author | Karl Beldan <karl.beldan@rivierawaves.com> | 2013-07-27 05:47:04 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-08-01 04:49:04 -0400 |
commit | a824131017a2c3c8f275c6eb46740cfb8a43f7c5 (patch) | |
tree | f6d634a12d72cbd6dd7b5d38457b28a2604445cc /net/mac80211/status.c | |
parent | 9e2bc79bce58a1ce0005015c9351b3bcaaa02e5c (diff) |
mac80211: report some VHT radiotap infos for tx status
The radiotap VHT info is 12 bytes (required to be aligned on 2) :
u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_*
u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_*
u8 bandwidth
u8 mcs_nss[4]
u8 coding
u8 group_id
u16 partial_aid
ATM mac80211 can handle IEEE80211_RADIOTAP_VHT_KNOWN_{GI,BANDWIDTH} and
mcs_nss[0] (i.e single user) in simple cases.
This is more a placeholder to let sniffers give more clues for VHT,
since we don't have yet the proper infrastructure/conventions
in mac80211 for complete feedback (e.g consider dynamic BW).
Signed-off-by: Karl Beldan <karl.beldan@rivierawaves.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r-- | net/mac80211/status.c | 76 |
1 files changed, 63 insertions, 13 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 8eabfd96ca36..368837fe3b80 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -235,7 +235,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info) | |||
235 | 235 | ||
236 | /* IEEE80211_RADIOTAP_RATE rate */ | 236 | /* IEEE80211_RADIOTAP_RATE rate */ |
237 | if (info->status.rates[0].idx >= 0 && | 237 | if (info->status.rates[0].idx >= 0 && |
238 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) | 238 | !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS | |
239 | IEEE80211_TX_RC_VHT_MCS))) | ||
239 | len += 2; | 240 | len += 2; |
240 | 241 | ||
241 | /* IEEE80211_RADIOTAP_TX_FLAGS */ | 242 | /* IEEE80211_RADIOTAP_TX_FLAGS */ |
@@ -244,16 +245,21 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info) | |||
244 | /* IEEE80211_RADIOTAP_DATA_RETRIES */ | 245 | /* IEEE80211_RADIOTAP_DATA_RETRIES */ |
245 | len += 1; | 246 | len += 1; |
246 | 247 | ||
247 | /* IEEE80211_TX_RC_MCS */ | 248 | /* IEEE80211_RADIOTAP_MCS |
248 | if (info->status.rates[0].idx >= 0 && | 249 | * IEEE80211_RADIOTAP_VHT */ |
249 | info->status.rates[0].flags & IEEE80211_TX_RC_MCS) | 250 | if (info->status.rates[0].idx >= 0) { |
250 | len += 3; | 251 | if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) |
252 | len += 3; | ||
253 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) | ||
254 | len = ALIGN(len, 2) + 12; | ||
255 | } | ||
251 | 256 | ||
252 | return len; | 257 | return len; |
253 | } | 258 | } |
254 | 259 | ||
255 | static void | 260 | static void |
256 | ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband, | 261 | ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, |
262 | struct ieee80211_supported_band *sband, | ||
257 | struct sk_buff *skb, int retry_count, | 263 | struct sk_buff *skb, int retry_count, |
258 | int rtap_len, int shift) | 264 | int rtap_len, int shift) |
259 | { | 265 | { |
@@ -280,7 +286,8 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband, | |||
280 | 286 | ||
281 | /* IEEE80211_RADIOTAP_RATE */ | 287 | /* IEEE80211_RADIOTAP_RATE */ |
282 | if (info->status.rates[0].idx >= 0 && | 288 | if (info->status.rates[0].idx >= 0 && |
283 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) { | 289 | !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS | |
290 | IEEE80211_TX_RC_VHT_MCS))) { | ||
284 | u16 rate; | 291 | u16 rate; |
285 | 292 | ||
286 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); | 293 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); |
@@ -310,9 +317,12 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband, | |||
310 | *pos = retry_count; | 317 | *pos = retry_count; |
311 | pos++; | 318 | pos++; |
312 | 319 | ||
313 | /* IEEE80211_TX_RC_MCS */ | 320 | if (info->status.rates[0].idx < 0) |
314 | if (info->status.rates[0].idx >= 0 && | 321 | return; |
315 | info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { | 322 | |
323 | /* IEEE80211_RADIOTAP_MCS | ||
324 | * IEEE80211_RADIOTAP_VHT */ | ||
325 | if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { | ||
316 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); | 326 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); |
317 | pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS | | 327 | pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS | |
318 | IEEE80211_RADIOTAP_MCS_HAVE_GI | | 328 | IEEE80211_RADIOTAP_MCS_HAVE_GI | |
@@ -325,8 +335,48 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband, | |||
325 | pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF; | 335 | pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF; |
326 | pos[2] = info->status.rates[0].idx; | 336 | pos[2] = info->status.rates[0].idx; |
327 | pos += 3; | 337 | pos += 3; |
328 | } | 338 | } else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { |
339 | u16 known = local->hw.radiotap_vht_details & | ||
340 | (IEEE80211_RADIOTAP_VHT_KNOWN_GI | | ||
341 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH); | ||
342 | |||
343 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); | ||
344 | |||
345 | /* required alignment from rthdr */ | ||
346 | pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2); | ||
329 | 347 | ||
348 | /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */ | ||
349 | put_unaligned_le16(known, pos); | ||
350 | pos += 2; | ||
351 | |||
352 | /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */ | ||
353 | if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) | ||
354 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; | ||
355 | pos++; | ||
356 | |||
357 | /* u8 bandwidth */ | ||
358 | if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
359 | *pos = 1; | ||
360 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
361 | *pos = 4; | ||
362 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) | ||
363 | *pos = 11; | ||
364 | else /* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */ | ||
365 | *pos = 0; | ||
366 | pos++; | ||
367 | |||
368 | /* u8 mcs_nss[4] */ | ||
369 | *pos = (ieee80211_rate_get_vht_mcs(&info->status.rates[0]) << 4) | | ||
370 | ieee80211_rate_get_vht_nss(&info->status.rates[0]); | ||
371 | pos += 4; | ||
372 | |||
373 | /* u8 coding */ | ||
374 | pos++; | ||
375 | /* u8 group_id */ | ||
376 | pos++; | ||
377 | /* u16 partial_aid */ | ||
378 | pos += 2; | ||
379 | } | ||
330 | } | 380 | } |
331 | 381 | ||
332 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | 382 | static void ieee80211_report_used_skb(struct ieee80211_local *local, |
@@ -631,8 +681,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
631 | dev_kfree_skb(skb); | 681 | dev_kfree_skb(skb); |
632 | return; | 682 | return; |
633 | } | 683 | } |
634 | ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len, | 684 | ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count, |
635 | shift); | 685 | rtap_len, shift); |
636 | 686 | ||
637 | /* XXX: is this sufficient for BPF? */ | 687 | /* XXX: is this sufficient for BPF? */ |
638 | skb_set_mac_header(skb, 0); | 688 | skb_set_mac_header(skb, 0); |