123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- From: Sven Eckelmann <sven@narfation.org>
- Date: Tue, 26 Jan 2016 17:11:13 +0100
- Subject: [PATCH] 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
- e6a9854b05c1 ("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 <sven@narfation.org>
- Cc: Simon Wunderlich <sw@simonwunderlich.de>
- Signed-off-by: Johannes Berg <johannes.berg@intel.com>
- ---
- --- a/include/net/mac80211.h
- +++ b/include/net/mac80211.h
- @@ -708,12 +708,14 @@ enum mac80211_tx_info_flags {
- * protocol frame (e.g. EAP)
- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
- * frame (PS-Poll or uAPSD).
- + * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
- *
- * These flags are used in tx_info->control.flags.
- */
- enum mac80211_tx_control_flags {
- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
- + IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
- };
-
- /*
- --- a/net/mac80211/tx.c
- +++ b/net/mac80211/tx.c
- @@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
-
- info->control.short_preamble = txrc.short_preamble;
-
- + /* don't ask rate control when rate already injected via radiotap */
- + if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
- + return TX_CONTINUE;
- +
- if (tx->sta)
- assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
-
- @@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub
- ieee80211_tx(sdata, sta, skb, false);
- }
-
- -static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
- +static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
- + struct sk_buff *skb)
- {
- struct ieee80211_radiotap_iterator iterator;
- struct ieee80211_radiotap_header *rthdr =
- (struct ieee80211_radiotap_header *) skb->data;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- + struct ieee80211_supported_band *sband =
- + local->hw.wiphy->bands[info->band];
- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
- NULL);
- u16 txflags;
- + u16 rate = 0;
- + bool rate_found = false;
- + u8 rate_retries = 0;
- + u16 rate_flags = 0;
- + u8 mcs_known, mcs_flags;
- + int i;
-
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
- IEEE80211_TX_CTL_DONTFRAG;
- @@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap(
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
- break;
-
- + case IEEE80211_RADIOTAP_RATE:
- + rate = *iterator.this_arg;
- + rate_flags = 0;
- + rate_found = true;
- + break;
- +
- + case IEEE80211_RADIOTAP_DATA_RETRIES:
- + rate_retries = *iterator.this_arg;
- + break;
- +
- + case IEEE80211_RADIOTAP_MCS:
- + mcs_known = iterator.this_arg[0];
- + mcs_flags = iterator.this_arg[1];
- + if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
- + break;
- +
- + rate_found = true;
- + rate = iterator.this_arg[2];
- + rate_flags = IEEE80211_TX_RC_MCS;
- +
- + if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
- + mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
- + rate_flags |= IEEE80211_TX_RC_SHORT_GI;
- +
- + if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
- + mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
- + rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- + break;
- +
- /*
- * Please update the file
- * Documentation/networking/mac80211-injection.txt
- @@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap(
- if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return false;
-
- + if (rate_found) {
- + info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
- +
- + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- + info->control.rates[i].idx = -1;
- + info->control.rates[i].flags = 0;
- + info->control.rates[i].count = 0;
- + }
- +
- + if (rate_flags & IEEE80211_TX_RC_MCS) {
- + info->control.rates[0].idx = rate;
- + } else {
- + for (i = 0; i < sband->n_bitrates; i++) {
- + if (rate * 5 != sband->bitrates[i].bitrate)
- + continue;
- +
- + info->control.rates[0].idx = i;
- + break;
- + }
- + }
- +
- + info->control.rates[0].flags = rate_flags;
- + info->control.rates[0].count = min_t(u8, rate_retries + 1,
- + local->hw.max_rate_tries);
- + }
- +
- /*
- * remove the radiotap header
- * iterator->_max_length was sanity-checked against
- @@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
- IEEE80211_TX_CTL_INJECTED;
-
- /* process and remove the injection radiotap header */
- - if (!ieee80211_parse_tx_radiotap(skb))
- + if (!ieee80211_parse_tx_radiotap(local, skb))
- goto fail;
-
- rcu_read_lock();
|