|
@@ -198,15 +198,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
|
ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
|
|
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
|
|
- struct ieee80211_sub_if_data *vlan;
|
|
|
-
|
|
|
- /* for the VLAN list */
|
|
|
- ASSERT_RTNL();
|
|
|
- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
|
|
- rcu_assign_pointer(vlan->vif.chanctx_conf, NULL);
|
|
|
- }
|
|
|
-
|
|
|
ieee80211_unassign_vif_chanctx(sdata, ctx);
|
|
|
if (ctx->refcount == 0)
|
|
|
ieee80211_free_chanctx(local, ctx);
|
|
@@ -326,15 +317,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
|
|
- struct ieee80211_sub_if_data *vlan;
|
|
|
-
|
|
|
- /* for the VLAN list */
|
|
|
- ASSERT_RTNL();
|
|
|
- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
|
|
- rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf);
|
|
|
- }
|
|
|
-
|
|
|
ieee80211_recalc_smps_chanctx(local, ctx);
|
|
|
out:
|
|
|
mutex_unlock(&local->chanctx_mtx);
|
|
@@ -369,6 +351,40 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
|
|
|
mutex_unlock(&local->chanctx_mtx);
|
|
|
}
|
|
|
|
|
|
+void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
|
|
|
+ bool clear)
|
|
|
+{
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ struct ieee80211_sub_if_data *vlan;
|
|
|
+ struct ieee80211_chanctx_conf *conf;
|
|
|
+
|
|
|
+ ASSERT_RTNL();
|
|
|
+
|
|
|
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
|
|
|
+ return;
|
|
|
+
|
|
|
+ mutex_lock(&local->chanctx_mtx);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Check that conf exists, even when clearing this function
|
|
|
+ * must be called with the AP's channel context still there
|
|
|
+ * as it would otherwise cause VLANs to have an invalid
|
|
|
+ * channel context pointer for a while, possibly pointing
|
|
|
+ * to a channel context that has already been freed.
|
|
|
+ */
|
|
|
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
|
|
+ lockdep_is_held(&local->chanctx_mtx));
|
|
|
+ WARN_ON(!conf);
|
|
|
+
|
|
|
+ if (clear)
|
|
|
+ conf = NULL;
|
|
|
+
|
|
|
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
|
|
+ rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
|
|
|
+
|
|
|
+ mutex_unlock(&local->chanctx_mtx);
|
|
|
+}
|
|
|
+
|
|
|
void ieee80211_iter_chan_contexts_atomic(
|
|
|
struct ieee80211_hw *hw,
|
|
|
void (*iter)(struct ieee80211_hw *hw,
|