Skip to content

Commit 5f9404a

Browse files
blogicjmberg-intel
authored andcommitted
mac80211: add support for BSS color change
The color change announcement is very similar to how CSA works where we have an IE that includes a counter. When the counter hits 0, the new color is applied via an updated beacon. This patch makes the CSA counter functionality reusable, rather than implementing it again. This also allows for future reuse incase support for other counter IEs gets added. Co-developed-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: John Crispin <[email protected]> Link: https://lore.kernel.org/r/057c1e67b82bee561ea44ce6a45a8462d3da6995.1625247619.git.lorenzo@kernel.org Signed-off-by: Johannes Berg <[email protected]>
1 parent 0d2ab3a commit 5f9404a

File tree

5 files changed

+283
-22
lines changed

5 files changed

+283
-22
lines changed

include/net/mac80211.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,6 +1711,10 @@ enum ieee80211_offload_flags {
17111711
* protected by fq->lock.
17121712
* @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
17131713
* &enum ieee80211_offload_flags.
1714+
* @color_change_active: marks whether a color change is ongoing. Internally it is
1715+
* write-protected by sdata_lock and local->mtx so holding either is fine
1716+
* for read access.
1717+
* @color_change_color: the bss color that will be used after the change.
17141718
*/
17151719
struct ieee80211_vif {
17161720
enum nl80211_iftype type;
@@ -1739,6 +1743,9 @@ struct ieee80211_vif {
17391743

17401744
bool txqs_stopped[IEEE80211_NUM_ACS];
17411745

1746+
bool color_change_active;
1747+
u8 color_change_color;
1748+
17421749
/* must be last */
17431750
u8 drv_priv[] __aligned(sizeof(void *));
17441751
};
@@ -5007,6 +5014,16 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif);
50075014
*/
50085015
bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif);
50095016

5017+
/**
5018+
* ieee80211_color_change_finish - notify mac80211 about color change
5019+
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
5020+
*
5021+
* After a color change announcement was scheduled and the counter in this
5022+
* announcement hits 1, this function must be called by the driver to
5023+
* notify mac80211 that the color can be changed
5024+
*/
5025+
void ieee80211_color_change_finish(struct ieee80211_vif *vif);
5026+
50105027
/**
50115028
* ieee80211_proberesp_get - retrieve a Probe Response template
50125029
* @hw: pointer obtained from ieee80211_alloc_hw().
@@ -6771,6 +6788,18 @@ struct sk_buff *
67716788
ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
67726789
struct ieee80211_vif *vif);
67736790

6791+
/**
6792+
* ieeee80211_obss_color_collision_notify - notify userland about a BSS color
6793+
* collision.
6794+
*
6795+
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
6796+
* @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is
6797+
* aware of.
6798+
*/
6799+
void
6800+
ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
6801+
u64 color_bitmap);
6802+
67746803
/**
67756804
* ieee80211_is_tx_data - check if frame is a data frame
67766805
*

net/mac80211/cfg.c

Lines changed: 223 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -828,9 +828,11 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
828828
return ret;
829829
}
830830

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)
834836
{
835837
struct probe_resp *new, *old;
836838

@@ -850,6 +852,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
850852
memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_presp,
851853
csa->n_counter_offsets_presp *
852854
sizeof(new->cntdwn_counter_offsets[0]));
855+
else if (cca)
856+
new->cntdwn_counter_offsets[0] = cca->counter_offset_presp;
853857

854858
rcu_assign_pointer(sdata->u.ap.probe_resp, new);
855859
if (old)
@@ -955,7 +959,8 @@ static int ieee80211_set_ftm_responder_params(
955959

956960
static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
957961
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)
959964
{
960965
struct beacon_data *new, *old;
961966
int new_head_len, new_tail_len;
@@ -1004,6 +1009,9 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
10041009
memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_beacon,
10051010
csa->n_counter_offsets_beacon *
10061011
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;
10071015
}
10081016

10091017
/* copy in head */
@@ -1020,7 +1028,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
10201028
memcpy(new->tail, old->tail, new_tail_len);
10211029

10221030
err = ieee80211_set_probe_resp(sdata, params->probe_resp,
1023-
params->probe_resp_len, csa);
1031+
params->probe_resp_len, csa, cca);
10241032
if (err < 0) {
10251033
kfree(new);
10261034
return err;
@@ -1175,7 +1183,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
11751183
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL))
11761184
sdata->vif.bss_conf.beacon_tx_rate = params->beacon_rate;
11771185

1178-
err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
1186+
err = ieee80211_assign_beacon(sdata, &params->beacon, NULL, NULL);
11791187
if (err < 0)
11801188
goto error;
11811189
changed |= err;
@@ -1230,17 +1238,17 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
12301238
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
12311239
sdata_assert_lock(sdata);
12321240

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
12341242
* of channel switch counter may change
12351243
*/
1236-
if (sdata->vif.csa_active)
1244+
if (sdata->vif.csa_active || sdata->vif.color_change_active)
12371245
return -EBUSY;
12381246

12391247
old = sdata_dereference(sdata->u.ap.beacon, sdata);
12401248
if (!old)
12411249
return -ENOENT;
12421250

1243-
err = ieee80211_assign_beacon(sdata, params, NULL);
1251+
err = ieee80211_assign_beacon(sdata, params, NULL, NULL);
12441252
if (err < 0)
12451253
return err;
12461254
ieee80211_bss_info_change_notify(sdata, err);
@@ -3156,7 +3164,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
31563164
switch (sdata->vif.type) {
31573165
case NL80211_IFTYPE_AP:
31583166
err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
3159-
NULL);
3167+
NULL, NULL);
31603168
kfree(sdata->u.ap.next_beacon);
31613169
sdata->u.ap.next_beacon = NULL;
31623170

@@ -3322,7 +3330,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
33223330
csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
33233331
csa.count = params->count;
33243332

3325-
err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa);
3333+
err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa, NULL);
33263334
if (err < 0) {
33273335
kfree(sdata->u.ap.next_beacon);
33283336
return err;
@@ -3411,6 +3419,15 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
34113419
return 0;
34123420
}
34133421

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+
34143431
static int
34153432
__ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
34163433
struct cfg80211_csa_settings *params)
@@ -3479,6 +3496,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
34793496
goto out;
34803497
}
34813498

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+
34823503
err = ieee80211_set_csa_beacon(sdata, params, &changed);
34833504
if (err) {
34843505
ieee80211_vif_unreserve_chanctx(sdata);
@@ -4130,6 +4151,196 @@ static int ieee80211_set_sar_specs(struct wiphy *wiphy,
41304151
return local->ops->set_sar_specs(&local->hw, sar);
41314152
}
41324153

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+
41334344
const struct cfg80211_ops mac80211_config_ops = {
41344345
.add_virtual_intf = ieee80211_add_iface,
41354346
.del_virtual_intf = ieee80211_del_iface,
@@ -4233,4 +4444,5 @@ const struct cfg80211_ops mac80211_config_ops = {
42334444
.set_tid_config = ieee80211_set_tid_config,
42344445
.reset_tid_config = ieee80211_reset_tid_config,
42354446
.set_sar_specs = ieee80211_set_sar_specs,
4447+
.color_change = ieee80211_color_change,
42364448
};

0 commit comments

Comments
 (0)