aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-11-18 22:20:45 +0000
committerFelix Fietkau <nbd@openwrt.org>2014-11-18 22:20:45 +0000
commit9cd492b3e19ba211791e4433cd25c6ec84288ff6 (patch)
treebccf96000877b7f02f2b2b36475a55fe3718af20 /package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch
parent7b0b8556d8f19bbcb7e0d2ce0e913ab3129eb781 (diff)
downloadupstream-9cd492b3e19ba211791e4433cd25c6ec84288ff6.tar.gz
upstream-9cd492b3e19ba211791e4433cd25c6ec84288ff6.tar.bz2
upstream-9cd492b3e19ba211791e4433cd25c6ec84288ff6.zip
mac80211: add support for reporting tx status without attached skb
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 43297
Diffstat (limited to 'package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch')
-rw-r--r--package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch219
1 files changed, 219 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch b/package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch
new file mode 100644
index 0000000000..18d3905597
--- /dev/null
+++ b/package/kernel/mac80211/patches/318-mac80211-add-ieee80211_tx_status_noskb.patch
@@ -0,0 +1,219 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 15 Nov 2014 23:50:27 +0100
+Subject: [PATCH] mac80211: add ieee80211_tx_status_noskb
+
+This can be used by drivers that cannot reliably map tx status
+information onto specific skbs.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -3517,6 +3517,28 @@ void ieee80211_tx_status(struct ieee8021
+ struct sk_buff *skb);
+
+ /**
++ * ieee80211_tx_status_noskb - transmit status callback without skb
++ *
++ * This function can be used as a replacement for ieee80211_tx_status
++ * in drivers that cannot reliably map tx status information back to
++ * specific skbs.
++ *
++ * This function may not be called in IRQ context. Calls to this function
++ * for a single hardware must be synchronized against each other. Calls
++ * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe()
++ * may not be mixed for a single hardware. Must not run concurrently with
++ * ieee80211_rx() or ieee80211_rx_ni().
++ *
++ * @hw: the hardware the frame was transmitted by
++ * @sta: the receiver station to which this packet is sent
++ * (NULL for multicast packets)
++ * @info: tx status information
++ */
++void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
++ struct ieee80211_sta *sta,
++ struct ieee80211_tx_info *info);
++
++/**
+ * ieee80211_tx_status_ni - transmit status callback (in process context)
+ *
+ * Like ieee80211_tx_status() but can be called in process context.
+--- a/net/mac80211/rate.h
++++ b/net/mac80211/rate.h
+@@ -49,6 +49,23 @@ static inline void rate_control_tx_statu
+ }
+
+
++static inline void
++rate_control_tx_status_noskb(struct ieee80211_local *local,
++ struct ieee80211_supported_band *sband,
++ struct sta_info *sta,
++ struct ieee80211_tx_info *info)
++{
++ struct rate_control_ref *ref = local->rate_ctrl;
++ struct ieee80211_sta *ista = &sta->sta;
++ void *priv_sta = sta->rate_ctrl_priv;
++
++ if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
++ return;
++
++ ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
++}
++
++
+ static inline void rate_control_rate_init(struct sta_info *sta)
+ {
+ struct ieee80211_local *local = sta->sdata->local;
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -541,10 +541,9 @@ static void ieee80211_tx_latency_end_msr
+ #define STA_LOST_TDLS_PKT_THRESHOLD 10
+ #define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */
+
+-static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
++static void ieee80211_lost_packet(struct sta_info *sta,
++ struct ieee80211_tx_info *info)
+ {
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+@@ -571,24 +570,13 @@ static void ieee80211_lost_packet(struct
+ sta->lost_packets = 0;
+ }
+
+-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
++static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
++ struct ieee80211_tx_info *info,
++ int *retry_count)
+ {
+- struct sk_buff *skb2;
+- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+- struct ieee80211_local *local = hw_to_local(hw);
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+- __le16 fc;
+- struct ieee80211_supported_band *sband;
+- struct ieee80211_sub_if_data *sdata;
+- struct net_device *prev_dev = NULL;
+- struct sta_info *sta, *tmp;
+- int retry_count = -1, i;
+ int rates_idx = -1;
+- bool send_to_cooked;
+- bool acked;
+- struct ieee80211_bar *bar;
+- int rtap_len;
+- int shift = 0;
++ int count = -1;
++ int i;
+
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+@@ -606,12 +594,94 @@ void ieee80211_tx_status(struct ieee8021
+ break;
+ }
+
+- retry_count += info->status.rates[i].count;
++ count += info->status.rates[i].count;
+ }
+ rates_idx = i - 1;
+
+- if (retry_count < 0)
+- retry_count = 0;
++ if (count < 0)
++ count = 0;
++
++ *retry_count = count;
++ return rates_idx;
++}
++
++void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
++ struct ieee80211_sta *pubsta,
++ struct ieee80211_tx_info *info)
++{
++ struct ieee80211_local *local = hw_to_local(hw);
++ struct ieee80211_supported_band *sband;
++ int retry_count;
++ int rates_idx;
++ bool acked;
++
++ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
++
++ sband = hw->wiphy->bands[info->band];
++
++ acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
++ if (pubsta) {
++ struct sta_info *sta;
++
++ sta = container_of(pubsta, struct sta_info, sta);
++
++ if (info->flags & IEEE80211_TX_STATUS_EOSP)
++ clear_sta_flag(sta, WLAN_STA_SP);
++
++ if (!acked)
++ sta->tx_retry_failed++;
++ sta->tx_retry_count += retry_count;
++
++ if (acked) {
++ sta->last_rx = jiffies;
++
++ if (sta->lost_packets)
++ sta->lost_packets = 0;
++
++ /* Track when last TDLS packet was ACKed */
++ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
++ sta->last_tdls_pkt_time = jiffies;
++ } else {
++ ieee80211_lost_packet(sta, info);
++ }
++
++ rate_control_tx_status_noskb(local, sband, sta, info);
++ }
++
++ if (acked) {
++ local->dot11TransmittedFrameCount++;
++ if (!pubsta)
++ local->dot11MulticastTransmittedFrameCount++;
++ if (retry_count > 0)
++ local->dot11RetryCount++;
++ if (retry_count > 1)
++ local->dot11MultipleRetryCount++;
++ } else {
++ local->dot11FailedCount++;
++ }
++}
++EXPORT_SYMBOL(ieee80211_tx_status_noskb);
++
++void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
++{
++ struct sk_buff *skb2;
++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
++ struct ieee80211_local *local = hw_to_local(hw);
++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++ __le16 fc;
++ struct ieee80211_supported_band *sband;
++ struct ieee80211_sub_if_data *sdata;
++ struct net_device *prev_dev = NULL;
++ struct sta_info *sta, *tmp;
++ int retry_count;
++ int rates_idx;
++ bool send_to_cooked;
++ bool acked;
++ struct ieee80211_bar *bar;
++ int rtap_len;
++ int shift = 0;
++
++ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
+
+ rcu_read_lock();
+
+@@ -716,7 +786,7 @@ void ieee80211_tx_status(struct ieee8021
+ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+ sta->last_tdls_pkt_time = jiffies;
+ } else {
+- ieee80211_lost_packet(sta, skb);
++ ieee80211_lost_packet(sta, info);
+ }
+ }
+