mbox series

[V6,0/3] mac80211: add BSS color change support

Message ID 20201103092244.1925158-1-john@phrozen.org
Headers show
Series mac80211: add BSS color change support | expand

Message

John Crispin Nov. 3, 2020, 9:22 a.m. UTC
This series adds support for BSS color collission detection and change.

This series depends on the multiple bssid one.

Changes in V6
* rebase on current next tree
* add 2 addition guards

John Crispin (3):
  nl80211: add support for BSS coloring
  mac80211: add support for BSS color change
  ath11k: add support for BSS color change

 drivers/net/wireless/ath/ath11k/mac.c |  35 ++++
 drivers/net/wireless/ath/ath11k/mac.h |   1 +
 drivers/net/wireless/ath/ath11k/wmi.c |  57 ++++++
 drivers/net/wireless/ath/ath11k/wmi.h |  14 ++
 include/net/cfg80211.h                |  95 ++++++++++
 include/net/mac80211.h                |  28 +++
 include/uapi/linux/nl80211.h          |  46 +++++
 net/mac80211/cfg.c                    | 250 +++++++++++++++++++++++++-
 net/mac80211/ieee80211_i.h            |  12 ++
 net/mac80211/iface.c                  |   3 +
 net/mac80211/tx.c                     |  24 ++-
 net/wireless/nl80211.c                | 135 ++++++++++++++
 net/wireless/rdev-ops.h               |  12 ++
 net/wireless/trace.h                  |  47 +++++
 14 files changed, 741 insertions(+), 18 deletions(-)

Comments

Johannes Berg Nov. 6, 2020, 9:55 a.m. UTC | #1
> +
> +/*
> + * cfg80211_bss_color_notify - notify about bss color event

These all need /**

I was going to fix that (and some below things), but it got a bit
complex, and there's a question ... and patch 2 needs significant work
anyway.

> +	NL80211_CMD_OBSS_COLOR_COLLISION,
> +
> +	NL80211_CMD_COLOR_CHANGE,
> +	NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_STARTED,
> +	NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_ABORTED,
> +	NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_COMPLETED,

Might make sense to multiplex that into a single
NL80211_CMD_COLOR_CHANGE event? Not sure, it doesn't matter too much
now, but ... we do have limited commands eventually :-)

> + * @NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_IES: Nested set of attributes containing the IE
> + *	information for the time while performing a color switch.

_ELEMS perhaps?

Should probably also be a bit more specific on what's used from there.

> + * @NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_C_OFF_BEACON: An array of offsets (u16) to the color
> + *	switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).

Is this inside or outside, for example? I think outside, but should it
be? I guess should be just like CSA though.

> + * @NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_C_OFF_PRESP: An array of offsets (u16) to the color
> + *	switch counters in the probe response (%NL80211_ATTR_PROBE_RESP).

This is unused?

>   * @NUM_NL80211_ATTR: total number of nl80211_attrs available
>   * @NL80211_ATTR_MAX: highest attribute number currently defined
>   * @__NL80211_ATTR_AFTER_LAST: internal use
> @@ -3035,6 +3071,12 @@ enum nl80211_attrs {
>  	NL80211_ATTR_MULTIPLE_BSSID_IES,
>  	NL80211_ATTR_MULTIPLE_BSSID_EMA,
>  
> +	NL80211_ATTR_OBSS_COLOR_BITMAP,
> +
> +	NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_COUNT,
> +	NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_COLOR,
> +	NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_IES,

and in fact not defined?

> +static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
> +{
> +	struct cfg80211_registered_device *rdev = info->user_ptr[0];
> +	struct net_device *dev = info->user_ptr[1];
> +	struct wireless_dev *wdev = dev->ieee80211_ptr;
> +	struct cfg80211_color_change_settings params;
> +	static struct nlattr *color_change_attrs[NL80211_ATTR_MAX + 1];

I'd prefer you didn't. I'm working on getting rid of the RTNL in most
places, and that just adds more complexity to that ... please
dynamically allocate it.

Also, it just reserves space in the binary for a very rarely used code
path.

> +	int err, len;
> +
> +	if (!rdev->ops->color_change ||
> +	    !(wiphy_ext_feature_isset(&rdev->wiphy, NL80211_EXT_FEATURE_BSS_COLOR)))


some line wrapping in some places would be nice - not sure if this one
is affected, but still, you have a few that wouldn't be hard to wrap
IMHO.

> +	err = nla_parse_nested(color_change_attrs, NL80211_ATTR_MAX,
> +			       info->attrs[NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_IES],
> +			       nl80211_policy, NULL);

Please pass info->extack through to the last argument.

> +	if (err)
> +		return err;
> +
> +	err = nl80211_parse_beacon(rdev, color_change_attrs, &params.beacon_color_change);

(here for example, re wrapping)

> +	if (!info->attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON])
> +		return -EINVAL;
> +
> +	len = nla_len(info->attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
> +	if (len != sizeof(u16))
> +		return -EINVAL;
> +
> +	memcpy(&params.counter_offset_beacon,
> +	       nla_data(info->attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]),
> +	       sizeof(u16));

In the CSA case, this comes from the *inner* attributes. In your case,
it comes from the *outer*. IMHO that's super confusing.

> +	if (params.counter_offset_beacon >= params.beacon_color_change.tail_len)
> +		return -EINVAL;
> +
> +	if (params.beacon_color_change.tail[params.counter_offset_beacon] != params.count)
> +		return -EINVAL;
> +
> +	if (info->attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]) {
> +		params.counter_offset_presp =
> +			nla_get_u16(info->attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);

same here.

In CSA this is also allowed to be an array - the parsing code probably
needs to be different because we currently don't validate the size/type
of this to be NLA_U16, just like you did above with the
NL80211_ATTR_CNTDWN_OFFS_BEACON.

johannes
Johannes Berg Nov. 6, 2020, 10 a.m. UTC | #2
On Tue, 2020-11-03 at 10:22 +0100, John Crispin wrote:
> 

> @@ -6805,4 +6822,15 @@ struct sk_buff *ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw *hw,

>  struct sk_buff *

>  ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,

>  					  struct ieee80211_vif *vif);

> +/**

> + * ieeee80211_obss_color_collision_notify notify userland about a BSS color

> + * collision.


missing a "-" here

> +static void ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,

> +						     u8 color, int enable, u32 changed)

> +{

> +	sdata->vif.bss_conf.he_bss_color.color = color;

> +	sdata->vif.bss_conf.he_bss_color.enabled = enable;

> +	changed |= BSS_CHANGED_HE_BSS_COLOR;

> +

> +	ieee80211_bss_info_change_notify(sdata, changed);

> +

> +	if (ieee80211_hw_check(&sdata->local->hw, SUPPORTS_MULTI_BSSID_AP) &&

> +	    !sdata->vif.multiple_bssid.parent) {

> +		struct ieee80211_sub_if_data *child;

> +

> +		rcu_read_lock();

> +		list_for_each_entry_rcu(child, &sdata->local->interfaces, list) {

> +			if (child->vif.multiple_bssid.parent != &sdata->vif)

> +				continue;

> +			sdata_lock(child);


Err, you can't lock a mutex in an atomic context opened by
rcu_read_lock().

I guess you can just take the iflist_mtx or something, but this
certainly doesn't seem right.

Also, since it's being called under sdata_lock(parent), it'll need some
lockdep annotations to be able to do this.

> +			child->vif.bss_conf.he_bss_color.color = color;

> +			child->vif.bss_conf.he_bss_color.enabled = enable;

> +			ieee80211_bss_info_change_notify(child, BSS_CHANGED_HE_BSS_COLOR);


And the driver is also allowed to sleep in this IIRC, so you can't call
it under rcu_read_lock().

johannes