|
@@ -300,32 +300,6 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
|
|
ieee80211_recalc_idle(local);
|
|
ieee80211_recalc_idle(local);
|
|
}
|
|
}
|
|
|
|
|
|
-static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
|
|
|
- struct ieee80211_chanctx *ctx)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_local *local = sdata->local;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- lockdep_assert_held(&local->chanctx_mtx);
|
|
|
|
-
|
|
|
|
- ret = drv_assign_vif_chanctx(local, sdata, ctx);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
-
|
|
|
|
- rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
|
|
|
|
- ctx->refcount++;
|
|
|
|
-
|
|
|
|
- ieee80211_recalc_txpower(sdata);
|
|
|
|
- ieee80211_recalc_chanctx_min_def(local, ctx);
|
|
|
|
- sdata->vif.bss_conf.idle = false;
|
|
|
|
-
|
|
|
|
- if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
|
|
|
|
- sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
|
|
|
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
|
|
static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
|
|
struct ieee80211_chanctx *ctx)
|
|
struct ieee80211_chanctx *ctx)
|
|
{
|
|
{
|
|
@@ -384,30 +358,57 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
|
|
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
|
|
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
|
|
}
|
|
}
|
|
|
|
|
|
-static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
|
|
|
- struct ieee80211_chanctx *ctx)
|
|
|
|
|
|
+static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
|
|
|
+ struct ieee80211_chanctx *new_ctx)
|
|
{
|
|
{
|
|
struct ieee80211_local *local = sdata->local;
|
|
struct ieee80211_local *local = sdata->local;
|
|
|
|
+ struct ieee80211_chanctx_conf *conf;
|
|
|
|
+ struct ieee80211_chanctx *curr_ctx = NULL;
|
|
|
|
+ int ret = 0;
|
|
|
|
|
|
- lockdep_assert_held(&local->chanctx_mtx);
|
|
|
|
|
|
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
|
|
|
+ lockdep_is_held(&local->chanctx_mtx));
|
|
|
|
|
|
- ctx->refcount--;
|
|
|
|
- RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
|
|
|
|
|
|
+ if (conf) {
|
|
|
|
+ curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
|
|
|
|
|
- sdata->vif.bss_conf.idle = true;
|
|
|
|
|
|
+ curr_ctx->refcount--;
|
|
|
|
+ drv_unassign_vif_chanctx(local, sdata, curr_ctx);
|
|
|
|
+ conf = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
- if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
|
|
|
|
- sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
|
|
|
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
|
|
|
|
|
+ if (new_ctx) {
|
|
|
|
+ ret = drv_assign_vif_chanctx(local, sdata, new_ctx);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ new_ctx->refcount++;
|
|
|
|
+ conf = &new_ctx->conf;
|
|
|
|
+ }
|
|
|
|
|
|
- drv_unassign_vif_chanctx(local, sdata, ctx);
|
|
|
|
|
|
+out:
|
|
|
|
+ rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
|
|
|
|
+
|
|
|
|
+ sdata->vif.bss_conf.idle = !conf;
|
|
|
|
|
|
- if (ctx->refcount > 0) {
|
|
|
|
- ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
|
|
|
|
- ieee80211_recalc_smps_chanctx(local, ctx);
|
|
|
|
- ieee80211_recalc_radar_chanctx(local, ctx);
|
|
|
|
- ieee80211_recalc_chanctx_min_def(local, ctx);
|
|
|
|
|
|
+ if (curr_ctx && curr_ctx->refcount > 0) {
|
|
|
|
+ ieee80211_recalc_chanctx_chantype(local, curr_ctx);
|
|
|
|
+ ieee80211_recalc_smps_chanctx(local, curr_ctx);
|
|
|
|
+ ieee80211_recalc_radar_chanctx(local, curr_ctx);
|
|
|
|
+ ieee80211_recalc_chanctx_min_def(local, curr_ctx);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (new_ctx && new_ctx->refcount > 0) {
|
|
|
|
+ ieee80211_recalc_txpower(sdata);
|
|
|
|
+ ieee80211_recalc_chanctx_min_def(local, new_ctx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
|
|
|
|
+ sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
|
|
|
+ ieee80211_bss_info_change_notify(sdata,
|
|
|
|
+ BSS_CHANGED_IDLE);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
|
static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
|
@@ -425,7 +426,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
|
|
|
|
|
ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
|
ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
|
|
|
|
|
- ieee80211_unassign_vif_chanctx(sdata, ctx);
|
|
|
|
|
|
+ ieee80211_assign_vif_chanctx(sdata, NULL);
|
|
if (ctx->refcount == 0)
|
|
if (ctx->refcount == 0)
|
|
ieee80211_free_chanctx(local, ctx);
|
|
ieee80211_free_chanctx(local, ctx);
|
|
}
|
|
}
|