Merge branch 'sfc-2.6.39' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-2.6
[pandora-kernel.git] / net / mac80211 / offchannel.c
index b4e5267..13427b1 100644 (file)
 #include "driver-trace.h"
 
 /*
- * inform AP that we will go to sleep so that it will buffer the frames
- * while we scan
+ * Tell our hardware to disable PS.
+ * Optionally inform AP that we will go to sleep so that it will buffer
+ * the frames while we are doing off-channel work.  This is optional
+ * because we *may* be doing work on-operating channel, and want our
+ * hardware unconditionally awake, but still let the AP send us normal frames.
  */
-static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
+                                          bool tell_ap)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -41,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
        }
 
-       if (!(local->offchannel_ps_enabled) ||
-           !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
+       if (tell_ap && (!local->offchannel_ps_enabled ||
+                       !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
                /*
                 * If power save was enabled, no need to send a nullfunc
                 * frame because AP knows that we are sleeping. But if the
@@ -77,6 +81,9 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
                 * we are sleeping, let's just enable power save mode in
                 * hardware.
                 */
+               /* TODO:  Only set hardware if CONF_PS changed?
+                * TODO:  Should we set offchannel_ps_enabled to false?
+                */
                local->hw.conf.flags |= IEEE80211_CONF_PS;
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
        } else if (local->hw.conf.dynamic_ps_timeout > 0) {
@@ -95,63 +102,61 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
        ieee80211_sta_reset_conn_monitor(sdata);
 }
 
-void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
+void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
+                                   bool offchannel_ps_enable)
 {
        struct ieee80211_sub_if_data *sdata;
 
+       /*
+        * notify the AP about us leaving the channel and stop all
+        * STA interfaces.
+        */
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
                        continue;
 
-               /* disable beaconing */
+               if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
+                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+
+               /* Check to see if we should disable beaconing. */
                if (sdata->vif.type == NL80211_IFTYPE_AP ||
                    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
                    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                        ieee80211_bss_info_change_notify(
                                sdata, BSS_CHANGED_BEACON_ENABLED);
 
-               /*
-                * only handle non-STA interfaces here, STA interfaces
-                * are handled in ieee80211_offchannel_stop_station(),
-                * e.g., from the background scan state machine.
-                *
-                * In addition, do not stop monitor interface to allow it to be
-                * used from user space controlled off-channel operations.
-                */
-               if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-                   sdata->vif.type != NL80211_IFTYPE_MONITOR) {
-                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+               if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                        netif_tx_stop_all_queues(sdata->dev);
+                       if (offchannel_ps_enable &&
+                           (sdata->vif.type == NL80211_IFTYPE_STATION) &&
+                           sdata->u.mgd.associated)
+                               ieee80211_offchannel_ps_enable(sdata, true);
                }
        }
        mutex_unlock(&local->iflist_mtx);
 }
 
-void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
+void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
+                                       bool tell_ap)
 {
        struct ieee80211_sub_if_data *sdata;
 
-       /*
-        * notify the AP about us leaving the channel and stop all STA interfaces
-        */
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
                        continue;
 
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
-                       netif_tx_stop_all_queues(sdata->dev);
-                       if (sdata->u.mgd.associated)
-                               ieee80211_offchannel_ps_enable(sdata);
-               }
+               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                   sdata->u.mgd.associated)
+                       ieee80211_offchannel_ps_enable(sdata, tell_ap);
        }
        mutex_unlock(&local->iflist_mtx);
 }
 
 void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool enable_beaconing)
+                                bool enable_beaconing,
+                                bool offchannel_ps_disable)
 {
        struct ieee80211_sub_if_data *sdata;
 
@@ -161,7 +166,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
                        continue;
 
                /* Tell AP we're back */
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+               if (offchannel_ps_disable &&
+                   sdata->vif.type == NL80211_IFTYPE_STATION) {
                        if (sdata->u.mgd.associated)
                                ieee80211_offchannel_ps_disable(sdata);
                }
@@ -181,7 +187,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
                        netif_tx_wake_all_queues(sdata->dev);
                }
 
-               /* re-enable beaconing */
+               /* Check to see if we should re-enable beaconing */
                if (enable_beaconing &&
                    (sdata->vif.type == NL80211_IFTYPE_AP ||
                     sdata->vif.type == NL80211_IFTYPE_ADHOC ||