From: Ben Greear <greearb@xxxxxxxxxxxxxxx> The ieee80211_cfg_on_oper_channel method compared the current hardware config as well as the desired hardware config. In most cases, this is proper, but when deciding whether to go back on-channel, if the hardware is not configured on-channel, but logically it *should* be on-channel, then we must go on-channel. This patch adds a flag to the ieee80211_cfg_on_oper_channel logic to disable comparing the actual hardware so we do not have to create another tricky method with similar logic. Reported-by: Eliad Peller <eliad@xxxxxxxxxx> Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx> --- NOTE: This is tricky stuff, please do not apply until at least Johannes gets time to review this. :100644 100644 4c3d1f5... 40ca484... M net/mac80211/ieee80211_i.h :100644 100644 d4ee6d2... 3ead637... M net/mac80211/main.c :100644 100644 397343a... d1b6b29... M net/mac80211/scan.c :100644 100644 bf5be22... 62a3357... M net/mac80211/work.c net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/main.c | 13 ++++++++----- net/mac80211/scan.c | 10 +++++----- net/mac80211/work.c | 11 +++++++---- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4c3d1f5..40ca484 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1139,7 +1139,8 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); void ieee80211_sched_scan_stopped_work(struct work_struct *work); /* off-channel helpers */ -bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); +bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local, + bool check_current_hw_cfg); void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, bool tell_ap); void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d4ee6d2..3ead637 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -94,11 +94,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work) /* * Returns true if we are logically configured to be on - * the operating channel AND the hardware-conf is currently - * configured on the operating channel. Compares channel-type + * the operating channel and channel-type. + * If the check_current_hw_cfg argument is TRUE, + * the currently configured hardware value is checked * as well. */ -bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local) +bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local, + bool check_current_hw_cfg) { struct ieee80211_channel *chan, *scan_chan; enum nl80211_channel_type channel_type; @@ -126,8 +128,9 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local) return false; /* Check current hardware-config against oper_channel. */ - if ((local->oper_channel != local->hw.conf.channel) || - (local->_oper_channel_type != local->hw.conf.channel_type)) + if (check_current_hw_cfg && + ((local->oper_channel != local->hw.conf.channel) || + (local->_oper_channel_type != local->hw.conf.channel_type))) return false; return true; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 397343a..d1b6b29 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -216,7 +216,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) * current channel, pass the pkt on up the stack so that * the rest of the stack can make use of it. */ - if (ieee80211_cfg_on_oper_channel(sdata->local) + if (ieee80211_cfg_on_oper_channel(sdata->local, true) && (channel == sdata->local->oper_channel)) return RX_CONTINUE; @@ -297,7 +297,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, local->scanning = 0; local->scan_channel = NULL; - on_oper_chan = ieee80211_cfg_on_oper_channel(local); + on_oper_chan = ieee80211_cfg_on_oper_channel(local, true); if (was_hw_scan || !on_oper_chan) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); @@ -309,7 +309,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, bool on_oper_chan2; ieee80211_configure_filter(local); drv_sw_scan_complete(local); - on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); + on_oper_chan2 = ieee80211_cfg_on_oper_channel(local, true); /* We should always be on-channel at this point. */ WARN_ON(!on_oper_chan2); if (on_oper_chan2 && (on_oper_chan != on_oper_chan2)) @@ -509,7 +509,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, next_chan = local->scan_req->channels[local->scan_channel_idx]; - if (ieee80211_cfg_on_oper_channel(local)) { + if (ieee80211_cfg_on_oper_channel(local, true)) { /* We're currently on operating channel. */ if (next_chan == local->oper_channel) /* We don't need to move off of operating channel. */ @@ -587,7 +587,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca { /* switch back to the operating channel */ local->scan_channel = NULL; - if (!ieee80211_cfg_on_oper_channel(local)) + if (!ieee80211_cfg_on_oper_channel(local, true)) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); /* diff --git a/net/mac80211/work.c b/net/mac80211/work.c index bf5be22..62a3357 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -973,7 +973,8 @@ static void ieee80211_work_work(struct work_struct *work) bool tmp_chan_changed = false; bool on_oper_chan2; enum nl80211_channel_type wk_ct; - on_oper_chan = ieee80211_cfg_on_oper_channel(local); + on_oper_chan = ieee80211_cfg_on_oper_channel(local, + true); /* Work with existing channel type if possible. */ wk_ct = wk->chan_type; @@ -993,7 +994,8 @@ static void ieee80211_work_work(struct work_struct *work) * happen to be on the same channel as * the requested channel. */ - on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); + on_oper_chan2 = ieee80211_cfg_on_oper_channel(local, + true); if (on_oper_chan != on_oper_chan2) { if (on_oper_chan2) { /* going off oper channel, PS too */ @@ -1091,7 +1093,7 @@ static void ieee80211_work_work(struct work_struct *work) } if (!remain_off_channel && local->tmp_channel) { - bool on_oper_chan = ieee80211_cfg_on_oper_channel(local); + bool on_oper_chan = ieee80211_cfg_on_oper_channel(local, true); local->tmp_channel = NULL; /* If tmp_channel wasn't operating channel, then * we need to go back on-channel. @@ -1101,7 +1103,8 @@ static void ieee80211_work_work(struct work_struct *work) * we still need to do a hardware config. Currently, * we cannot be here while scanning, however. */ - if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan) + if (ieee80211_cfg_on_oper_channel(local, false) && + !on_oper_chan) ieee80211_hw_config(local, 0); /* At the least, we need to disable offchannel_ps, -- 1.7.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html