@ -2988,28 +2988,26 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
return new_beacon ;
}
void ieee80211_csa_finalize_work ( struct work_struct * work )
void ieee80211_csa_finish ( struct ieee80211_vif * vif )
{
struct ieee80211_sub_if_data * sdata =
container_of ( work , struct ieee80211_sub_if_data ,
csa_finalize_work ) ;
struct ieee80211_local * local = sdata - > local ;
int err , changed = 0 ;
struct ieee80211_sub_if_data * sdata = vif_to_sdata ( vif ) ;
sdata_lock ( sdata ) ;
/* AP might have been stopped while waiting for the lock. */
if ( ! sdata - > vif . csa_active )
goto unlock ;
ieee80211_queue_work ( & sdata - > local - > hw ,
& sdata - > csa_finalize_work ) ;
}
EXPORT_SYMBOL ( ieee80211_csa_finish ) ;
if ( ! ieee80211_sdata_running ( sdata ) )
goto unlock ;
static void ieee80211_csa_finalize ( struct ieee80211_sub_if_data * sdata )
{
struct ieee80211_local * local = sdata - > local ;
int err , changed = 0 ;
sdata - > radar_required = sdata - > csa_radar_required ;
mutex_lock ( & local - > mtx ) ;
err = ieee80211_vif_change_channel ( sdata , & changed ) ;
mutex_unlock ( & local - > mtx ) ;
if ( WARN_ON ( err < 0 ) )
goto unlock ;
return ;
if ( ! local - > use_chanctx ) {
local - > _oper_chandef = sdata - > csa_chandef ;
@ -3023,7 +3021,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
case NL80211_IFTYPE_AP :
err = ieee80211_assign_beacon ( sdata , sdata - > u . ap . next_beacon ) ;
if ( err < 0 )
goto unlock ;
return ;
changed | = err ;
kfree ( sdata - > u . ap . next_beacon ) ;
@ -3038,12 +3036,12 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
case NL80211_IFTYPE_MESH_POINT :
err = ieee80211_mesh_finish_csa ( sdata ) ;
if ( err < 0 )
goto unlock ;
return ;
break ;
# endif
default :
WARN_ON ( 1 ) ;
goto unlock ;
return ;
}
ieee80211_wake_queues_by_reason ( & sdata - > local - > hw ,
@ -3051,6 +3049,23 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
IEEE80211_QUEUE_STOP_REASON_CSA ) ;
cfg80211_ch_switch_notify ( sdata - > dev , & sdata - > csa_chandef ) ;
}
void ieee80211_csa_finalize_work ( struct work_struct * work )
{
struct ieee80211_sub_if_data * sdata =
container_of ( work , struct ieee80211_sub_if_data ,
csa_finalize_work ) ;
sdata_lock ( sdata ) ;
/* AP might have been stopped while waiting for the lock. */
if ( ! sdata - > vif . csa_active )
goto unlock ;
if ( ! ieee80211_sdata_running ( sdata ) )
goto unlock ;
ieee80211_csa_finalize ( sdata ) ;
unlock :
sdata_unlock ( sdata ) ;
@ -3064,7 +3079,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_chanctx_conf * chanctx_conf ;
struct ieee80211_chanctx * chanctx ;
struct ieee80211_if_mesh __maybe_unused * ifmsh ;
int err , num_chanctx ;
int err , num_chanctx , changed = 0 ;
lockdep_assert_held ( & sdata - > wdev . mtx ) ;
@ -3105,19 +3120,40 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
switch ( sdata - > vif . type ) {
case NL80211_IFTYPE_AP :
sdata - > csa_counter_offset_beacon =
params - > counter_offset_beacon ;
sdata - > csa_counter_offset_presp = params - > counter_offset_presp ;
sdata - > u . ap . next_beacon =
cfg80211_beacon_dup ( & params - > 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 , & params - > 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 )
@ -3145,9 +3181,16 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
params - > chandef . chan - > band )
return - EINVAL ;
err = ieee80211_ibss_csa_beacon ( sdata , params ) ;
if ( err < 0 )
return err ;
/* 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 :
@ -3172,12 +3215,19 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if ( ifmsh - > csa_role = = IEEE80211_MESH_CSA_ROLE_NONE )
ifmsh - > csa_role = IEEE80211_MESH_CSA_ROLE_INIT ;
err = ieee80211_mesh_csa_beacon ( sdata , params ,
( ifmsh - > csa_role = = IEEE80211_MESH_CSA_ROLE_INIT ) ) ;
if ( err < 0 ) {
ifmsh - > csa_role = IEEE80211_MESH_CSA_ROLE_NONE ;
return err ;
/* 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 :
@ -3194,8 +3244,13 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
sdata - > csa_chandef = params - > chandef ;
sdata - > vif . csa_active = true ;
ieee80211_bss_info_change_notify ( sdata , err ) ;
drv_channel_switch_beacon ( sdata , & params - > chandef ) ;
if ( changed ) {
ieee80211_bss_info_change_notify ( sdata , changed ) ;
drv_channel_switch_beacon ( sdata , & params - > chandef ) ;
} else {
/* if the beacon didn't change, we can finalize immediately */
ieee80211_csa_finalize ( sdata ) ;
}
return 0 ;
}