|
@@ -235,7 +235,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
|
|
|
|
|
|
/* IEEE80211_RADIOTAP_RATE rate */
|
|
|
if (info->status.rates[0].idx >= 0 &&
|
|
|
- !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
|
|
|
+ !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS |
|
|
|
+ IEEE80211_TX_RC_VHT_MCS)))
|
|
|
len += 2;
|
|
|
|
|
|
/* IEEE80211_RADIOTAP_TX_FLAGS */
|
|
@@ -244,16 +245,21 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
|
|
|
/* IEEE80211_RADIOTAP_DATA_RETRIES */
|
|
|
len += 1;
|
|
|
|
|
|
- /* IEEE80211_TX_RC_MCS */
|
|
|
- if (info->status.rates[0].idx >= 0 &&
|
|
|
- info->status.rates[0].flags & IEEE80211_TX_RC_MCS)
|
|
|
- len += 3;
|
|
|
+ /* IEEE80211_RADIOTAP_MCS
|
|
|
+ * IEEE80211_RADIOTAP_VHT */
|
|
|
+ if (info->status.rates[0].idx >= 0) {
|
|
|
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS)
|
|
|
+ len += 3;
|
|
|
+ else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS)
|
|
|
+ len = ALIGN(len, 2) + 12;
|
|
|
+ }
|
|
|
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|
|
+ieee80211_add_tx_radiotap_header(struct ieee80211_local *local,
|
|
|
+ struct ieee80211_supported_band *sband,
|
|
|
struct sk_buff *skb, int retry_count,
|
|
|
int rtap_len, int shift)
|
|
|
{
|
|
@@ -280,7 +286,8 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|
|
|
|
|
/* IEEE80211_RADIOTAP_RATE */
|
|
|
if (info->status.rates[0].idx >= 0 &&
|
|
|
- !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
|
|
+ !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS |
|
|
|
+ IEEE80211_TX_RC_VHT_MCS))) {
|
|
|
u16 rate;
|
|
|
|
|
|
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
|
|
@@ -310,9 +317,12 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|
|
*pos = retry_count;
|
|
|
pos++;
|
|
|
|
|
|
- /* IEEE80211_TX_RC_MCS */
|
|
|
- if (info->status.rates[0].idx >= 0 &&
|
|
|
- info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
|
|
|
+ if (info->status.rates[0].idx < 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* IEEE80211_RADIOTAP_MCS
|
|
|
+ * IEEE80211_RADIOTAP_VHT */
|
|
|
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
|
|
|
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
|
|
|
pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
|
|
|
IEEE80211_RADIOTAP_MCS_HAVE_GI |
|
|
@@ -325,8 +335,48 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
|
|
|
pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF;
|
|
|
pos[2] = info->status.rates[0].idx;
|
|
|
pos += 3;
|
|
|
- }
|
|
|
+ } else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
|
|
|
+ u16 known = local->hw.radiotap_vht_details &
|
|
|
+ (IEEE80211_RADIOTAP_VHT_KNOWN_GI |
|
|
|
+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH);
|
|
|
+
|
|
|
+ rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT);
|
|
|
+
|
|
|
+ /* required alignment from rthdr */
|
|
|
+ pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2);
|
|
|
|
|
|
+ /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */
|
|
|
+ put_unaligned_le16(known, pos);
|
|
|
+ pos += 2;
|
|
|
+
|
|
|
+ /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */
|
|
|
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
|
|
|
+ *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
|
|
|
+ pos++;
|
|
|
+
|
|
|
+ /* u8 bandwidth */
|
|
|
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
|
|
+ *pos = 1;
|
|
|
+ else if (info->status.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
|
|
|
+ *pos = 4;
|
|
|
+ else if (info->status.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
|
|
|
+ *pos = 11;
|
|
|
+ else /* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */
|
|
|
+ *pos = 0;
|
|
|
+ pos++;
|
|
|
+
|
|
|
+ /* u8 mcs_nss[4] */
|
|
|
+ *pos = (ieee80211_rate_get_vht_mcs(&info->status.rates[0]) << 4) |
|
|
|
+ ieee80211_rate_get_vht_nss(&info->status.rates[0]);
|
|
|
+ pos += 4;
|
|
|
+
|
|
|
+ /* u8 coding */
|
|
|
+ pos++;
|
|
|
+ /* u8 group_id */
|
|
|
+ pos++;
|
|
|
+ /* u16 partial_aid */
|
|
|
+ pos += 2;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
dev_kfree_skb(skb);
|
|
|
return;
|
|
|
}
|
|
|
- ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len,
|
|
|
- shift);
|
|
|
+ ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
|
|
|
+ rtap_len, shift);
|
|
|
|
|
|
/* XXX: is this sufficient for BPF? */
|
|
|
skb_set_mac_header(skb, 0);
|