@ -2792,17 +2792,35 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
sdata_assert_lock ( sdata ) ;
lockdep_assert_held ( & local - > mtx ) ;
lockdep_assert_held ( & local - > chanctx_mtx ) ;
sdata - > radar_required = sdata - > csa_radar_required ;
err = ieee80211_vif_change_channel ( sdata , & changed ) ;
if ( err < 0 )
return err ;
/*
* using reservation isn ' t immediate as it may be deferred until later
* with multi - vif . once reservation is complete it will re - schedule the
* work with no reserved_chanctx so verify chandef to check if it
* completed successfully
*/
if ( ! local - > use_chanctx ) {
local - > _oper_chandef = sdata - > csa_chandef ;
ieee80211_hw_config ( local , 0 ) ;
if ( sdata - > reserved_chanctx ) {
/*
* with multi - vif csa driver may call ieee80211_csa_finish ( )
* many times while waiting for other interfaces to use their
* reservations
*/
if ( sdata - > reserved_ready )
return 0 ;
err = ieee80211_vif_use_reserved_context ( sdata ) ;
if ( err )
return err ;
return 0 ;
}
if ( ! cfg80211_chandef_identical ( & sdata - > vif . bss_conf . chandef ,
& sdata - > csa_chandef ) )
return - EINVAL ;
sdata - > vif . csa_active = false ;
err = ieee80211_set_after_csa_beacon ( sdata , & changed ) ;
@ -2839,6 +2857,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
sdata_lock ( sdata ) ;
mutex_lock ( & local - > mtx ) ;
mutex_lock ( & local - > chanctx_mtx ) ;
/* AP might have been stopped while waiting for the lock. */
if ( ! sdata - > vif . csa_active )
@ -2850,6 +2869,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
ieee80211_csa_finalize ( sdata ) ;
unlock :
mutex_unlock ( & local - > chanctx_mtx ) ;
mutex_unlock ( & local - > mtx ) ;
sdata_unlock ( sdata ) ;
}
@ -2995,7 +3015,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local * local = sdata - > local ;
struct ieee80211_chanctx_conf * conf ;
struct ieee80211_chanctx * chanctx ;
int err , num_chanctx , changed = 0 ;
int err , changed = 0 ;
sdata_assert_lock ( sdata ) ;
lockdep_assert_held ( & local - > mtx ) ;
@ -3010,37 +3030,43 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
& sdata - > vif . bss_conf . chandef ) )
return - EINVAL ;
/* don't allow another channel switch if one is already active. */
if ( sdata - > vif . csa_active )
return - EBUSY ;
mutex_lock ( & local - > chanctx_mtx ) ;
conf = rcu_dereference_protected ( sdata - > vif . chanctx_conf ,
lockdep_is_held ( & local - > chanctx_mtx ) ) ;
if ( ! conf ) {
mutex_unlock ( & local - > chanctx_mtx ) ;
return - EBUSY ;
err = - EBUSY ;
goto out ;
}
/* don't handle for multi-VIF cases */
chanctx = container_of ( conf , struct ieee80211_chanctx , conf ) ;
if ( ieee80211_chanctx_refcount ( local , chanctx ) > 1 ) {
mutex_unlock ( & local - > chanctx_mtx ) ;
return - EBUSY ;
if ( ! chanctx ) {
err = - EBUSY ;
goto out ;
}
num_chanctx = 0 ;
list_for_each_entry_rcu ( chanctx , & local - > chanctx_list , list )
num_chanctx + + ;
mutex_unlock ( & local - > chanctx_mtx ) ;
if ( num_chanctx > 1 )
return - EBUSY ;
err = ieee80211_vif_reserve_chanctx ( sdata , & params - > chandef ,
chanctx - > mode ,
params - > radar_required ) ;
if ( err )
goto out ;
/* don't allow another channel switch if one is already active. */
if ( sdata - > vif . csa_active )
return - EBUSY ;
/* if reservation is invalid then this will fail */
err = ieee80211_check_combinations ( sdata , NULL , chanctx - > mode , 0 ) ;
if ( err ) {
ieee80211_vif_unreserve_chanctx ( sdata ) ;
goto out ;
}
err = ieee80211_set_csa_beacon ( sdata , params , & changed ) ;
if ( err )
return err ;
if ( err ) {
ieee80211_vif_unreserve_chanctx ( sdata ) ;
goto out ;
}
sdata - > csa_radar_required = params - > radar_required ;
sdata - > csa_chandef = params - > chandef ;
sdata - > csa_block_tx = params - > block_tx ;
sdata - > vif . csa_active = true ;
@ -3057,7 +3083,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
ieee80211_csa_finalize ( sdata ) ;
}
return 0 ;
out :
mutex_unlock ( & local - > chanctx_mtx ) ;
return err ;
}
int ieee80211_channel_switch ( struct wiphy * wiphy , struct net_device * dev ,