Skip to content

Commit dfdfc2b

Browse files
ecsvjmberg-intel
authored andcommitted
mac80211: Parse legacy and HT rate in injected frames
Drivers/devices without their own rate control algorithm can get the information what rates they should use from either the radiotap header of injected frames or from the rate control algorithm. But the parsing of the legacy rate information from the radiotap header was removed in commit e6a9854 ("mac80211/drivers: rewrite the rate control API"). The removal of this feature heavily reduced the usefulness of frame injection when wanting to simulate specific transmission behavior. Having rate parsing together with MCS rates and retry support allows a fine grained selection of the tx behavior of injected frames for these kind of tests. Signed-off-by: Sven Eckelmann <[email protected]> Cc: Simon Wunderlich <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 3f73fe9 commit dfdfc2b

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

Documentation/networking/mac80211-injection.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ radiotap headers and used to control injection:
2828
IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
2929
an ACK even if it is a unicast frame
3030

31+
* IEEE80211_RADIOTAP_RATE
32+
33+
legacy rate for the transmission (only for devices without own rate control)
34+
35+
* IEEE80211_RADIOTAP_MCS
36+
37+
HT rate for the transmission (only for devices without own rate control).
38+
Also some flags are parsed
39+
40+
IEEE80211_TX_RC_SHORT_GI: use short guard interval
41+
IEEE80211_TX_RC_40_MHZ_WIDTH: send in HT40 mode
42+
43+
* IEEE80211_RADIOTAP_DATA_RETRIES
44+
45+
number of retries when either IEEE80211_RADIOTAP_RATE or
46+
IEEE80211_RADIOTAP_MCS was used
47+
3148
The injection code can also skip all other currently defined radiotap fields
3249
facilitating replay of captured radiotap headers directly.
3350

include/net/mac80211.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,12 +708,14 @@ enum mac80211_tx_info_flags {
708708
* protocol frame (e.g. EAP)
709709
* @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
710710
* frame (PS-Poll or uAPSD).
711+
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
711712
*
712713
* These flags are used in tx_info->control.flags.
713714
*/
714715
enum mac80211_tx_control_flags {
715716
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
716717
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
718+
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
717719
};
718720

719721
/*

net/mac80211/tx.c

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
710710

711711
info->control.short_preamble = txrc.short_preamble;
712712

713+
/* don't ask rate control when rate already injected via radiotap */
714+
if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
715+
return TX_CONTINUE;
716+
713717
if (tx->sta)
714718
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
715719

@@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
16651669
ieee80211_tx(sdata, sta, skb, false);
16661670
}
16671671

1668-
static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
1672+
static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
1673+
struct sk_buff *skb)
16691674
{
16701675
struct ieee80211_radiotap_iterator iterator;
16711676
struct ieee80211_radiotap_header *rthdr =
16721677
(struct ieee80211_radiotap_header *) skb->data;
16731678
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1679+
struct ieee80211_supported_band *sband =
1680+
local->hw.wiphy->bands[info->band];
16741681
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
16751682
NULL);
16761683
u16 txflags;
1684+
u16 rate = 0;
1685+
bool rate_found = false;
1686+
u8 rate_retries = 0;
1687+
u16 rate_flags = 0;
1688+
u8 mcs_known, mcs_flags;
1689+
int i;
16771690

16781691
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
16791692
IEEE80211_TX_CTL_DONTFRAG;
@@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
17241737
info->flags |= IEEE80211_TX_CTL_NO_ACK;
17251738
break;
17261739

1740+
case IEEE80211_RADIOTAP_RATE:
1741+
rate = *iterator.this_arg;
1742+
rate_flags = 0;
1743+
rate_found = true;
1744+
break;
1745+
1746+
case IEEE80211_RADIOTAP_DATA_RETRIES:
1747+
rate_retries = *iterator.this_arg;
1748+
break;
1749+
1750+
case IEEE80211_RADIOTAP_MCS:
1751+
mcs_known = iterator.this_arg[0];
1752+
mcs_flags = iterator.this_arg[1];
1753+
if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
1754+
break;
1755+
1756+
rate_found = true;
1757+
rate = iterator.this_arg[2];
1758+
rate_flags = IEEE80211_TX_RC_MCS;
1759+
1760+
if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
1761+
mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
1762+
rate_flags |= IEEE80211_TX_RC_SHORT_GI;
1763+
1764+
if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
1765+
mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
1766+
rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
1767+
break;
1768+
17271769
/*
17281770
* Please update the file
17291771
* Documentation/networking/mac80211-injection.txt
@@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
17381780
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
17391781
return false;
17401782

1783+
if (rate_found) {
1784+
info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
1785+
1786+
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
1787+
info->control.rates[i].idx = -1;
1788+
info->control.rates[i].flags = 0;
1789+
info->control.rates[i].count = 0;
1790+
}
1791+
1792+
if (rate_flags & IEEE80211_TX_RC_MCS) {
1793+
info->control.rates[0].idx = rate;
1794+
} else {
1795+
for (i = 0; i < sband->n_bitrates; i++) {
1796+
if (rate * 5 != sband->bitrates[i].bitrate)
1797+
continue;
1798+
1799+
info->control.rates[0].idx = i;
1800+
break;
1801+
}
1802+
}
1803+
1804+
info->control.rates[0].flags = rate_flags;
1805+
info->control.rates[0].count = min_t(u8, rate_retries + 1,
1806+
local->hw.max_rate_tries);
1807+
}
1808+
17411809
/*
17421810
* remove the radiotap header
17431811
* iterator->_max_length was sanity-checked against
@@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
18191887
IEEE80211_TX_CTL_INJECTED;
18201888

18211889
/* process and remove the injection radiotap header */
1822-
if (!ieee80211_parse_tx_radiotap(skb))
1890+
if (!ieee80211_parse_tx_radiotap(local, skb))
18231891
goto fail;
18241892

18251893
rcu_read_lock();

0 commit comments

Comments
 (0)