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: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 80534f5..aaa59d7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3089,6 +3089,129 @@
sdata_unlock(sdata);
}
+static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_csa_settings *params,
+ u32 *changed)
+{
+ int err;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ sdata->u.ap.next_beacon =
+ cfg80211_beacon_dup(¶ms->beacon_after);
+ if (!sdata->u.ap.next_beacon)
+ return -ENOMEM;
+
+ /*
+ * With a count of 0, we don't have to wait for any
+ * TBTT before switching, so complete the CSA
+ * immediately. In theory, with a count == 1 we
+ * should delay the switch until just before the next
+ * TBTT, but that would complicate things so we switch
+ * immediately too. If we would delay the switch
+ * until the next TBTT, we would have to set the probe
+ * response here.
+ *
+ * TODO: A channel switch with count <= 1 without
+ * sending a CSA action frame is kind of useless,
+ * because the clients won't know we're changing
+ * channels. The action frame must be implemented
+ * either here or in the userspace.
+ */
+ if (params->count <= 1)
+ break;
+
+ sdata->csa_counter_offset_beacon =
+ params->counter_offset_beacon;
+ sdata->csa_counter_offset_presp = params->counter_offset_presp;
+ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
+ if (err < 0) {
+ kfree(sdata->u.ap.next_beacon);
+ return err;
+ }
+ *changed |= err;
+
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (!sdata->vif.bss_conf.ibss_joined)
+ return -EINVAL;
+
+ if (params->chandef.width != sdata->u.ibss.chandef.width)
+ return -EINVAL;
+
+ switch (params->chandef.width) {
+ case NL80211_CHAN_WIDTH_40:
+ if (cfg80211_get_chandef_type(¶ms->chandef) !=
+ cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
+ return -EINVAL;
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* changes into another band are not supported */
+ if (sdata->u.ibss.chandef.chan->band !=
+ params->chandef.chan->band)
+ return -EINVAL;
+
+ /* see comments in the NL80211_IFTYPE_AP block */
+ if (params->count > 1) {
+ err = ieee80211_ibss_csa_beacon(sdata, params);
+ if (err < 0)
+ return err;
+ *changed |= err;
+ }
+
+ ieee80211_send_action_csa(sdata, params);
+
+ break;
+#ifdef CONFIG_MAC80211_MESH
+ case NL80211_IFTYPE_MESH_POINT: {
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
+ return -EINVAL;
+
+ /* changes into another band are not supported */
+ if (sdata->vif.bss_conf.chandef.chan->band !=
+ params->chandef.chan->band)
+ return -EINVAL;
+
+ if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) {
+ ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT;
+ if (!ifmsh->pre_value)
+ ifmsh->pre_value = 1;
+ else
+ ifmsh->pre_value++;
+ }
+
+ /* see comments in the NL80211_IFTYPE_AP block */
+ if (params->count > 1) {
+ err = ieee80211_mesh_csa_beacon(sdata, params);
+ if (err < 0) {
+ ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
+ return err;
+ }
+ *changed |= err;
+ }
+
+ if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
+ ieee80211_send_action_csa(sdata, params);
+
+ break;
+ }
+#endif
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params)
{
@@ -3096,7 +3219,6 @@
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);
@@ -3136,118 +3258,9 @@
if (sdata->vif.csa_active)
return -EBUSY;
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- sdata->u.ap.next_beacon =
- cfg80211_beacon_dup(¶ms->beacon_after);
- if (!sdata->u.ap.next_beacon)
- return -ENOMEM;
-
- /*
- * With a count of 0, we don't have to wait for any
- * TBTT before switching, so complete the CSA
- * immediately. In theory, with a count == 1 we
- * should delay the switch until just before the next
- * TBTT, but that would complicate things so we switch
- * immediately too. If we would delay the switch
- * until the next TBTT, we would have to set the probe
- * response here.
- *
- * TODO: A channel switch with count <= 1 without
- * sending a CSA action frame is kind of useless,
- * because the clients won't know we're changing
- * channels. The action frame must be implemented
- * either here or in the userspace.
- */
- if (params->count <= 1)
- break;
-
- sdata->csa_counter_offset_beacon =
- params->counter_offset_beacon;
- sdata->csa_counter_offset_presp = params->counter_offset_presp;
- err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
- if (err < 0) {
- kfree(sdata->u.ap.next_beacon);
- return err;
- }
- changed |= err;
-
- break;
- case NL80211_IFTYPE_ADHOC:
- if (!sdata->vif.bss_conf.ibss_joined)
- return -EINVAL;
-
- if (params->chandef.width != sdata->u.ibss.chandef.width)
- return -EINVAL;
-
- switch (params->chandef.width) {
- case NL80211_CHAN_WIDTH_40:
- if (cfg80211_get_chandef_type(¶ms->chandef) !=
- cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
- return -EINVAL;
- case NL80211_CHAN_WIDTH_5:
- case NL80211_CHAN_WIDTH_10:
- case NL80211_CHAN_WIDTH_20_NOHT:
- case NL80211_CHAN_WIDTH_20:
- break;
- default:
- return -EINVAL;
- }
-
- /* changes into another band are not supported */
- if (sdata->u.ibss.chandef.chan->band !=
- params->chandef.chan->band)
- return -EINVAL;
-
- /* see comments in the NL80211_IFTYPE_AP block */
- if (params->count > 1) {
- err = ieee80211_ibss_csa_beacon(sdata, params);
- if (err < 0)
- return err;
- changed |= err;
- }
-
- ieee80211_send_action_csa(sdata, params);
-
- break;
-#ifdef CONFIG_MAC80211_MESH
- case NL80211_IFTYPE_MESH_POINT:
- ifmsh = &sdata->u.mesh;
-
- if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
- return -EINVAL;
-
- /* changes into another band are not supported */
- if (sdata->vif.bss_conf.chandef.chan->band !=
- params->chandef.chan->band)
- return -EINVAL;
-
- if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) {
- ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT;
- if (!ifmsh->pre_value)
- ifmsh->pre_value = 1;
- else
- ifmsh->pre_value++;
- }
-
- /* see comments in the NL80211_IFTYPE_AP block */
- if (params->count > 1) {
- err = ieee80211_mesh_csa_beacon(sdata, params);
- if (err < 0) {
- ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
- return err;
- }
- changed |= err;
- }
-
- if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
- ieee80211_send_action_csa(sdata, params);
-
- break;
-#endif
- default:
- return -EOPNOTSUPP;
- }
+ err = ieee80211_set_csa_beacon(sdata, params, &changed);
+ if (err)
+ return err;
sdata->csa_radar_required = params->radar_required;