mac80211: do remain-on-channel while idle
authorJohannes Berg <johannes.berg@intel.com>
Tue, 5 Jun 2012 12:28:40 +0000 (14:28 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 6 Jun 2012 19:20:33 +0000 (15:20 -0400)
The IDLE handling in HW off-channel is broken right
now since we turn off IDLE only when the off-channel
period already started. Therefore, all drivers that
use it today (only iwlwifi!) must support off-channel
while idle, so playing with idle isn't needed at all.

Off-channel in general, since it's no longer used for
authentication/association, shouldn't affect PS, so
also remove that logic.

Also document a small caveat for reporting TX status
from off-channel frames in HW remain-on-channel.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/offchannel.c

index d2ed86da8e4c313c4f1be62bd105c05af511dac8..6e700bf8d4a578c48807f34412f5537acbf39712 100644 (file)
@@ -2183,7 +2183,13 @@ enum ieee80211_rate_control_changed {
  *     offload. Frames to transmit on the off-channel channel are transmitted
  *     normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
  *     duration (which will always be non-zero) expires, the driver must call
- *     ieee80211_remain_on_channel_expired(). This callback may sleep.
+ *     ieee80211_remain_on_channel_expired().
+ *     The driver must not call ieee80211_remain_on_channel_expired() before
+ *     the TX status for a frame that was sent off-channel, otherwise the TX
+ *     status is reported to userspace in an invalid way.
+ *     Note that this callback may be called while the device is in IDLE and
+ *     must be accepted in this case.
+ *     This callback may sleep.
  * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
  *     aborted before it expires. This callback may sleep.
  *
index d99359a6f76dadc786d7d75491c1d5a171343c4f..a169079197097bfd5e1dea749f791dafef13b50c 100644 (file)
@@ -2187,8 +2187,6 @@ static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
        local->hw_roc_cookie = 0;
        local->hw_roc_channel = NULL;
 
-       ieee80211_recalc_idle(local);
-
        return 0;
 }
 
@@ -2248,7 +2246,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
        u32 flags;
-       bool is_offchan = false;
+       bool is_offchan = false, in_hw_roc = false;
 
        if (dont_wait_for_ack)
                flags = IEEE80211_TX_CTL_NO_ACK;
@@ -2268,6 +2266,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        if (chan == local->hw_roc_channel) {
                /* TODO: check channel type? */
                is_offchan = false;
+               in_hw_roc = true;
                flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
        }
 
@@ -2370,7 +2369,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
         * wait is involved, we might otherwise not be on
         * the right channel for long enough!
         */
-       if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
+       if (!is_offchan && !wait && (in_hw_roc || !sdata->vif.bss_conf.idle)) {
                ieee80211_tx_skb(sdata, skb);
                return 0;
        }
index ede5f4959904cd06261354757bd6879fdf6a937f..968d71c50713d52f2306affb19421ae0ba8143ce 100644 (file)
@@ -1456,7 +1456,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
        int count = 0;
-       bool working = false, scanning = false, hw_roc = false;
+       bool working = false, scanning = false;
        struct ieee80211_work *wk;
        unsigned int led_trig_start = 0, led_trig_stop = 0;
 
@@ -1493,9 +1493,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                count++;
        }
 
-       list_for_each_entry(wk, &local->work_list, list) {
-               working = true;
-               wk->sdata->vif.bss_conf.idle = false;
+       if (!local->ops->remain_on_channel) {
+               list_for_each_entry(wk, &local->work_list, list) {
+                       working = true;
+                       wk->sdata->vif.bss_conf.idle = false;
+               }
        }
 
        if (local->scan_sdata &&
@@ -1504,9 +1506,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                local->scan_sdata->vif.bss_conf.idle = false;
        }
 
-       if (local->hw_roc_channel)
-               hw_roc = true;
-
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
                    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -1518,7 +1517,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
        }
 
-       if (working || scanning || hw_roc)
+       if (working || scanning)
                led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
        else
                led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
@@ -1530,8 +1529,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 
        ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
 
-       if (hw_roc)
-               return ieee80211_idle_off(local, "hw remain-on-channel");
        if (working)
                return ieee80211_idle_off(local, "working");
        if (scanning)
index e7c4ec4ce16654859d2811c210643929a76c5dc9..0f45d02e0ba740005e1bea41c60d1c2c036e3a01 100644 (file)
@@ -930,11 +930,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                return;
        }
 
-       if (!list_empty(&local->work_list)) {
-               local->ps_sdata = NULL;
-               goto change;
-       }
-
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
                        continue;
@@ -1007,7 +1002,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                local->ps_sdata = NULL;
        }
 
- change:
        ieee80211_change_ps(local);
 }
 
index 935aa4b6deee0220737ee4c1cebad69472dea343..8f482b15bc51869c8e889d7aa8490499276692b8 100644 (file)
@@ -207,8 +207,6 @@ static void ieee80211_hw_roc_start(struct work_struct *work)
                                          GFP_KERNEL);
        }
 
-       ieee80211_recalc_idle(local);
-
        mutex_unlock(&local->mtx);
 }
 
@@ -260,8 +258,6 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
        local->hw_roc_channel = NULL;
        local->hw_roc_cookie = 0;
 
-       ieee80211_recalc_idle(local);
-
        mutex_unlock(&local->mtx);
 }