mac80211: fix channel context iteration
authorJohannes Berg <johannes.berg@intel.com>
Thu, 13 Dec 2012 16:42:30 +0000 (17:42 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 3 Jan 2013 12:01:35 +0000 (13:01 +0100)
During suspend/resume channel contexts might be
iterated even if they haven't been re-added to
the driver, keep track of this and skip them in
iteration. Also use the new status for sanity
checks.

Also clarify the fact that during HW restart all
contexts are iterated over (thanks Eliad.)

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/chan.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h

index ee50c5eba50c027aed710c7fded8616b9461b96a..0978b0faa88061d62839d8f778f737f387509746 100644 (file)
@@ -3754,6 +3754,11 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
  * The iterator will not find a context that's being added (during
  * the driver callback to add it) but will find it while it's being
  * removed.
+ *
+ * Note that during hardware restart, all contexts that existed
+ * before the restart are considered already present so will be
+ * found while iterating, whether they've been re-added already
+ * or not.
  */
 void ieee80211_iter_chan_contexts_atomic(
        struct ieee80211_hw *hw,
index 80e55527504b91cd71b6d33a946507ad10b59c7e..1bfe0a8b19d222c95c3878d157114e9e85a0443b 100644 (file)
@@ -381,7 +381,8 @@ void ieee80211_iter_chan_contexts_atomic(
 
        rcu_read_lock();
        list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
-               iter(hw, &ctx->conf, iter_data);
+               if (ctx->driver_present)
+                       iter(hw, &ctx->conf, iter_data);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
index 698dc7e6f309847373541748c3cc4a2f40b67f58..608ced41548d8aaa23cb2c51c9a7c112caa85df7 100644 (file)
@@ -913,6 +913,8 @@ static inline int drv_add_chanctx(struct ieee80211_local *local,
        if (local->ops->add_chanctx)
                ret = local->ops->add_chanctx(&local->hw, &ctx->conf);
        trace_drv_return_int(local, ret);
+       if (!ret)
+               ctx->driver_present = true;
 
        return ret;
 }
@@ -924,6 +926,7 @@ static inline void drv_remove_chanctx(struct ieee80211_local *local,
        if (local->ops->remove_chanctx)
                local->ops->remove_chanctx(&local->hw, &ctx->conf);
        trace_drv_return_void(local);
+       ctx->driver_present = false;
 }
 
 static inline void drv_change_chanctx(struct ieee80211_local *local,
@@ -931,8 +934,10 @@ static inline void drv_change_chanctx(struct ieee80211_local *local,
                                      u32 changed)
 {
        trace_drv_change_chanctx(local, ctx, changed);
-       if (local->ops->change_chanctx)
+       if (local->ops->change_chanctx) {
+               WARN_ON_ONCE(!ctx->driver_present);
                local->ops->change_chanctx(&local->hw, &ctx->conf, changed);
+       }
        trace_drv_return_void(local);
 }
 
@@ -945,10 +950,12 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
        check_sdata_in_driver(sdata);
 
        trace_drv_assign_vif_chanctx(local, sdata, ctx);
-       if (local->ops->assign_vif_chanctx)
+       if (local->ops->assign_vif_chanctx) {
+               WARN_ON_ONCE(!ctx->driver_present);
                ret = local->ops->assign_vif_chanctx(&local->hw,
                                                     &sdata->vif,
                                                     &ctx->conf);
+       }
        trace_drv_return_int(local, ret);
 
        return ret;
@@ -961,10 +968,12 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
        check_sdata_in_driver(sdata);
 
        trace_drv_unassign_vif_chanctx(local, sdata, ctx);
-       if (local->ops->unassign_vif_chanctx)
+       if (local->ops->unassign_vif_chanctx) {
+               WARN_ON_ONCE(!ctx->driver_present);
                local->ops->unassign_vif_chanctx(&local->hw,
                                                 &sdata->vif,
                                                 &ctx->conf);
+       }
        trace_drv_return_void(local);
 }
 
index 38e7883cff23c4f41c7c61da3bf12817207f57d1..23161189b173ad6cb45e7f0e35c7d8c56605a4df 100644 (file)
@@ -685,6 +685,7 @@ struct ieee80211_chanctx {
 
        enum ieee80211_chanctx_mode mode;
        int refcount;
+       bool driver_present;
 
        struct ieee80211_chanctx_conf conf;
 };