From 808118cb41dfe12a1ac0e35515ac4d91b170bdf9 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Thu, 10 Mar 2011 16:43:19 -0800 Subject: mac80211: do not enable ps if 802.1x controlled port is unblocked If dynamic_ps is disabled, enabling power save before the 4-way handshake completes may delay the station from being authorized to send/receive traffic, i.e. increase roaming times. It also may result in a failed 4-way handshake depending on the AP's timing requirements and beacon interval, and the station's listen interval. To fix this, prevent power save from being enabled while the station isn't authorized and recalculate power save whenever the station's authorized state changes. Signed-off-by: Jason Young Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 ++++ net/mac80211/mlme.c | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7b701dcddb50..11866b42f1ed 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; } 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; -- cgit v1.2.3 From 3677713b799155c96637cdef3fa025e42f3fcf48 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 7 Mar 2011 16:17:59 -0500 Subject: wireless: add support for ethtool_ops->{get,set}_ringparam Signed-off-by: John W. Linville --- net/wireless/ethtool.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'net') 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 #include +#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, }; -- cgit v1.2.3 From 38c091590f6ed78fcaf114c14ce133e5b3f717e6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 7 Mar 2011 16:19:18 -0500 Subject: mac80211: implement support for cfg80211_ops->{get,set}_ringparam Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 17 +++++++++++++++ net/mac80211/driver-ops.h | 26 +++++++++++++++++++++++ net/mac80211/driver-trace.h | 52 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 11866b42f1ed..334213571ad0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2012,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, @@ -2069,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/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) -- cgit v1.2.3 From cf28d7934c57168d530b606c26ab955a56eb13f9 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 9 Mar 2011 10:02:38 +0100 Subject: mac80211: Shortcut minstrel_ht rate setup for non-MRR capable devices Devices without multi rate retry support won't be able to use all rates as specified by mintrel_ht. Hence, we can simply skip setting up further rates as the devices will only use the first one. Also add a special case for devices with only two possible tx rates. We use sample_rate -> max_prob_rate for sampling and max_tp_rate -> max_prob_rate by default. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel_ht.c | 41 +++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'net') 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++; -- cgit v1.2.3 From 9db372fdd5de9e0464c77a9d3db2a3b356db8668 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 11 Mar 2011 21:45:51 +0100 Subject: mac80211: fix channel type recalculation with HT and non-HT interfaces When running an AP interface along with the cooked monitor interface created by hostapd, adding an interface and deleting it again triggers a channel type recalculation during which the (non-HT) monitor interface takes precedence over the HT AP interface, thus causing the channel type to be set to non-HT. Fix this by ensuring that a more wide channel type will not be overwritten by a less wide channel type. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/chan.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') 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: -- cgit v1.2.3