mac80211: parse legacy and HT rates in monitor mode injected frames
authorFelix Fietkau <nbd@openwrt.org>
Fri, 5 Feb 2016 16:43:25 +0000 (16:43 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 5 Feb 2016 16:43:25 +0000 (16:43 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 48636

package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch b/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch
new file mode 100644 (file)
index 0000000..c4155a1
--- /dev/null
@@ -0,0 +1,155 @@
+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();