summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c21
-rw-r--r--net/mac80211/chan.c3
-rw-r--r--net/mac80211/driver-ops.h26
-rw-r--r--net/mac80211/driver-trace.h52
-rw-r--r--net/mac80211/mlme.c37
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c41
-rw-r--r--net/wireless/ethtool.c33
7 files changed, 201 insertions, 12 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7b701dcddb50..334213571ad0 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -834,6 +834,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
rcu_read_unlock();
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))
+ ieee80211_recalc_ps(local, -1);
+
return 0;
}
@@ -2008,6 +2012,21 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
return drv_get_antenna(local, tx_ant, rx_ant);
}
+static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ return drv_set_ringparam(local, tx, rx);
+}
+
+static void ieee80211_get_ringparam(struct wiphy *wiphy,
+ u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ drv_get_ringparam(local, tx, tx_max, rx, rx_max);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -2065,4 +2084,6 @@ struct cfg80211_ops mac80211_config_ops = {
.mgmt_frame_register = ieee80211_mgmt_frame_register,
.set_antenna = ieee80211_set_antenna,
.get_antenna = ieee80211_get_antenna,
+ .set_ringparam = ieee80211_set_ringparam,
+ .get_ringparam = ieee80211_get_ringparam,
};
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 5b24740fc0b0..889c3e93e0f4 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -77,6 +77,9 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
switch (tmp->vif.bss_conf.channel_type) {
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
+ if (superchan > tmp->vif.bss_conf.channel_type)
+ break;
+
superchan = tmp->vif.bss_conf.channel_type;
break;
case NL80211_CHAN_HT40PLUS:
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 3729296f6f95..9c0d62bb0ea3 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -526,4 +526,30 @@ static inline int drv_offchannel_tx_cancel_wait(struct ieee80211_local *local)
return ret;
}
+static inline int drv_set_ringparam(struct ieee80211_local *local,
+ u32 tx, u32 rx)
+{
+ int ret = -ENOTSUPP;
+
+ might_sleep();
+
+ trace_drv_set_ringparam(local, tx, rx);
+ if (local->ops->set_ringparam)
+ ret = local->ops->set_ringparam(&local->hw, tx, rx);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
+static inline void drv_get_ringparam(struct ieee80211_local *local,
+ u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
+{
+ might_sleep();
+
+ trace_drv_get_ringparam(local, tx, tx_max, rx, rx_max);
+ if (local->ops->get_ringparam)
+ local->ops->get_ringparam(&local->hw, tx, tx_max, rx, rx_max);
+ trace_drv_return_void(local);
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 520fe2444893..45aab80738e2 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -912,6 +912,58 @@ TRACE_EVENT(drv_offchannel_tx,
)
);
+TRACE_EVENT(drv_set_ringparam,
+ TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
+
+ TP_ARGS(local, tx, rx),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, tx)
+ __field(u32, rx)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->tx = tx;
+ __entry->rx = rx;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " tx:%d rx %d",
+ LOCAL_PR_ARG, __entry->tx, __entry->rx
+ )
+);
+
+TRACE_EVENT(drv_get_ringparam,
+ TP_PROTO(struct ieee80211_local *local, u32 *tx, u32 *tx_max,
+ u32 *rx, u32 *rx_max),
+
+ TP_ARGS(local, tx, tx_max, rx, rx_max),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, tx)
+ __field(u32, tx_max)
+ __field(u32, rx)
+ __field(u32, rx_max)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->tx = *tx;
+ __entry->tx_max = *tx_max;
+ __entry->rx = *rx;
+ __entry->rx_max = *rx_max;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " tx:%d tx_max %d rx %d rx_max %d",
+ LOCAL_PR_ARG,
+ __entry->tx, __entry->tx_max, __entry->rx, __entry->rx_max
+ )
+);
+
DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cc984bd861cf..64d92d5a7f40 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -613,6 +613,37 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
}
}
+static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_managed *mgd = &sdata->u.mgd;
+ struct sta_info *sta = NULL;
+ u32 sta_flags = 0;
+
+ if (!mgd->powersave)
+ return false;
+
+ if (!mgd->associated)
+ return false;
+
+ if (!mgd->associated->beacon_ies)
+ return false;
+
+ if (mgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
+ return false;
+
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgd->bssid);
+ if (sta)
+ sta_flags = get_sta_flags(sta);
+ rcu_read_unlock();
+
+ if (!(sta_flags & WLAN_STA_AUTHORIZED))
+ return false;
+
+ return true;
+}
+
/* need to hold RTNL or interface lock */
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
{
@@ -647,11 +678,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
count++;
}
- if (count == 1 && found->u.mgd.powersave &&
- found->u.mgd.associated &&
- found->u.mgd.associated->beacon_ies &&
- !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
- IEEE80211_STA_CONNECTION_POLL))) {
+ if (count == 1 && ieee80211_powersave_allowed(found)) {
struct ieee80211_conf *conf = &local->hw.conf;
s32 beaconint_us;
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index bce14fbfc3b6..8212a8bebf06 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -598,19 +598,46 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
sample = true;
minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
txrc, true, false);
- minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
- txrc, false, false);
info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
txrc, false, false);
- minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
- txrc, false, true);
}
- minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, !sample);
- ar[3].count = 0;
- ar[3].idx = -1;
+ if (mp->hw->max_rates >= 3) {
+ /*
+ * At least 3 tx rates supported, use
+ * sample_rate -> max_tp_rate -> max_prob_rate for sampling and
+ * max_tp_rate -> max_tp_rate2 -> max_prob_rate by default.
+ */
+ if (sample_idx >= 0)
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
+ txrc, false, false);
+ else
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
+ txrc, false, true);
+
+ minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate,
+ txrc, false, !sample);
+
+ ar[3].count = 0;
+ ar[3].idx = -1;
+ } else if (mp->hw->max_rates == 2) {
+ /*
+ * Only 2 tx rates supported, use
+ * sample_rate -> max_prob_rate for sampling and
+ * max_tp_rate -> max_prob_rate by default.
+ */
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate,
+ txrc, false, !sample);
+
+ ar[2].count = 0;
+ ar[2].idx = -1;
+ } else {
+ /* Not using MRR, only use the first rate */
+ ar[1].count = 0;
+ ar[1].idx = -1;
+ }
mi->total_packets++;
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c
index ca4c825be93d..9bde4d1d3e9b 100644
--- a/net/wireless/ethtool.c
+++ b/net/wireless/ethtool.c
@@ -1,5 +1,6 @@
#include <linux/utsname.h>
#include <net/cfg80211.h>
+#include "core.h"
#include "ethtool.h"
static void cfg80211_get_drvinfo(struct net_device *dev,
@@ -37,9 +38,41 @@ static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs->len = 0;
}
+static void cfg80211_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *rp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+ memset(rp, 0, sizeof(*rp));
+
+ if (rdev->ops->get_ringparam)
+ rdev->ops->get_ringparam(wdev->wiphy,
+ &rp->tx_pending, &rp->tx_max_pending,
+ &rp->rx_pending, &rp->rx_max_pending);
+}
+
+static int cfg80211_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *rp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+ if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0)
+ return -EINVAL;
+
+ if (rdev->ops->set_ringparam)
+ return rdev->ops->set_ringparam(wdev->wiphy,
+ rp->tx_pending, rp->rx_pending);
+
+ return -ENOTSUPP;
+}
+
const struct ethtool_ops cfg80211_ethtool_ops = {
.get_drvinfo = cfg80211_get_drvinfo,
.get_regs_len = cfg80211_get_regs_len,
.get_regs = cfg80211_get_regs,
.get_link = ethtool_op_get_link,
+ .get_ringparam = cfg80211_get_ringparam,
+ .set_ringparam = cfg80211_set_ringparam,
};