aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2016-01-26 11:11:13 -0500
committerJohannes Berg <johannes.berg@intel.com>2016-02-24 03:04:30 -0500
commitdfdfc2beb0dd7e3a067d2eeacb4623cb48e77658 (patch)
tree68171d12c6bd64d08b39beda5e27aac1c44eb696
parent3f73fe9fd8703123faf663908923ca9e62cb984e (diff)
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>
-rw-r--r--Documentation/networking/mac80211-injection.txt17
-rw-r--r--include/net/mac80211.h2
-rw-r--r--net/mac80211/tx.c72
3 files changed, 89 insertions, 2 deletions
diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt
index 3a930072b161..ec8f934c2eb2 100644
--- a/Documentation/networking/mac80211-injection.txt
+++ b/Documentation/networking/mac80211-injection.txt
@@ -28,6 +28,23 @@ radiotap headers and used to control injection:
28 IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for 28 IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
29 an ACK even if it is a unicast frame 29 an ACK even if it is a unicast frame
30 30
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
31The injection code can also skip all other currently defined radiotap fields 48The injection code can also skip all other currently defined radiotap fields
32facilitating replay of captured radiotap headers directly. 49facilitating replay of captured radiotap headers directly.
33 50
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 31337f81ec03..dbcd69a6bfda 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -708,12 +708,14 @@ enum mac80211_tx_info_flags {
708 * protocol frame (e.g. EAP) 708 * protocol frame (e.g. EAP)
709 * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll 709 * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
710 * frame (PS-Poll or uAPSD). 710 * frame (PS-Poll or uAPSD).
711 * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
711 * 712 *
712 * These flags are used in tx_info->control.flags. 713 * These flags are used in tx_info->control.flags.
713 */ 714 */
714enum mac80211_tx_control_flags { 715enum mac80211_tx_control_flags {
715 IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), 716 IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
716 IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), 717 IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
718 IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
717}; 719};
718 720
719/* 721/*
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3311ce0f3d6c..723cd7aa8953 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
710 710
711 info->control.short_preamble = txrc.short_preamble; 711 info->control.short_preamble = txrc.short_preamble;
712 712
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
713 if (tx->sta) 717 if (tx->sta)
714 assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); 718 assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
715 719
@@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
1665 ieee80211_tx(sdata, sta, skb, false); 1669 ieee80211_tx(sdata, sta, skb, false);
1666} 1670}
1667 1671
1668static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) 1672static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
1673 struct sk_buff *skb)
1669{ 1674{
1670 struct ieee80211_radiotap_iterator iterator; 1675 struct ieee80211_radiotap_iterator iterator;
1671 struct ieee80211_radiotap_header *rthdr = 1676 struct ieee80211_radiotap_header *rthdr =
1672 (struct ieee80211_radiotap_header *) skb->data; 1677 (struct ieee80211_radiotap_header *) skb->data;
1673 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1678 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1679 struct ieee80211_supported_band *sband =
1680 local->hw.wiphy->bands[info->band];
1674 int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, 1681 int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
1675 NULL); 1682 NULL);
1676 u16 txflags; 1683 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;
1677 1690
1678 info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | 1691 info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
1679 IEEE80211_TX_CTL_DONTFRAG; 1692 IEEE80211_TX_CTL_DONTFRAG;
@@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
1724 info->flags |= IEEE80211_TX_CTL_NO_ACK; 1737 info->flags |= IEEE80211_TX_CTL_NO_ACK;
1725 break; 1738 break;
1726 1739
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
1727 /* 1769 /*
1728 * Please update the file 1770 * Please update the file
1729 * Documentation/networking/mac80211-injection.txt 1771 * Documentation/networking/mac80211-injection.txt
@@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
1738 if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ 1780 if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
1739 return false; 1781 return false;
1740 1782
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
1741 /* 1809 /*
1742 * remove the radiotap header 1810 * remove the radiotap header
1743 * iterator->_max_length was sanity-checked against 1811 * iterator->_max_length was sanity-checked against
@@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
1819 IEEE80211_TX_CTL_INJECTED; 1887 IEEE80211_TX_CTL_INJECTED;
1820 1888
1821 /* process and remove the injection radiotap header */ 1889 /* process and remove the injection radiotap header */
1822 if (!ieee80211_parse_tx_radiotap(skb)) 1890 if (!ieee80211_parse_tx_radiotap(local, skb))
1823 goto fail; 1891 goto fail;
1824 1892
1825 rcu_read_lock(); 1893 rcu_read_lock();