Commit 37fa2bdd authored by Michal Kazior's avatar Michal Kazior Committed by Johannes Berg

mac80211: refactor channel switch function

The function was quite big. This splits out beacon
updating into a separate function for improved
maintenance and extension.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 7c8d5e03
...@@ -3089,52 +3089,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work) ...@@ -3089,52 +3089,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
sdata_unlock(sdata); sdata_unlock(sdata);
} }
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *params) struct cfg80211_csa_settings *params,
u32 *changed)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int err;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
struct ieee80211_if_mesh __maybe_unused *ifmsh;
int err, num_chanctx, changed = 0;
sdata_assert_lock(sdata);
if (!list_empty(&local->roc_list) || local->scanning)
return -EBUSY;
if (sdata->wdev.cac_started)
return -EBUSY;
if (cfg80211_chandef_identical(&params->chandef,
&sdata->vif.bss_conf.chandef))
return -EINVAL;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return -EBUSY;
}
/* don't handle for multi-VIF cases */
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
rcu_read_unlock();
return -EBUSY;
}
num_chanctx = 0;
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
num_chanctx++;
rcu_read_unlock();
if (num_chanctx > 1)
return -EBUSY;
/* don't allow another channel switch if one is already active. */
if (sdata->vif.csa_active)
return -EBUSY;
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
...@@ -3170,7 +3129,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ...@@ -3170,7 +3129,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
kfree(sdata->u.ap.next_beacon); kfree(sdata->u.ap.next_beacon);
return err; return err;
} }
changed |= err; *changed |= err;
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
...@@ -3204,15 +3163,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ...@@ -3204,15 +3163,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
err = ieee80211_ibss_csa_beacon(sdata, params); err = ieee80211_ibss_csa_beacon(sdata, params);
if (err < 0) if (err < 0)
return err; return err;
changed |= err; *changed |= err;
} }
ieee80211_send_action_csa(sdata, params); ieee80211_send_action_csa(sdata, params);
break; break;
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT: {
ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
if (params->chandef.width != sdata->vif.bss_conf.chandef.width) if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
return -EINVAL; return -EINVAL;
...@@ -3237,18 +3196,72 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ...@@ -3237,18 +3196,72 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
return err; return err;
} }
changed |= err; *changed |= err;
} }
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
ieee80211_send_action_csa(sdata, params); ieee80211_send_action_csa(sdata, params);
break; break;
}
#endif #endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
return 0;
}
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
int err, num_chanctx, changed = 0;
sdata_assert_lock(sdata);
if (!list_empty(&local->roc_list) || local->scanning)
return -EBUSY;
if (sdata->wdev.cac_started)
return -EBUSY;
if (cfg80211_chandef_identical(&params->chandef,
&sdata->vif.bss_conf.chandef))
return -EINVAL;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return -EBUSY;
}
/* don't handle for multi-VIF cases */
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
rcu_read_unlock();
return -EBUSY;
}
num_chanctx = 0;
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
num_chanctx++;
rcu_read_unlock();
if (num_chanctx > 1)
return -EBUSY;
/* don't allow another channel switch if one is already active. */
if (sdata->vif.csa_active)
return -EBUSY;
err = ieee80211_set_csa_beacon(sdata, params, &changed);
if (err)
return err;
sdata->csa_radar_required = params->radar_required; sdata->csa_radar_required = params->radar_required;
if (params->block_tx) if (params->block_tx)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment