blob: 2ab7252662764c932433988bd3c03ef558ab1a6c [file] [log] [blame]
From 3a7f4236d9d089c749bbc4ff537f8ff2437acf2e Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Tue, 12 Mar 2024 11:29:55 +0800
Subject: [PATCH 07/61] sync backports patches/subsys
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
include/net/cfg80211.h | 28 +++++++++++
net/mac80211/cfg.c | 2 +
net/mac80211/debugfs.c | 13 +++++-
net/mac80211/ieee80211_i.h | 4 ++
net/mac80211/main.c | 19 +-------
net/mac80211/mesh.c | 8 +++-
net/mac80211/mesh.h | 31 ++++++++++--
net/mac80211/mesh_pathtbl.c | 19 +++++---
net/mac80211/rc80211_minstrel_ht.c | 75 +++++++-----------------------
net/mac80211/rc80211_minstrel_ht.h | 2 +-
net/mac80211/rx.c | 13 ++++--
net/mac80211/sta_info.c | 29 +++++++-----
net/mac80211/tx.c | 46 +++++++++---------
net/wireless/ap.c | 6 +--
net/wireless/chan.c | 45 ++++++++++++++++++
net/wireless/core.c | 15 ------
net/wireless/core.h | 2 +
net/wireless/mlme.c | 7 +--
net/wireless/sysfs.c | 27 +++++++++--
19 files changed, 240 insertions(+), 151 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0b5799f..4c5daf9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -189,6 +189,8 @@ enum ieee80211_channel_flags {
* @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
+ * @dfs_state_last_available: timestamp (jiffies) of the last time when the
+ * channel was available.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
* @psd: power spectral density (in dBm)
*/
@@ -206,6 +208,7 @@ struct ieee80211_channel {
int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
+ unsigned long dfs_state_last_available;
unsigned int dfs_cac_ms;
s8 psd;
};
@@ -1075,6 +1078,30 @@ int cfg80211_chandef_primary(const struct cfg80211_chan_def *chandef,
enum nl80211_chan_width primary_chan_width,
u16 *punctured);
+/**
+ * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable and we
+ * can/need start CAC on such channel
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ *
+ * Return: true if all channels available and at least
+ * one channel requires CAC (NL80211_DFS_USABLE)
+ */
+bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef);
+
+/**
+ * cfg80211_chandef_dfs_cac_time - get the DFS CAC time (in ms) for given
+ * channel definition
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ *
+ * Returns: DFS CAC time (in ms) which applies for this channel definition
+ */
+unsigned int
+cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef);
+
/**
* nl80211_send_chandef - sends the channel definition.
* @msg: the msg to send channel definition
@@ -3413,6 +3440,7 @@ enum wiphy_params_flags {
/* The per TXQ device queue limit in airtime */
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC 50000
/* The per interface airtime threshold to switch to lower queue limit */
#define IEEE80211_AQL_THRESHOLD 24000
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index db71792..72e64be 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2851,6 +2851,8 @@ static int ieee80211_scan(struct wiphy *wiphy,
*/
fallthrough;
case NL80211_IFTYPE_AP:
+ /* skip check */
+ break;
/*
* If the scan has been forced (and the driver supports
* forcing), don't care about being beaconing already.
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index c660138..f9c5ed8 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -215,11 +215,13 @@ static ssize_t aql_pending_read(struct file *file,
"VI %u us\n"
"BE %u us\n"
"BK %u us\n"
+ "BC/MC %u us\n"
"total %u us\n",
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]),
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]),
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]),
atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]),
+ atomic_read(&local->aql_bc_pending_airtime),
atomic_read(&local->aql_total_pending_airtime));
return simple_read_from_buffer(user_buf, count, ppos,
buf, len);
@@ -245,7 +247,8 @@ static ssize_t aql_txq_limit_read(struct file *file,
"VO %u %u\n"
"VI %u %u\n"
"BE %u %u\n"
- "BK %u %u\n",
+ "BK %u %u\n"
+ "BC/MC %u\n",
local->aql_txq_limit_low[IEEE80211_AC_VO],
local->aql_txq_limit_high[IEEE80211_AC_VO],
local->aql_txq_limit_low[IEEE80211_AC_VI],
@@ -253,7 +256,8 @@ static ssize_t aql_txq_limit_read(struct file *file,
local->aql_txq_limit_low[IEEE80211_AC_BE],
local->aql_txq_limit_high[IEEE80211_AC_BE],
local->aql_txq_limit_low[IEEE80211_AC_BK],
- local->aql_txq_limit_high[IEEE80211_AC_BK]);
+ local->aql_txq_limit_high[IEEE80211_AC_BK],
+ local->aql_txq_limit_bc);
return simple_read_from_buffer(user_buf, count, ppos,
buf, len);
}
@@ -279,6 +283,11 @@ static ssize_t aql_txq_limit_write(struct file *file,
else
buf[count] = '\0';
+ if (sscanf(buf, "mcast %u", &q_limit_low) == 1) {
+ local->aql_txq_limit_bc = q_limit_low;
+ return count;
+ }
+
if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
return -EINVAL;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4827825..c5781c3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -102,6 +102,8 @@ ieee80211_sta_keep_active(struct sta_info *sta, u8 ac)
return time_before_eq(jiffies, sta->airtime[ac].last_active + HZ / 10);
}
+#define AIRTIME_QUANTUM_SHIFT 3
+
struct ieee80211_bss {
u32 device_ts_beacon, device_ts_presp;
@@ -1343,10 +1345,12 @@ struct ieee80211_local {
spinlock_t handle_wake_tx_queue_lock;
u16 airtime_flags;
+ u32 aql_txq_limit_bc;
u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
u32 aql_threshold;
atomic_t aql_total_pending_airtime;
+ atomic_t aql_bc_pending_airtime;
atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
const struct ieee80211_ops *ops;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6518ca5..81a9645 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -944,6 +944,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
spin_lock_init(&local->rx_path_lock);
spin_lock_init(&local->queue_stop_reason_lock);
+ local->aql_txq_limit_bc = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
INIT_LIST_HEAD(&local->active_txqs[i]);
spin_lock_init(&local->active_txq_lock[i]);
@@ -1562,24 +1563,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_add(local);
rate_control_add_debugfs(local);
- rtnl_lock();
- wiphy_lock(hw->wiphy);
-
- /* add one default STA interface if supported */
- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
- !ieee80211_hw_check(hw, NO_AUTO_VIF)) {
- struct vif_params params = {0};
-
- result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL,
- NL80211_IFTYPE_STATION, &params);
- if (result)
- wiphy_warn(local->hw.wiphy,
- "Failed to add default virtual iface\n");
- }
-
- wiphy_unlock(hw->wiphy);
- rtnl_unlock();
-
#ifdef CONFIG_INET
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
result = register_inetaddr_notifier(&local->ifa_notifier);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 32475da..cbc9b5e 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -747,6 +747,9 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 ctrl_flags)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct ieee80211_mesh_fast_tx_key key = {
+ .type = MESH_FAST_TX_TYPE_LOCAL
+ };
struct ieee80211_mesh_fast_tx *entry;
struct ieee80211s_hdr *meshhdr;
u8 sa[ETH_ALEN] __aligned(2);
@@ -782,7 +785,10 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
return false;
}
- entry = mesh_fast_tx_get(sdata, skb->data);
+ ether_addr_copy(key.addr, skb->data);
+ if (!ether_addr_equal(skb->data + ETH_ALEN, sdata->vif.addr))
+ key.type = MESH_FAST_TX_TYPE_PROXIED;
+ entry = mesh_fast_tx_get(sdata, &key);
if (!entry)
return false;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index c472b49..c0c357f 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -134,10 +134,34 @@ struct mesh_path {
#define MESH_FAST_TX_CACHE_THRESHOLD_SIZE 384
#define MESH_FAST_TX_CACHE_TIMEOUT 8000 /* msecs */
+/**
+ * enum ieee80211_mesh_fast_tx_type - cached mesh fast tx entry type
+ *
+ * @MESH_FAST_TX_TYPE_LOCAL: tx from the local vif address as SA
+ * @MESH_FAST_TX_TYPE_PROXIED: local tx with a different SA (e.g. bridged)
+ * @MESH_FAST_TX_TYPE_FORWARDED: forwarded from a different mesh point
+ */
+enum ieee80211_mesh_fast_tx_type {
+ MESH_FAST_TX_TYPE_LOCAL,
+ MESH_FAST_TX_TYPE_PROXIED,
+ MESH_FAST_TX_TYPE_FORWARDED,
+};
+
+/**
+ * struct ieee80211_mesh_fast_tx_key - cached mesh fast tx entry key
+ *
+ * @addr: The Ethernet DA for this entry
+ * @type: cache entry type
+ */
+struct ieee80211_mesh_fast_tx_key {
+ u8 addr[ETH_ALEN] __aligned(2);
+ enum ieee80211_mesh_fast_tx_type type;
+};
+
/**
* struct ieee80211_mesh_fast_tx - cached mesh fast tx entry
* @rhash: rhashtable pointer
- * @addr_key: The Ethernet DA which is the key for this entry
+ * @key: the lookup key for this cache entry
* @fast_tx: base fast_tx data
* @hdr: cached mesh and rfc1042 headers
* @hdrlen: length of mesh + rfc1042
@@ -148,7 +172,7 @@ struct mesh_path {
*/
struct ieee80211_mesh_fast_tx {
struct rhash_head rhash;
- u8 addr_key[ETH_ALEN] __aligned(2);
+ struct ieee80211_mesh_fast_tx_key key;
struct ieee80211_fast_tx fast_tx;
u8 hdr[sizeof(struct ieee80211s_hdr) + sizeof(rfc1042_header)];
@@ -334,7 +358,8 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
struct ieee80211_mesh_fast_tx *
-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr);
+mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mesh_fast_tx_key *key);
bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 ctrl_flags);
void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 91b55d6..93f6a03 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -37,8 +37,8 @@ static const struct rhashtable_params mesh_rht_params = {
static const struct rhashtable_params fast_tx_rht_params = {
.nelem_hint = 10,
.automatic_shrinking = true,
- .key_len = ETH_ALEN,
- .key_offset = offsetof(struct ieee80211_mesh_fast_tx, addr_key),
+ .key_len = sizeof(struct ieee80211_mesh_fast_tx_key),
+ .key_offset = offsetof(struct ieee80211_mesh_fast_tx, key),
.head_offset = offsetof(struct ieee80211_mesh_fast_tx, rhash),
.hashfn = mesh_table_hash,
};
@@ -431,20 +431,21 @@ static void mesh_fast_tx_entry_free(struct mesh_tx_cache *cache,
}
struct ieee80211_mesh_fast_tx *
-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr)
+mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mesh_fast_tx_key *key)
{
struct ieee80211_mesh_fast_tx *entry;
struct mesh_tx_cache *cache;
cache = &sdata->u.mesh.tx_cache;
- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
+ entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
if (!entry)
return NULL;
if (!(entry->mpath->flags & MESH_PATH_ACTIVE) ||
mpath_expired(entry->mpath)) {
spin_lock_bh(&cache->walk_lock);
- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
+ entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
if (entry)
mesh_fast_tx_entry_free(cache, entry);
spin_unlock_bh(&cache->walk_lock);
@@ -489,18 +490,24 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
if (!sta)
return;
+ build.key.type = MESH_FAST_TX_TYPE_LOCAL;
if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) {
/* This is required to keep the mppath alive */
mppath = mpp_path_lookup(sdata, meshhdr->eaddr1);
if (!mppath)
return;
build.mppath = mppath;
+ if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr))
+ build.key.type = MESH_FAST_TX_TYPE_PROXIED;
} else if (ieee80211_has_a4(hdr->frame_control)) {
mppath = mpath;
} else {
return;
}
+ if (!ether_addr_equal(hdr->addr4, sdata->vif.addr))
+ build.key.type = MESH_FAST_TX_TYPE_FORWARDED;
+
/* rate limit, in case fast xmit can't be enabled */
if (mppath->fast_tx_check == jiffies)
return;
@@ -547,7 +554,7 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
}
}
- memcpy(build.addr_key, mppath->dst, ETH_ALEN);
+ memcpy(build.key.addr, mppath->dst, ETH_ALEN);
build.timestamp = jiffies;
build.fast_tx.band = info->band;
build.fast_tx.da_offs = offsetof(struct ieee80211_hdr, addr3);
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 62f323a..74413d7 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -582,6 +582,14 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 *dest, u16 index)
int cur_tp_avg, cur_group, cur_idx;
int max_gpr_group, max_gpr_idx;
int max_gpr_tp_avg, max_gpr_prob;
+ int min_dur;
+
+ min_dur = max(minstrel_get_duration(mi->max_tp_rate[0]),
+ minstrel_get_duration(mi->max_tp_rate[1]));
+
+ /* make the rate at least 18% slower than max tp rates */
+ if (minstrel_get_duration(index) <= min_dur * 19 / 16)
+ return;
cur_group = MI_RATE_GROUP(index);
cur_idx = MI_RATE_IDX(index);
@@ -603,11 +611,6 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 *dest, u16 index)
!minstrel_ht_is_legacy_group(max_tp_group))
return;
- /* skip rates faster than max tp rate with lower prob */
- if (minstrel_get_duration(mi->max_tp_rate[0]) > minstrel_get_duration(index) &&
- mrs->prob_avg < max_tp_prob)
- return;
-
max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate);
max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate);
max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
@@ -665,40 +668,6 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
}
-/*
- * Try to increase robustness of max_prob rate by decrease number of
- * streams if possible.
- */
-static inline void
-minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
-{
- struct minstrel_mcs_group_data *mg;
- int tmp_max_streams, group, tmp_idx, tmp_prob;
- int tmp_tp = 0;
-
- if (!mi->sta->deflink.ht_cap.ht_supported)
- return;
-
- group = MI_RATE_GROUP(mi->max_tp_rate[0]);
- tmp_max_streams = minstrel_mcs_groups[group].streams;
- for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
- mg = &mi->groups[group];
- if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
- continue;
-
- tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate);
- tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
-
- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
- (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
- mi->max_prob_rate = mg->max_group_prob_rate;
- tmp_tp = minstrel_ht_get_tp_avg(mi, group,
- tmp_idx,
- tmp_prob);
- }
- }
-}
-
static u16
__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
enum minstrel_sample_type type)
@@ -771,7 +740,8 @@ minstrel_ht_calc_rate_stats(struct minstrel_priv *mp,
unsigned int cur_prob;
if (unlikely(mrs->attempts > 0)) {
- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
+ cur_prob = MINSTREL_FRAC(mrs->success + mrs->last_success,
+ mrs->attempts + mrs->last_attempts);
minstrel_filter_avg_add(&mrs->prob_avg,
&mrs->prob_avg_1, cur_prob);
mrs->att_hist += mrs->attempts;
@@ -1177,8 +1147,6 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
mi->max_prob_rate = tmp_max_prob_rate;
- /* Try to increase robustness of max_prob_rate*/
- minstrel_ht_prob_rate_reduce_streams(mi);
minstrel_ht_refill_sample_rates(mi);
#ifdef CPTCFG_MAC80211_DEBUGFS
@@ -1257,7 +1225,7 @@ minstrel_ht_ri_txstat_valid(struct minstrel_priv *mp,
}
static void
-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
+minstrel_downgrade_prob_rate(struct minstrel_ht_sta *mi, u16 *idx)
{
int group, orig_group;
@@ -1272,11 +1240,7 @@ minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
minstrel_mcs_groups[orig_group].streams)
continue;
- if (primary)
- *idx = mi->groups[group].max_group_tp_rate[0];
- else
- *idx = mi->groups[group].max_group_tp_rate[1];
- break;
+ *idx = mi->groups[group].max_group_prob_rate;
}
}
@@ -1287,7 +1251,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_tx_info *info = st->info;
struct minstrel_ht_sta *mi = priv_sta;
struct ieee80211_tx_rate *ar = info->status.rates;
- struct minstrel_rate_stats *rate, *rate2;
+ struct minstrel_rate_stats *rate;
struct minstrel_priv *mp = priv;
u32 update_interval = mp->update_interval;
bool last, update = false;
@@ -1355,18 +1319,13 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
/*
* check for sudden death of spatial multiplexing,
* downgrade to a lower number of streams if necessary.
+ * only do this for the max_prob_rate to prevent spurious
+ * rate fluctuations when the link changes suddenly
*/
- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
+ rate = minstrel_get_ratestats(mi, mi->max_prob_rate);
if (rate->attempts > 30 &&
rate->success < rate->attempts / 4) {
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
- update = true;
- }
-
- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
- if (rate2->attempts > 30 &&
- rate2->success < rate2->attempts / 4) {
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
+ minstrel_downgrade_prob_rate(mi, &mi->max_prob_rate);
update = true;
}
}
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index f385cf6..1f78a94 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -14,7 +14,7 @@
/* scaled fraction values */
#define MINSTREL_SCALE 12
-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / (div))
#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 42ffd1e..be724c2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2767,7 +2767,10 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int hdrlen)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct ieee80211_mesh_fast_tx *entry = NULL;
+ struct ieee80211_mesh_fast_tx_key key = {
+ .type = MESH_FAST_TX_TYPE_FORWARDED
+ };
+ struct ieee80211_mesh_fast_tx *entry;
struct ieee80211s_hdr *mesh_hdr;
struct tid_ampdu_tx *tid_tx;
struct sta_info *sta;
@@ -2776,9 +2779,13 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
- entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1);
+ ether_addr_copy(key.addr, mesh_hdr->eaddr1);
else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
- entry = mesh_fast_tx_get(sdata, skb->data);
+ ether_addr_copy(key.addr, skb->data);
+ else
+ return false;
+
+ entry = mesh_fast_tx_get(sdata, &key);
if (!entry)
return false;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 32d050c..411a610 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -912,6 +912,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_accept_plinks_update(sdata);
+ ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_xmit(sta);
@@ -2354,28 +2355,27 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
struct sta_info *sta, u8 ac,
u16 tx_airtime, bool tx_completed)
{
+ atomic_t *counter;
int tx_pending;
if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
return;
- if (!tx_completed) {
- if (sta)
- atomic_add(tx_airtime,
- &sta->airtime[ac].aql_tx_pending);
+ if (sta)
+ counter = &sta->airtime[ac].aql_tx_pending;
+ else
+ counter = &local->aql_bc_pending_airtime;
+ if (!tx_completed) {
+ atomic_add(tx_airtime, counter);
atomic_add(tx_airtime, &local->aql_total_pending_airtime);
atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
return;
}
- if (sta) {
- tx_pending = atomic_sub_return(tx_airtime,
- &sta->airtime[ac].aql_tx_pending);
- if (tx_pending < 0)
- atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending,
- tx_pending, 0);
- }
+ tx_pending = atomic_sub_return(tx_airtime, counter);
+ if (tx_pending < 0)
+ atomic_cmpxchg(counter, tx_pending, 0);
atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
tx_pending = atomic_sub_return(tx_airtime,
@@ -2439,6 +2439,13 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
sband = local->hw.wiphy->bands[band];
+ if (!sband) {
+ wiphy_warn(local->hw.wiphy,
+ "Invalid band %d\n",
+ band);
+ break;
+ }
+
if (WARN_ON_ONCE(!sband->bitrates))
break;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 141b094..f479d87 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3978,9 +3978,8 @@ begin:
encap_out:
info->control.vif = vif;
- if (tx.sta &&
- wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
- bool ampdu = txq->ac != IEEE80211_AC_VO;
+ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
+ bool ampdu = txq->sta && txq->ac != IEEE80211_AC_VO;
u32 airtime;
airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
@@ -4043,6 +4042,7 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
struct ieee80211_txq *ret = NULL;
struct txq_info *txqi = NULL, *head = NULL;
bool found_eligible_txq = false;
+ bool aql_check;
spin_lock_bh(&local->active_txq_lock[ac]);
@@ -4066,26 +4066,26 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
if (!head)
head = txqi;
+ aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
+ if (aql_check)
+ found_eligible_txq = true;
+
if (txqi->txq.sta) {
struct sta_info *sta = container_of(txqi->txq.sta,
struct sta_info, sta);
- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
- s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac);
-
- if (aql_check)
- found_eligible_txq = true;
-
- if (deficit < 0)
+ if (ieee80211_sta_deficit(sta, txqi->txq.ac) < 0) {
sta->airtime[txqi->txq.ac].deficit +=
- sta->airtime_weight;
-
- if (deficit < 0 || !aql_check) {
- list_move_tail(&txqi->schedule_order,
- &local->active_txqs[txqi->txq.ac]);
- goto begin;
+ sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
+ aql_check = false;
}
}
+ if (!aql_check) {
+ list_move_tail(&txqi->schedule_order,
+ &local->active_txqs[txqi->txq.ac]);
+ goto begin;
+ }
+
if (txqi->schedule_round == local->schedule_round[ac])
goto out;
@@ -4150,7 +4150,8 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
return true;
if (!txq->sta)
- return true;
+ return atomic_read(&local->aql_bc_pending_airtime) <
+ local->aql_txq_limit_bc;
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
return true;
@@ -4199,15 +4200,15 @@ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
spin_lock_bh(&local->active_txq_lock[ac]);
- if (!txqi->txq.sta)
- goto out;
-
if (list_empty(&txqi->schedule_order))
goto out;
if (!ieee80211_txq_schedule_airtime_check(local, ac))
goto out;
+ if (!txqi->txq.sta)
+ goto out;
+
list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
schedule_order) {
if (iter == txqi)
@@ -4220,7 +4221,8 @@ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
}
sta = container_of(iter->txq.sta, struct sta_info, sta);
if (ieee80211_sta_deficit(sta, ac) < 0)
- sta->airtime[ac].deficit += sta->airtime_weight;
+ sta->airtime[ac].deficit += sta->airtime_weight <<
+ AIRTIME_QUANTUM_SHIFT;
list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
}
@@ -4228,7 +4230,7 @@ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
if (sta->airtime[ac].deficit >= 0)
goto out;
- sta->airtime[ac].deficit += sta->airtime_weight;
+ sta->airtime[ac].deficit += sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
spin_unlock_bh(&local->active_txq_lock[ac]);
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index 9a9a870..9cd0ab4 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -30,6 +30,9 @@ static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
if (!wdev->links[link_id].ap.beacon_interval)
return -ENOENT;
+ cfg80211_update_last_available(wdev->wiphy,
+ &wdev->links[link_id].ap.chandef);
+
err = rdev_stop_ap(rdev, dev, link_id);
if (!err) {
wdev->conn_owner_nlportid = 0;
@@ -41,9 +44,6 @@ static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
if (notify)
nl80211_send_ap_stopped(wdev, link_id);
- /* Should we apply the grace period during beaconing interface
- * shutdown also?
- */
cfg80211_sched_dfs_chan_update(rdev);
}
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 14c27bc..4bac395 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -560,6 +560,8 @@ static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
c->dfs_state = dfs_state;
c->dfs_state_entered = jiffies;
+ if (dfs_state == NL80211_DFS_AVAILABLE)
+ c->dfs_state_last_available = jiffies;
}
}
@@ -1049,6 +1051,49 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
return true;
}
+static void
+__cfg80211_update_last_available(struct wiphy *wiphy,
+ u32 center_freq,
+ u32 bandwidth)
+{
+ struct ieee80211_channel *c;
+ u32 freq, start_freq, end_freq;
+
+ start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+ end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+ /*
+ * Check entire range of channels for the bandwidth.
+ * If any channel in between is disabled or has not
+ * had gone through CAC return false
+ */
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
+ if (!c)
+ return;
+
+ c->dfs_state_last_available = jiffies;
+ }
+}
+
+void cfg80211_update_last_available(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef)
+{
+ int width;
+
+ width = cfg80211_chandef_get_width(chandef);
+ if (width < 0)
+ return;
+
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1),
+ width);
+ if (chandef->width != NL80211_CHAN_WIDTH_80P80)
+ return;
+
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2),
+ width);
+}
+
static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 0cd5c78..ac9417e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -662,21 +662,6 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
c->limits[j].max > 1))
return -EINVAL;
- /*
- * This isn't well-defined right now. If you have an
- * IBSS interface, then its beacon interval may change
- * by joining other networks, and nothing prevents it
- * from doing that.
- * So technically we probably shouldn't even allow AP
- * and IBSS in the same interface, but it seems that
- * some drivers support that, possibly only with fixed
- * beacon intervals for IBSS.
- */
- if (WARN_ON(types & BIT(NL80211_IFTYPE_ADHOC) &&
- c->beacon_int_min_gcd)) {
- return -EINVAL;
- }
-
cnt += c->limits[j].max;
/*
* Don't advertise an unsupported type
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 2e19279..7bef6b0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -467,6 +467,8 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
enum nl80211_dfs_state dfs_state);
void cfg80211_dfs_channels_update_work(struct work_struct *work);
+void cfg80211_update_last_available(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef);
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 3b0fe7c..c7e62eb 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -1037,6 +1037,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
radar_event = NL80211_RADAR_NOP_FINISHED;
+ timeout = c->dfs_state_entered +
+ msecs_to_jiffies(time_dfs_update);
} else {
if (regulatory_pre_cac_allowed(wiphy) ||
cfg80211_any_wiphy_oper_chan(wiphy, c))
@@ -1044,11 +1046,10 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
+ timeout = c->dfs_state_last_available +
+ msecs_to_jiffies(time_dfs_update);
}
- timeout = c->dfs_state_entered +
- msecs_to_jiffies(time_dfs_update);
-
if (time_after_eq(jiffies, timeout)) {
c->dfs_state = NL80211_DFS_USABLE;
c->dfs_state_entered = jiffies;
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 1387106..49aac4c 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -24,18 +24,35 @@ static inline struct cfg80211_registered_device *dev_to_rdev(
return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
}
-#define SHOW_FMT(name, fmt, member) \
+#define SHOW_FMT(name, fmt, member, mode) \
static ssize_t name ## _show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \
} \
-static DEVICE_ATTR_RO(name)
+static DEVICE_ATTR_##mode(name)
-SHOW_FMT(index, "%d", wiphy_idx);
-SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
-SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
+static ssize_t macaddress_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ u8 mac[ETH_ALEN];
+
+ if (!mac_pton(buf, mac))
+ return -EINVAL;
+
+ if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
+ return -EINVAL;
+
+ memcpy(dev_to_rdev(dev)->wiphy.perm_addr, mac, ETH_ALEN);
+
+ return strnlen(buf, len);
+}
+
+SHOW_FMT(index, "%d", wiphy_idx, RO);
+SHOW_FMT(macaddress, "%pM", wiphy.perm_addr, RW);
+SHOW_FMT(address_mask, "%pM", wiphy.addr_mask, RO);
static ssize_t name_show(struct device *dev,
struct device_attribute *attr,
--
2.39.2