diff options
Diffstat (limited to 'net/mac80211/work.c')
-rw-r--r-- | net/mac80211/work.c | 66 |
1 files changed, 55 insertions, 11 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 36305e0d06ef..6bf787a5b38a 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -924,18 +924,44 @@ static void ieee80211_work_work(struct work_struct *work) | |||
924 | } | 924 | } |
925 | 925 | ||
926 | if (!started && !local->tmp_channel) { | 926 | if (!started && !local->tmp_channel) { |
927 | /* | 927 | bool on_oper_chan; |
928 | * TODO: could optimize this by leaving the | 928 | bool tmp_chan_changed = false; |
929 | * station vifs in awake mode if they | 929 | bool on_oper_chan2; |
930 | * happen to be on the same channel as | 930 | on_oper_chan = ieee80211_cfg_on_oper_channel(local); |
931 | * the requested channel | 931 | if (local->tmp_channel) |
932 | */ | 932 | if ((local->tmp_channel != wk->chan) || |
933 | ieee80211_offchannel_stop_beaconing(local); | 933 | (local->tmp_channel_type != wk->chan_type)) |
934 | ieee80211_offchannel_stop_station(local); | 934 | tmp_chan_changed = true; |
935 | 935 | ||
936 | local->tmp_channel = wk->chan; | 936 | local->tmp_channel = wk->chan; |
937 | local->tmp_channel_type = wk->chan_type; | 937 | local->tmp_channel_type = wk->chan_type; |
938 | ieee80211_hw_config(local, 0); | 938 | /* |
939 | * Leave the station vifs in awake mode if they | ||
940 | * happen to be on the same channel as | ||
941 | * the requested channel. | ||
942 | */ | ||
943 | on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); | ||
944 | if (on_oper_chan != on_oper_chan2) { | ||
945 | if (on_oper_chan2) { | ||
946 | /* going off oper channel, PS too */ | ||
947 | ieee80211_offchannel_stop_vifs(local, | ||
948 | true); | ||
949 | ieee80211_hw_config(local, 0); | ||
950 | } else { | ||
951 | /* going on channel, but leave PS | ||
952 | * off-channel. */ | ||
953 | ieee80211_hw_config(local, 0); | ||
954 | ieee80211_offchannel_return(local, | ||
955 | true, | ||
956 | false); | ||
957 | } | ||
958 | } else if (tmp_chan_changed) | ||
959 | /* Still off-channel, but on some other | ||
960 | * channel, so update hardware. | ||
961 | * PS should already be off-channel. | ||
962 | */ | ||
963 | ieee80211_hw_config(local, 0); | ||
964 | |||
939 | started = true; | 965 | started = true; |
940 | wk->timeout = jiffies; | 966 | wk->timeout = jiffies; |
941 | } | 967 | } |
@@ -1011,9 +1037,27 @@ static void ieee80211_work_work(struct work_struct *work) | |||
1011 | } | 1037 | } |
1012 | 1038 | ||
1013 | if (!remain_off_channel && local->tmp_channel) { | 1039 | if (!remain_off_channel && local->tmp_channel) { |
1040 | bool on_oper_chan = ieee80211_cfg_on_oper_channel(local); | ||
1014 | local->tmp_channel = NULL; | 1041 | local->tmp_channel = NULL; |
1015 | ieee80211_hw_config(local, 0); | 1042 | /* If tmp_channel wasn't operating channel, then |
1016 | ieee80211_offchannel_return(local, true); | 1043 | * we need to go back on-channel. |
1044 | * NOTE: If we can ever be here while scannning, | ||
1045 | * or if the hw_config() channel config logic changes, | ||
1046 | * then we may need to do a more thorough check to see if | ||
1047 | * we still need to do a hardware config. Currently, | ||
1048 | * we cannot be here while scanning, however. | ||
1049 | */ | ||
1050 | if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan) | ||
1051 | ieee80211_hw_config(local, 0); | ||
1052 | |||
1053 | /* At the least, we need to disable offchannel_ps, | ||
1054 | * so just go ahead and run the entire offchannel | ||
1055 | * return logic here. We *could* skip enabling | ||
1056 | * beaconing if we were already on-oper-channel | ||
1057 | * as a future optimization. | ||
1058 | */ | ||
1059 | ieee80211_offchannel_return(local, true, true); | ||
1060 | |||
1017 | /* give connection some time to breathe */ | 1061 | /* give connection some time to breathe */ |
1018 | run_again(local, jiffies + HZ/2); | 1062 | run_again(local, jiffies + HZ/2); |
1019 | } | 1063 | } |