220 lines
6.3 KiB
Diff
220 lines
6.3 KiB
Diff
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);
|
|
}
|
|
}
|
|
|