mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
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>
This commit is contained in:
parent
7c8d5e03ac
commit
37fa2bdd16
@ -3089,6 +3089,129 @@ unlock:
|
||||
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 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
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 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user