@@ -828,9 +828,11 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
828
828
return ret ;
829
829
}
830
830
831
- static int ieee80211_set_probe_resp (struct ieee80211_sub_if_data * sdata ,
832
- const u8 * resp , size_t resp_len ,
833
- const struct ieee80211_csa_settings * csa )
831
+ static int
832
+ ieee80211_set_probe_resp (struct ieee80211_sub_if_data * sdata ,
833
+ const u8 * resp , size_t resp_len ,
834
+ const struct ieee80211_csa_settings * csa ,
835
+ const struct ieee80211_color_change_settings * cca )
834
836
{
835
837
struct probe_resp * new , * old ;
836
838
@@ -850,6 +852,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
850
852
memcpy (new -> cntdwn_counter_offsets , csa -> counter_offsets_presp ,
851
853
csa -> n_counter_offsets_presp *
852
854
sizeof (new -> cntdwn_counter_offsets [0 ]));
855
+ else if (cca )
856
+ new -> cntdwn_counter_offsets [0 ] = cca -> counter_offset_presp ;
853
857
854
858
rcu_assign_pointer (sdata -> u .ap .probe_resp , new );
855
859
if (old )
@@ -955,7 +959,8 @@ static int ieee80211_set_ftm_responder_params(
955
959
956
960
static int ieee80211_assign_beacon (struct ieee80211_sub_if_data * sdata ,
957
961
struct cfg80211_beacon_data * params ,
958
- const struct ieee80211_csa_settings * csa )
962
+ const struct ieee80211_csa_settings * csa ,
963
+ const struct ieee80211_color_change_settings * cca )
959
964
{
960
965
struct beacon_data * new , * old ;
961
966
int new_head_len , new_tail_len ;
@@ -1004,6 +1009,9 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
1004
1009
memcpy (new -> cntdwn_counter_offsets , csa -> counter_offsets_beacon ,
1005
1010
csa -> n_counter_offsets_beacon *
1006
1011
sizeof (new -> cntdwn_counter_offsets [0 ]));
1012
+ } else if (cca ) {
1013
+ new -> cntdwn_current_counter = cca -> count ;
1014
+ new -> cntdwn_counter_offsets [0 ] = cca -> counter_offset_beacon ;
1007
1015
}
1008
1016
1009
1017
/* copy in head */
@@ -1020,7 +1028,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
1020
1028
memcpy (new -> tail , old -> tail , new_tail_len );
1021
1029
1022
1030
err = ieee80211_set_probe_resp (sdata , params -> probe_resp ,
1023
- params -> probe_resp_len , csa );
1031
+ params -> probe_resp_len , csa , cca );
1024
1032
if (err < 0 ) {
1025
1033
kfree (new );
1026
1034
return err ;
@@ -1175,7 +1183,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
1175
1183
if (ieee80211_hw_check (& local -> hw , HAS_RATE_CONTROL ))
1176
1184
sdata -> vif .bss_conf .beacon_tx_rate = params -> beacon_rate ;
1177
1185
1178
- err = ieee80211_assign_beacon (sdata , & params -> beacon , NULL );
1186
+ err = ieee80211_assign_beacon (sdata , & params -> beacon , NULL , NULL );
1179
1187
if (err < 0 )
1180
1188
goto error ;
1181
1189
changed |= err ;
@@ -1230,17 +1238,17 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
1230
1238
sdata = IEEE80211_DEV_TO_SUB_IF (dev );
1231
1239
sdata_assert_lock (sdata );
1232
1240
1233
- /* don't allow changing the beacon while CSA is in place - offset
1241
+ /* don't allow changing the beacon while a countdown is in place - offset
1234
1242
* of channel switch counter may change
1235
1243
*/
1236
- if (sdata -> vif .csa_active )
1244
+ if (sdata -> vif .csa_active || sdata -> vif . color_change_active )
1237
1245
return - EBUSY ;
1238
1246
1239
1247
old = sdata_dereference (sdata -> u .ap .beacon , sdata );
1240
1248
if (!old )
1241
1249
return - ENOENT ;
1242
1250
1243
- err = ieee80211_assign_beacon (sdata , params , NULL );
1251
+ err = ieee80211_assign_beacon (sdata , params , NULL , NULL );
1244
1252
if (err < 0 )
1245
1253
return err ;
1246
1254
ieee80211_bss_info_change_notify (sdata , err );
@@ -3156,7 +3164,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
3156
3164
switch (sdata -> vif .type ) {
3157
3165
case NL80211_IFTYPE_AP :
3158
3166
err = ieee80211_assign_beacon (sdata , sdata -> u .ap .next_beacon ,
3159
- NULL );
3167
+ NULL , NULL );
3160
3168
kfree (sdata -> u .ap .next_beacon );
3161
3169
sdata -> u .ap .next_beacon = NULL ;
3162
3170
@@ -3322,7 +3330,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
3322
3330
csa .n_counter_offsets_presp = params -> n_counter_offsets_presp ;
3323
3331
csa .count = params -> count ;
3324
3332
3325
- err = ieee80211_assign_beacon (sdata , & params -> beacon_csa , & csa );
3333
+ err = ieee80211_assign_beacon (sdata , & params -> beacon_csa , & csa , NULL );
3326
3334
if (err < 0 ) {
3327
3335
kfree (sdata -> u .ap .next_beacon );
3328
3336
return err ;
@@ -3411,6 +3419,15 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
3411
3419
return 0 ;
3412
3420
}
3413
3421
3422
+ static void ieee80211_color_change_abort (struct ieee80211_sub_if_data * sdata )
3423
+ {
3424
+ sdata -> vif .color_change_active = false;
3425
+ kfree (sdata -> u .ap .next_beacon );
3426
+ sdata -> u .ap .next_beacon = NULL ;
3427
+
3428
+ cfg80211_color_change_aborted_notify (sdata -> dev );
3429
+ }
3430
+
3414
3431
static int
3415
3432
__ieee80211_channel_switch (struct wiphy * wiphy , struct net_device * dev ,
3416
3433
struct cfg80211_csa_settings * params )
@@ -3479,6 +3496,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3479
3496
goto out ;
3480
3497
}
3481
3498
3499
+ /* if there is a color change in progress, abort it */
3500
+ if (sdata -> vif .color_change_active )
3501
+ ieee80211_color_change_abort (sdata );
3502
+
3482
3503
err = ieee80211_set_csa_beacon (sdata , params , & changed );
3483
3504
if (err ) {
3484
3505
ieee80211_vif_unreserve_chanctx (sdata );
@@ -4130,6 +4151,196 @@ static int ieee80211_set_sar_specs(struct wiphy *wiphy,
4130
4151
return local -> ops -> set_sar_specs (& local -> hw , sar );
4131
4152
}
4132
4153
4154
+ static int
4155
+ ieee80211_set_after_color_change_beacon (struct ieee80211_sub_if_data * sdata ,
4156
+ u32 * changed )
4157
+ {
4158
+ switch (sdata -> vif .type ) {
4159
+ case NL80211_IFTYPE_AP : {
4160
+ int ret ;
4161
+
4162
+ ret = ieee80211_assign_beacon (sdata , sdata -> u .ap .next_beacon ,
4163
+ NULL , NULL );
4164
+ kfree (sdata -> u .ap .next_beacon );
4165
+ sdata -> u .ap .next_beacon = NULL ;
4166
+
4167
+ if (ret < 0 )
4168
+ return ret ;
4169
+
4170
+ * changed |= ret ;
4171
+ break ;
4172
+ }
4173
+ default :
4174
+ WARN_ON_ONCE (1 );
4175
+ return - EINVAL ;
4176
+ }
4177
+
4178
+ return 0 ;
4179
+ }
4180
+
4181
+ static int
4182
+ ieee80211_set_color_change_beacon (struct ieee80211_sub_if_data * sdata ,
4183
+ struct cfg80211_color_change_settings * params ,
4184
+ u32 * changed )
4185
+ {
4186
+ struct ieee80211_color_change_settings color_change = {};
4187
+ int err ;
4188
+
4189
+ switch (sdata -> vif .type ) {
4190
+ case NL80211_IFTYPE_AP :
4191
+ sdata -> u .ap .next_beacon =
4192
+ cfg80211_beacon_dup (& params -> beacon_next );
4193
+ if (!sdata -> u .ap .next_beacon )
4194
+ return - ENOMEM ;
4195
+
4196
+ if (params -> count <= 1 )
4197
+ break ;
4198
+
4199
+ color_change .counter_offset_beacon =
4200
+ params -> counter_offset_beacon ;
4201
+ color_change .counter_offset_presp =
4202
+ params -> counter_offset_presp ;
4203
+ color_change .count = params -> count ;
4204
+
4205
+ err = ieee80211_assign_beacon (sdata , & params -> beacon_color_change ,
4206
+ NULL , & color_change );
4207
+ if (err < 0 ) {
4208
+ kfree (sdata -> u .ap .next_beacon );
4209
+ return err ;
4210
+ }
4211
+ * changed |= err ;
4212
+ break ;
4213
+ default :
4214
+ return - EOPNOTSUPP ;
4215
+ }
4216
+
4217
+ return 0 ;
4218
+ }
4219
+
4220
+ static void
4221
+ ieee80211_color_change_bss_config_notify (struct ieee80211_sub_if_data * sdata ,
4222
+ u8 color , int enable , u32 changed )
4223
+ {
4224
+ sdata -> vif .bss_conf .he_bss_color .color = color ;
4225
+ sdata -> vif .bss_conf .he_bss_color .enabled = enable ;
4226
+ changed |= BSS_CHANGED_HE_BSS_COLOR ;
4227
+
4228
+ ieee80211_bss_info_change_notify (sdata , changed );
4229
+ }
4230
+
4231
+ static int ieee80211_color_change_finalize (struct ieee80211_sub_if_data * sdata )
4232
+ {
4233
+ struct ieee80211_local * local = sdata -> local ;
4234
+ u32 changed = 0 ;
4235
+ int err ;
4236
+
4237
+ sdata_assert_lock (sdata );
4238
+ lockdep_assert_held (& local -> mtx );
4239
+
4240
+ sdata -> vif .color_change_active = false;
4241
+
4242
+ err = ieee80211_set_after_color_change_beacon (sdata , & changed );
4243
+ if (err ) {
4244
+ cfg80211_color_change_aborted_notify (sdata -> dev );
4245
+ return err ;
4246
+ }
4247
+
4248
+ ieee80211_color_change_bss_config_notify (sdata ,
4249
+ sdata -> vif .color_change_color ,
4250
+ 1 , changed );
4251
+ cfg80211_color_change_notify (sdata -> dev );
4252
+
4253
+ return 0 ;
4254
+ }
4255
+
4256
+ void ieee80211_color_change_finalize_work (struct work_struct * work )
4257
+ {
4258
+ struct ieee80211_sub_if_data * sdata =
4259
+ container_of (work , struct ieee80211_sub_if_data ,
4260
+ color_change_finalize_work );
4261
+ struct ieee80211_local * local = sdata -> local ;
4262
+
4263
+ sdata_lock (sdata );
4264
+ mutex_lock (& local -> mtx );
4265
+
4266
+ /* AP might have been stopped while waiting for the lock. */
4267
+ if (!sdata -> vif .color_change_active )
4268
+ goto unlock ;
4269
+
4270
+ if (!ieee80211_sdata_running (sdata ))
4271
+ goto unlock ;
4272
+
4273
+ ieee80211_color_change_finalize (sdata );
4274
+
4275
+ unlock :
4276
+ mutex_unlock (& local -> mtx );
4277
+ sdata_unlock (sdata );
4278
+ }
4279
+
4280
+ void ieee80211_color_change_finish (struct ieee80211_vif * vif )
4281
+ {
4282
+ struct ieee80211_sub_if_data * sdata = vif_to_sdata (vif );
4283
+
4284
+ ieee80211_queue_work (& sdata -> local -> hw ,
4285
+ & sdata -> color_change_finalize_work );
4286
+ }
4287
+ EXPORT_SYMBOL_GPL (ieee80211_color_change_finish );
4288
+
4289
+ void
4290
+ ieeee80211_obss_color_collision_notify (struct ieee80211_vif * vif ,
4291
+ u64 color_bitmap )
4292
+ {
4293
+ struct ieee80211_sub_if_data * sdata = vif_to_sdata (vif );
4294
+
4295
+ if (sdata -> vif .color_change_active || sdata -> vif .csa_active )
4296
+ return ;
4297
+
4298
+ cfg80211_obss_color_collision_notify (sdata -> dev , color_bitmap );
4299
+ }
4300
+ EXPORT_SYMBOL_GPL (ieeee80211_obss_color_collision_notify );
4301
+
4302
+ static int
4303
+ ieee80211_color_change (struct wiphy * wiphy , struct net_device * dev ,
4304
+ struct cfg80211_color_change_settings * params )
4305
+ {
4306
+ struct ieee80211_sub_if_data * sdata = IEEE80211_DEV_TO_SUB_IF (dev );
4307
+ struct ieee80211_local * local = sdata -> local ;
4308
+ u32 changed = 0 ;
4309
+ int err ;
4310
+
4311
+ sdata_assert_lock (sdata );
4312
+
4313
+ mutex_lock (& local -> mtx );
4314
+
4315
+ /* don't allow another color change if one is already active or if csa
4316
+ * is active
4317
+ */
4318
+ if (sdata -> vif .color_change_active || sdata -> vif .csa_active ) {
4319
+ err = - EBUSY ;
4320
+ goto out ;
4321
+ }
4322
+
4323
+ err = ieee80211_set_color_change_beacon (sdata , params , & changed );
4324
+ if (err )
4325
+ goto out ;
4326
+
4327
+ sdata -> vif .color_change_active = true;
4328
+ sdata -> vif .color_change_color = params -> color ;
4329
+
4330
+ cfg80211_color_change_started_notify (sdata -> dev , params -> count );
4331
+
4332
+ if (changed )
4333
+ ieee80211_color_change_bss_config_notify (sdata , 0 , 0 , changed );
4334
+ else
4335
+ /* if the beacon didn't change, we can finalize immediately */
4336
+ ieee80211_color_change_finalize (sdata );
4337
+
4338
+ out :
4339
+ mutex_unlock (& local -> mtx );
4340
+
4341
+ return err ;
4342
+ }
4343
+
4133
4344
const struct cfg80211_ops mac80211_config_ops = {
4134
4345
.add_virtual_intf = ieee80211_add_iface ,
4135
4346
.del_virtual_intf = ieee80211_del_iface ,
@@ -4233,4 +4444,5 @@ const struct cfg80211_ops mac80211_config_ops = {
4233
4444
.set_tid_config = ieee80211_set_tid_config ,
4234
4445
.reset_tid_config = ieee80211_reset_tid_config ,
4235
4446
.set_sar_specs = ieee80211_set_sar_specs ,
4447
+ .color_change = ieee80211_color_change ,
4236
4448
};
0 commit comments